327 lines
23 KiB
Plaintext
327 lines
23 KiB
Plaintext
//+——————————————————————————————————————————————————————————————————+
|
|
//| C_AO_BO |
|
|
//| Copyright 2007-2025, Andrey Dik |
|
|
//| https://www.mql5.com/ru/users/joo |
|
|
//+——————————————————————————————————————————————————————————————————+
|
|
|
|
#include "#C_AO.mqh"
|
|
|
|
//————————————————————————————————————————————————————————————————————
|
|
class C_AO_BO : public C_AO
|
|
{
|
|
public: //----------------------------------------------------------
|
|
~C_AO_BO () { }
|
|
C_AO_BO ()
|
|
{
|
|
ao_name = "BO";
|
|
ao_desc = "Bonobo Optimizer";
|
|
ao_link = "https://www.mql5.com/ru/articles/20245";
|
|
|
|
popSize = 50;
|
|
xgmProbInit = 0.03;
|
|
scab = 1.25;
|
|
scsb = 1.3;
|
|
rcpp = 0.0035;
|
|
subgroupFactorMax = 0.05;
|
|
|
|
ArrayResize (params, 6);
|
|
params [0].name = "popSize"; params [0].val = popSize;
|
|
params [1].name = "xgmProbInit"; params [1].val = xgmProbInit;
|
|
params [2].name = "scab"; params [2].val = scab;
|
|
params [3].name = "scsb"; params [3].val = scsb;
|
|
params [4].name = "rcpp"; params [4].val = rcpp;
|
|
params [5].name = "subgroupFactorMax"; params [5].val = subgroupFactorMax;
|
|
}
|
|
|
|
void SetParams ()
|
|
{
|
|
popSize = (int)params [0].val;
|
|
xgmProbInit = params [1].val;
|
|
scab = params [2].val;
|
|
scsb = params [3].val;
|
|
rcpp = params [4].val;
|
|
subgroupFactorMax = params [5].val;
|
|
}
|
|
|
|
bool Init (const double &rangeMinP [],
|
|
const double &rangeMaxP [],
|
|
const double &rangeStepP [],
|
|
const int epochsP);
|
|
|
|
void Moving ();
|
|
void Revision ();
|
|
|
|
//------------------------------------------------------------------
|
|
double xgmProbInit; // Начальная вероятность внегруппового спаривания
|
|
double scab; // Коэффициент разделения для альфа-бонобо
|
|
double scsb; // Коэффициент разделения для выбранного бонобо
|
|
double rcpp; // Вероятность изменения фазы
|
|
double subgroupFactorMax; // Максимальное значение временного коэффициента размера подгруппы
|
|
|
|
private: //---------------------------------------------------------
|
|
int negPhaseCount; // npc - Отрицательное количество фаз
|
|
int posPhaseCount; // ppc - Положительное количество фаз
|
|
double xgmProb; // p_xgm - Вероятность внегруппового спаривания
|
|
double subgroupFactorInit;// tsgs_factor_initial
|
|
double subgroupFactor; // tsgs_factor
|
|
double phaseProb; // p_p - Фазовая вероятность
|
|
double directProb; // p_d - Вероятность направления
|
|
double prevBestFitness; // pbestcost
|
|
|
|
S_AO_Agent prevState []; // Старые позиции для критериев приемлемости
|
|
};
|
|
//————————————————————————————————————————————————————————————————————
|
|
|
|
//————————————————————————————————————————————————————————————————————
|
|
bool C_AO_BO::Init (const double &rangeMinP [],
|
|
const double &rangeMaxP [],
|
|
const double &rangeStepP [],
|
|
const int epochsP)
|
|
{
|
|
if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
|
|
|
|
//------------------------------------------------------------------
|
|
negPhaseCount = 0;
|
|
posPhaseCount = 0;
|
|
xgmProb = xgmProbInit;
|
|
subgroupFactorInit = 0.5 * subgroupFactorMax;
|
|
subgroupFactor = subgroupFactorInit;
|
|
phaseProb = 0.5;
|
|
directProb = 0.5;
|
|
prevBestFitness = -DBL_MAX;
|
|
|
|
ArrayResize (prevState, popSize);
|
|
for (int i = 0; i < popSize; i++) prevState [i].Init (coords);
|
|
|
|
return true;
|
|
}
|
|
//————————————————————————————————————————————————————————————————————
|
|
|
|
//————————————————————————————————————————————————————————————————————
|
|
void C_AO_BO::Moving ()
|
|
{
|
|
if (!revision)
|
|
{
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
|
|
a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
|
}
|
|
}
|
|
revision = true;
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
int maxSubgroupSize = (int)MathMax (2.0, MathCeil (popSize * subgroupFactor));
|
|
|
|
//------------------------------------------------------------------
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
// Сохраняем старое состояние
|
|
ArrayCopy (prevState [i].c, a [i].c, 0, 0, coords);
|
|
prevState [i].f = a [i].f;
|
|
|
|
// Создаем список индексов без текущего агента
|
|
int availableIndices [];
|
|
ArrayResize (availableIndices, popSize - 1);
|
|
int idx = 0;
|
|
for (int k = 0; k < popSize; k++)
|
|
{
|
|
if (k != i) availableIndices [idx++] = k;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Определяем фактический размер подгруппы
|
|
int actualSubgroupSize = 2 + u.RNDminusOne (maxSubgroupSize - 1);
|
|
|
|
// Выбираем случайную подгруппу
|
|
int subgroupIndices [];
|
|
ArrayResize (subgroupIndices, actualSubgroupSize);
|
|
for (int k = 0; k < actualSubgroupSize; k++)
|
|
{
|
|
int rndIdx = u.RNDminusOne (popSize - 1 - k);
|
|
subgroupIndices [k] = availableIndices [rndIdx];
|
|
// Удаляем выбранный элемент
|
|
for (int m = rndIdx; m < popSize - 2 - k; m++)
|
|
{
|
|
availableIndices [m] = availableIndices [m + 1];
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Выбираем лучшего партнера из подгруппы
|
|
int partnerIdx = subgroupIndices [0];
|
|
for (int k = 1; k < actualSubgroupSize; k++)
|
|
{
|
|
if (a [subgroupIndices [k]].f > a [partnerIdx].f)
|
|
{
|
|
partnerIdx = subgroupIndices [k];
|
|
}
|
|
}
|
|
|
|
// Определяем направление (флаг)
|
|
int direction;
|
|
if (a [i].f > a [partnerIdx].f)
|
|
{
|
|
partnerIdx = subgroupIndices [u.RNDminusOne (actualSubgroupSize)];
|
|
direction = 1;
|
|
}
|
|
else
|
|
{
|
|
direction = -1;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Создание нового решения
|
|
double offspring [];
|
|
ArrayResize (offspring, coords);
|
|
|
|
if (u.RNDprobab () <= phaseProb)
|
|
{
|
|
//--------------------------------------------------------------
|
|
// PROMISCUOUS или RESTRICTIVE MATING
|
|
//--------------------------------------------------------------
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
double rndWeight = u.RNDprobab ();
|
|
|
|
offspring [c] = a [i].c [c] +
|
|
scab * rndWeight * (cB [c] - a [i].c [c]) +
|
|
direction * scsb * (1.0 - rndWeight) * (a [i].c [c] - a [partnerIdx].c [c]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//--------------------------------------------------------------
|
|
// CONSORSHIP или EXTRA-GROUP MATING
|
|
//--------------------------------------------------------------
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
if (u.RNDprobab () <= xgmProb)
|
|
{
|
|
//----------------------------------------------------------
|
|
// EXTRA-GROUP MATING
|
|
//----------------------------------------------------------
|
|
double rndValue = u.RNDprobab ();
|
|
if (rndValue < 0.01) rndValue = 0.01;
|
|
|
|
if (cB [c] >= a [i].c [c])
|
|
{
|
|
if (u.RNDprobab () <= directProb)
|
|
{
|
|
double betaCoef1 = MathExp (rndValue * rndValue + rndValue - 2.0 / rndValue);
|
|
offspring [c] = a [i].c [c] + betaCoef1 * (rangeMax [c] - a [i].c [c]);
|
|
}
|
|
else
|
|
{
|
|
double betaCoef2 = MathExp (-rndValue * rndValue + 2.0 * rndValue - 2.0 / rndValue);
|
|
offspring [c] = a [i].c [c] - betaCoef2 * (a [i].c [c] - rangeMin [c]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (u.RNDprobab () <= directProb)
|
|
{
|
|
double betaCoef1 = MathExp (rndValue * rndValue + rndValue - 2.0 / rndValue);
|
|
offspring [c] = a [i].c [c] - betaCoef1 * (a [i].c [c] - rangeMin [c]);
|
|
}
|
|
else
|
|
{
|
|
double betaCoef2 = MathExp (-rndValue * rndValue + 2.0 * rndValue - 2.0 / rndValue);
|
|
offspring [c] = a [i].c [c] + betaCoef2 * (rangeMax [c] - a [i].c [c]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//----------------------------------------------------------
|
|
// CONSORSHIP MATING
|
|
//----------------------------------------------------------
|
|
if (direction == 1 || u.RNDprobab () <= directProb)
|
|
{
|
|
offspring [c] = a [i].c [c] + direction * MathExp (-u.RNDprobab ()) * (a [i].c [c] - a [partnerIdx].c [c]);
|
|
}
|
|
else
|
|
{
|
|
offspring [c] = a [partnerIdx].c [c];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Ограничение границами
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
if (offspring [c] > rangeMax [c]) offspring [c] = rangeMax [c];
|
|
if (offspring [c] < rangeMin [c]) offspring [c] = rangeMin [c];
|
|
offspring [c] = u.SeInDiSp (offspring [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
|
|
|
a [i].c [c] = offspring [c];
|
|
}
|
|
}
|
|
}
|
|
//————————————————————————————————————————————————————————————————————
|
|
|
|
//————————————————————————————————————————————————————————————————————
|
|
void C_AO_BO::Revision ()
|
|
{
|
|
//------------------------------------------------------------------
|
|
// ACCEPTANCE CRITERIA
|
|
//------------------------------------------------------------------
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
bool acceptNew = (a [i].f > prevState [i].f) || (u.RNDprobab () <= xgmProb);
|
|
|
|
if (!acceptNew)
|
|
{
|
|
// Откатываем к предыдущему состоянию
|
|
ArrayCopy (a [i].c, prevState [i].c, 0, 0, coords);
|
|
a [i].f = prevState [i].f;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
// Обновляем глобальное лучшее
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
if (a [i].f > fB)
|
|
{
|
|
fB = a [i].f;
|
|
ArrayCopy (cB, a [i].c, 0, 0, coords);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
// Обновление параметров
|
|
//------------------------------------------------------------------
|
|
if (fB > prevBestFitness)
|
|
{
|
|
// POSITIVE PHASE
|
|
negPhaseCount = 0;
|
|
posPhaseCount = posPhaseCount + 1;
|
|
|
|
double changeParam = MathMin (0.5, posPhaseCount * rcpp);
|
|
prevBestFitness = fB;
|
|
xgmProb = xgmProbInit;
|
|
phaseProb = 0.5 + changeParam;
|
|
directProb = phaseProb;
|
|
subgroupFactor = MathMin (subgroupFactorMax, subgroupFactorInit + posPhaseCount * rcpp * rcpp);
|
|
}
|
|
else
|
|
{
|
|
// NEGATIVE PHASE
|
|
negPhaseCount = negPhaseCount + 1;
|
|
posPhaseCount = 0;
|
|
|
|
double changeParam = -MathMin (0.5, negPhaseCount * rcpp);
|
|
xgmProb = MathMin (0.5, xgmProbInit + negPhaseCount * rcpp * rcpp);
|
|
subgroupFactor = MathMax (0.0, subgroupFactorInit - negPhaseCount * rcpp * rcpp);
|
|
phaseProb = 0.5 + changeParam;
|
|
directProb = 0.5;
|
|
}
|
|
}
|
|
//———————————————————————————————————————————————————————————————————— |