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