//+——————————————————————————————————————————————————————————————————+ //| C_AO_DO | //| Copyright 2007-2025, Andrey Dik | //| https://www.mql5.com/ru/users/joo | //+——————————————————————————————————————————————————————————————————+ #include "#C_AO.mqh" //———————————————————————————————————————————————————————————————————— struct S_DO_Coord { double v; }; //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— class C_AO_DO : public C_AO { public: ~C_AO_DO () { } C_AO_DO () { ao_name = "DO"; ao_desc = "Dandelion Optimizer"; ao_link = "https://www.mql5.com/ru/articles/20540"; popSize = 50; ArrayResize (params, 1); params [0].name = "popSize"; params [0].val = popSize; } void SetParams () { popSize = (int)params [0].val; } bool Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP); void Moving (); void Revision (); private: //————————————————————————————————————————————————————————— int epochs; // maximum iterations int currentEpoch; // current iteration double sigma_u; // precomputed Levy sigma for beta=1.5 S_DO_Coord mean []; // mean position S_DO_Coord levy []; // levy flight steps S_DO_Coord center []; // center of search range S_DO_Coord range []; // range width void LevyFlight (); double LognormalPDF (double x, double mu, double sigma); void BoundaryControl (int idx); }; //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— bool C_AO_DO::Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP) { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //------------------------------------------------------------------ epochs = epochsP; currentEpoch = 0; ArrayResize (mean, coords); ArrayResize (levy, coords); ArrayResize (center, coords); ArrayResize (range, coords); // Предвычисление центра и ширины диапазона для каждой координаты for (int c = 0; c < coords; c++) { center [c].v = (rangeMax [c] + rangeMin [c]) * 0.5; range [c].v = rangeMax [c] - rangeMin [c]; } // Предвычисление sigma_u для Levy flight с beta=1.5 sigma_u = 0.6966; return true; } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— void C_AO_DO::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; } //------------------------------------------------------------------ currentEpoch++; double t = (double)currentEpoch; double T = (double)epochs; // Параметр alpha (eq. 8): alpha = rand * (t?/T? - 2t/T + 1) double alpha = u.RNDfromCI (0.0, 1.0) * ((t * t) / (T * T) - 2.0 * t / T + 1.0); // Параметры для k (eq. 11) double denom = T * T - 2.0 * T + 1.0; if (MathAbs (denom) < 1e-10) denom = 1e-10; double aa = 1.0 / denom; double bb = -2.0 * aa; double cc = 1.0 - aa - bb; double k = 1.0 - u.RNDfromCI (0.0, 1.0) * (cc + aa * t * t + bb * t); //================================================================== // Rising stage (Фаза подъёма) //================================================================== if (u.RNDprobab () < 0.8) { // Вихревой подъём (eq. 5) for (int i = 0; i < popSize; i++) { double theta = (2.0 * u.RNDfromCI (0.0, 1.0) - 1.0) * M_PI; double row = 1.0 / MathExp (theta); double vx = row * MathCos (theta); double vy = row * MathSin (theta); double vxvy = vx * vy; for (int c = 0; c < coords; c++) { double lamb = MathAbs (u.GaussDistribution (0, 1, -3, 3)); double lognPDF = LognormalPDF (lamb, 0.0, 1.0); double NEW = u.RNDfromCI (rangeMin [c], rangeMax [c]); a [i].c [c] = a [i].c [c] + alpha * vxvy * lognPDF * (NEW - a [i].c [c]); } BoundaryControl (i); } } else { // Линейный подъём (eq. 10) - масштабирование относительно центра диапазона for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { // Смещение относительно центра, масштабирование, возврат double offset = a [i].c [c] - center [c].v; a [i].c [c] = center [c].v + offset * k; } BoundaryControl (i); } } //================================================================== // Decline stage (Фаза снижения) //================================================================== // Вычисление среднего положения (eq. 14) for (int c = 0; c < coords; c++) { mean [c].v = 0.0; } for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { mean [c].v += a [i].c [c]; } } for (int c = 0; c < coords; c++) { mean [c].v /= popSize; } // Обновление позиций (eq. 13) for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { // Ограничиваем beta типичным диапазоном нормального распределения double beta = u.GaussDistribution (0, 1, -3, 3); double betaAlpha = beta * alpha; double delta = -betaAlpha * (mean [c].v - betaAlpha * a [i].c [c]); // Ограничиваем смещение double maxDelta = range [c].v * 0.3; if (delta > maxDelta) delta = maxDelta; if (delta < -maxDelta) delta = -maxDelta; a [i].c [c] = a [i].c [c] + delta; } BoundaryControl (i); } //================================================================== // Landing stage (Фаза приземления) //================================================================== double ratio = 2.0 * t / T; if (ratio > 2.0) ratio = 2.0; // Ограничение ratio for (int i = 0; i < popSize; i++) { LevyFlight (); for (int c = 0; c < coords; c++) { double elite = cB [c]; double current = a [i].c [c]; // eq. 15: x = Elite + levy * alpha * (Elite - x * ratio) double delta = levy [c].v * alpha * (elite - current * ratio); // Ограничиваем итоговое смещение половиной диапазона double maxDelta = range [c].v * 0.5; if (delta > maxDelta) delta = maxDelta; if (delta < -maxDelta) delta = -maxDelta; a [i].c [c] = elite + delta; } BoundaryControl (i); } } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— void C_AO_DO::LevyFlight () { // Levy flight с beta = 1.5 for (int c = 0; c < coords; c++) { double uu = u.GaussDistribution (0, sigma_u, -3.0 * sigma_u, 3.0 * sigma_u); double vv = u.GaussDistribution (0, 1, -3, 3); if (MathAbs (vv) < 1e-10) vv = 1e-10; levy [c].v = uu / MathPow (MathAbs (vv), 0.6667); } } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— double C_AO_DO::LognormalPDF (double x, double mu, double sigma) { if (x <= 0.0) return 0.0; double logx = MathLog (x); double diff = logx - mu; double coeff = 1.0 / (x * sigma * MathSqrt (2.0 * M_PI)); double expon = MathExp (-diff * diff / (2.0 * sigma * sigma)); return coeff * expon; } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— void C_AO_DO::BoundaryControl (int idx) { for (int c = 0; c < coords; c++) { double val = a [idx].c [c]; double min = rangeMin [c]; double max = rangeMax [c]; // Итеративное отражение от границ (максимум 10 итераций) int iter = 0; while ((val < min || val > max) && iter < 10) { if (val < min) val = min + (min - val); if (val > max) val = max - (val - max); iter++; } // Если отражение не помогло, случайная позиция if (val < min || val > max) { val = u.RNDfromCI (min, max); } a [idx].c [c] = u.SeInDiSp (val, min, max, rangeStep [c]); } } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— void C_AO_DO::Revision () { int bestIdx = 0; double bestFit = a [0].f; for (int i = 1; i < popSize; i++) { if (a [i].f > bestFit) { bestFit = a [i].f; bestIdx = i; } } if (bestFit > fB) { fB = bestFit; ArrayCopy (cB, a [bestIdx].c, 0, 0, coords); } } //————————————————————————————————————————————————————————————————————