diff --git a/MQL5/Include/Math/AOs/PopulationAO/#C_AO.mqh b/MQL5/Include/Math/AOs/PopulationAO/#C_AO.mqh index 1a3ea1c..29fecf9 100644 Binary files a/MQL5/Include/Math/AOs/PopulationAO/#C_AO.mqh and b/MQL5/Include/Math/AOs/PopulationAO/#C_AO.mqh differ diff --git a/MQL5/Include/Math/AOs/PopulationAO/#C_AO_enum.mqh b/MQL5/Include/Math/AOs/PopulationAO/#C_AO_enum.mqh index cb817bc..ceaff8e 100644 Binary files a/MQL5/Include/Math/AOs/PopulationAO/#C_AO_enum.mqh and b/MQL5/Include/Math/AOs/PopulationAO/#C_AO_enum.mqh differ diff --git a/MQL5/Include/Math/AOs/PopulationAO/AO_BRO_BattleRoyaleOptimizer.mqh b/MQL5/Include/Math/AOs/PopulationAO/AO_BRO_BattleRoyaleOptimizer.mqh index 847318a..613cd1e 100644 Binary files a/MQL5/Include/Math/AOs/PopulationAO/AO_BRO_BattleRoyaleOptimizer.mqh and b/MQL5/Include/Math/AOs/PopulationAO/AO_BRO_BattleRoyaleOptimizer.mqh differ diff --git a/MQL5/Include/Math/AOs/PopulationAO/AO_BWOm_BelugaWhaleOptimization.mqh b/MQL5/Include/Math/AOs/PopulationAO/AO_BWOm_BelugaWhaleOptimization.mqh new file mode 100644 index 0000000..0b94d61 --- /dev/null +++ b/MQL5/Include/Math/AOs/PopulationAO/AO_BWOm_BelugaWhaleOptimization.mqh @@ -0,0 +1,349 @@ +//+——————————————————————————————————————————————————————————————————+ +//| C_AO_BWOm | +//| Copyright 2007-2026, Andrey Dik | +//| https://www.mql5.com/ru/users/joo | +//———————————————————————————————————————————————————————————————————+ + +#include "#C_AO.mqh" + +//+------------------------------------------------------------------+ +//| Beluga Whale Optimization — МОДИФИЦИРОВАННАЯ версия. | +//| | +//| Общий принцип модификации: в оригинальной BWO каждая из трёх фаз | +//| использует случайные множители, разыгранные ОДИН раз на агента | +//| (r1..r7 — скаляры), домножающие целые векторы. Любой такой | +//| скаляр-на-вектор запирает кандидата в низкоразмерное подпрост- | +//| ранство. На бенче из N копий одной функции оптимум осесимметри- | +//| чен, и это подпространство совпадает с главной диагональю, на | +//| которой оптимум и лежит — алгоритм «считывает диагональ» даром, | +//| причём эффект УСИЛИВАЕТСЯ с размерностью: покоординатный шум | +//| Леви усредняется при greedy-приёмке по среднему фитнесу. | +//| | +//| BWOm заменяет скаляры-на-агента на ПОКООРДИНАТНУЮ случайность во | +//| всех трёх фазах: | +//| - разведка: r1, r2 на каждую пару; тяга к одноимённой паре | +//| соседа (без общего скаляра-опоры и кросс-перестановки); | +//| - эксплуатация: тяга к глобальному лучшему — покоординатная | +//| интерполяция (r3 на каждую координату); масштаб-скаляр | +//| r3*cB убран — именно он порождал луч origin->cB; | +//| - падение кита: r5, r6 покоординатные. | +//| Трёхфазная структура, балансовый фактор, вероятность падения | +//| кита, полёт Леви и временное затухание C1/C2 сохранены. | +//+------------------------------------------------------------------+ +class C_AO_BWOm : public C_AO + { +public: + ~C_AO_BWOm() {} + C_AO_BWOm() + { + ao_name = "BWOm"; + ao_desc = "Beluga Whale Optimization (modified)"; + ao_link = "https://www.mql5.com/ru/articles/22686"; + + popSize = 20; + KD = 1.5; + + ArrayResize(params, 2); + params [0].name = "popSize"; params [0].val = popSize; + params [1].name = "KD"; params [1].val = KD; + } + + void SetParams() + { + popSize = (int)params [0].val; + KD = params [1].val; + + //--- предохранители + if(popSize < 1) + popSize = 1; + if(KD < 0.0) + KD = 0.0; + } + + bool Init(const double &rangeMinP [], + const double &rangeMaxP [], + const double &rangeStepP [], + const int epochsP = 0); + + void Moving(); + void Revision(); + + //--- видимые параметры + double KD; // интенсивность полёта Леви (оригинал: 0.05) + +private: + //--- snapshot для greedy acceptance + double snap_c []; // [popSize * coords] — плоский буфер + double snap_f []; // [popSize] + + //--- счётчик итераций (для отношения T/Max_it) + int epochs; // всего эпох (из Init) + int epochsDen; // знаменатель для T/Max_it + int epochNow; // номер текущей «боевой» итерации + + //--- константа масштаба для полёта Леви (Mantegna, beta = 1.5) + double levySigma; + + //--- стандартное нормальное число (Box–Muller) + double Gauss(); + //--- один отсчёт полёта Леви по координате + double LevyStep(); + }; +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Init | +//+------------------------------------------------------------------+ +bool C_AO_BWOm::Init(const double &rangeMinP [], + const double &rangeMaxP [], + const double &rangeStepP [], + const int epochsP = 0) + { + if(!StandardInit(rangeMinP, rangeMaxP, rangeStepP)) + return false; + +//--- начальная случайная популяция в cP[] (попадёт в c[] на первом Moving) + for(int i = 0; i < popSize; i++) + for(int c = 0; c < coords; c++) + a [i].cP [c] = u.RNDfromCI(rangeMin [c], rangeMax [c]); + +//--- внутренние буферы + ArrayResize(snap_c, popSize * coords); + ArrayResize(snap_f, popSize); + +//--- счётчик итераций + epochs = epochsP; + epochsDen = (epochs > 1) ? epochs - 1 : 1; + epochNow = 0; + +//--- sigma для полёта Леви (Mantegna), beta = 1.5 +// значения гамма-функции посчитаны заранее, чтобы не зависеть +// от наличия MathGamma: +// Г(1 + beta) = Г(2.5) = 1.3293403881791 +// Г((1+beta)/2) = Г(1.25) = 0.9064024770554 + double beta = 1.5; + double g1 = 1.3293403881791; + double g2 = 0.9064024770554; + levySigma = MathPow((g1 * MathSin(M_PI * beta / 2.0)) / + (g2 * beta * MathPow(2.0, (beta - 1.0) / 2.0)), + 1.0 / beta); // ≈ 0.69655 + + return true; + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Gauss — стандартное нормальное (Box–Muller) | +//+------------------------------------------------------------------+ +double C_AO_BWOm::Gauss() + { + double u1 = u.RNDfromCI(0.0, 1.0); + double u2 = u.RNDfromCI(0.0, 1.0); + if(u1 < 1e-15) + u1 = 1e-15; + return MathSqrt(-2.0 * MathLog(u1)) * MathCos(2.0 * M_PI * u2); + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| LevyStep — один отсчёт полёта Леви (Mantegna) | +//+------------------------------------------------------------------+ +double C_AO_BWOm::LevyStep() + { + double uu = Gauss() * levySigma; + double vv = Gauss(); + double av = MathAbs(vv); + if(av < 1e-300) + av = 1e-300; + return KD * (uu / MathPow(av, 1.0 / 1.5)); + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Moving | +//| | +//| Структура итерации: | +//| 1. snapshot текущей популяции; | +//| 2. для каждого агента — балансовый фактор Bf и сосед RJ; | +//| 3. выбор ветви: | +//| Bf <= WF -> падение кита; | +//| Bf > 0.5 -> разведка (честное парное плавание); | +//| иначе -> эксплуатация (покоординатная тяга к cB); | +//| 4. новый кандидат пишется в a[i].c. | +//| Во всех ветвях случайность ПОКООРДИНАТНАЯ — нет скаляра на | +//| агента, домножающего целый вектор. | +//+------------------------------------------------------------------+ +void C_AO_BWOm::Moving() + { +//--- первый прогон: cP -> c, чтобы внешний цикл оценил FF + if(!revision) + { + for(int i = 0; i < popSize; i++) + for(int c = 0; c < coords; c++) + a [i].c [c] = u.SeInDiSp(a [i].cP [c], rangeMin [c], rangeMax [c], rangeStep [c]); + return; + } + +//--- номер текущей итерации и отношение T/Max_it + epochNow++; + double tRatio = (double)epochNow / (double)epochsDen; + if(tRatio > 1.0) + tRatio = 1.0; + +//--- snapshot текущей популяции + for(int i = 0; i < popSize; i++) + { + for(int c = 0; c < coords; c++) + snap_c [i * coords + c] = a [i].c [c]; + snap_f [i] = a [i].f; + } + +//--- вероятность падения кита + double WF = 0.1 - 0.05 * tRatio; + +//--- движение + for(int i = 0; i < popSize; i++) + { + //--- балансовый фактор Bf = B0 * (1 - T/2Tmax) + double Bf = (1.0 - 0.5 * tRatio) * u.RNDprobab(); + + //--- случайный сосед RJ != i + int RJ = i; + if(popSize > 1) + while(RJ == i) + RJ = u.RNDminusOne(popSize); + + //================================================================ + if(Bf <= WF) + { + //--- ФАЗА 3: ПАДЕНИЕ КИТА (whale fall) — модификация + // Оригинал: v = r5*xi - r6*xr + step, r5/r6 — скаляры на + // агента -> скелет заперт в плоскости (xi, xr), на стянутой + // диагонали — в линию. BWOm: r5, r6 покоординатные. + // r7 (магнитуда шага) оставлен на агента — равномерный + // масштаб шага не запирает кандидата. + double r7 = u.RNDprobab(); + double C2 = 2.0 * (double)popSize * WF; + double decay = MathExp(-C2 * tRatio); + + for(int c = 0; c < coords; c++) + { + double r5c = u.RNDprobab(); + double r6c = u.RNDprobab(); + double step = r7 * (rangeMax [c] - rangeMin [c]) * decay; + double v = r5c * snap_c [i * coords + c] - + r6c * snap_c [RJ * coords + c] + step; + a [i].c [c] = u.SeInDiSp(v, rangeMin [c], rangeMax [c], rangeStep [c]); + } + } + //================================================================ + else + if(Bf > 0.5) + { + //--- ФАЗА 1: РАЗВЕДКА — честное парное плавание (модификация) + // каждая пара координат (dA, dB) тянется к своей одноимённой + // паре соседа RJ; r1, r2 разыгрываются на КАЖДУЮ пару. + // Ни общего скаляра-опоры, ни кросс-перестановки измерений. + + //--- незатронутые координаты остаются прежними + for(int c = 0; c < coords; c++) + a [i].c [c] = snap_c [i * coords + c]; + + int pairs = coords / 2; + + for(int j = 0; j < pairs; j++) + { + int dA = 2 * j; // x-координата пары + int dB = 2 * j + 1; // y-координата пары + + double r1 = u.RNDprobab(); + double r2 = u.RNDprobab(); + double ang = 2.0 * M_PI * r2; + double sinA = MathSin(ang); + double cosA = MathCos(ang); + + double xA = snap_c [i * coords + dA]; + double xB = snap_c [i * coords + dB]; + double refA = snap_c [RJ * coords + dA]; + double refB = snap_c [RJ * coords + dB]; + + double vA = xA + (refA - xA) * (r1 + 1.0) * sinA; + double vB = xB + (refB - xB) * (r1 + 1.0) * cosA; + a [i].c [dA] = u.SeInDiSp(vA, rangeMin [dA], rangeMax [dA], rangeStep [dA]); + a [i].c [dB] = u.SeInDiSp(vB, rangeMin [dB], rangeMax [dB], rangeStep [dB]); + } + } + //================================================================ + else + { + //--- ФАЗА 2: ЭКСПЛУАТАЦИЯ (охота, полёт Леви) — модификация + // Оригинал: v = r3*cB - r4*xi + C1*LF*(xr-xi), r3 — скаляр + // на агента. Слагаемое r3*cB — масштабированный осесиммет- + // ричный глобальный лучший: кандидат скользит по лучу + // origin->cB (главная диагональ на бенче из копий функции). + // На больших размерностях покоординатный шум Леви усред- + // няется при greedy-приёмке по среднему фитнесу, и отбор + // оптимизирует фактически одномерное сканирование диагонали. + // BWOm: тяга к лучшему — покоординатная интерполяция (r3 на + // КАЖДУЮ координату), скаляр-масштаб r3*cB убран. + // C1 (затухание Леви) оставлен на агента: равномерный + // масштаб покоординатно-случайного вектора Леви не запирает + // кандидата в подпространство. + double r4 = u.RNDprobab(); + double C1 = 2.0 * r4 * (1.0 - tRatio); + + for(int c = 0; c < coords; c++) + { + double r3c = u.RNDprobab(); + double xi = snap_c [i * coords + c]; + double xr = snap_c [RJ * coords + c]; + double Lv = LevyStep(); + double v = xi + r3c * (cB [c] - xi) + C1 * Lv * (xr - xi); + a [i].c [c] = u.SeInDiSp(v, rangeMin [c], rangeMax [c], rangeStep [c]); + } + } + } + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Revision | +//| | +//| Стандартное обновление fB/cB + greedy acceptance: если новый | +//| фитнес хуже снапшота — откат координат и фитнеса агента. | +//+------------------------------------------------------------------+ +void C_AO_BWOm::Revision() + { +//--- обновление личных и глобального лучших + for(int i = 0; i < popSize; i++) + { + if(a [i].f > a [i].fB) + { + a [i].fB = a [i].f; + ArrayCopy(a [i].cB, a [i].c, 0, 0, coords); + } + if(a [i].f > fB) + { + fB = a [i].f; + ArrayCopy(cB, a [i].c, 0, 0, coords); + } + } + + if(!revision) + { + revision = true; + return; + } + +//--- greedy acceptance: rollback если стало хуже + for(int i = 0; i < popSize; i++) + { + if(a [i].f < snap_f [i]) + { + for(int c = 0; c < coords; c++) + a [i].c [c] = snap_c [i * coords + c]; + a [i].f = snap_f [i]; + } + } + } +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/MQL5/Include/Math/AOs/PopulationAO/links.html b/MQL5/Include/Math/AOs/PopulationAO/links.html index 93be279..12e0753 100644 --- a/MQL5/Include/Math/AOs/PopulationAO/links.html +++ b/MQL5/Include/Math/AOs/PopulationAO/links.html @@ -81,6 +81,7 @@