Files
Population-optimization-alg…/MQL5/Include/Math/AOs/PopulationAO/AO_BO_BonoboOptimizer.mqh
T
2025-11-12 23:03:11 +04:00

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;
}
}
//————————————————————————————————————————————————————————————————————