//+------------------------------------------------------------------+ //| C_AO_BSO_Beetle | //| Copyright 2007-2026, Andrey Dik | //| https://www.mql5.com/ru/users/joo | //+------------------------------------------------------------------+ #include "#C_AO.mqh" //———————————————————————————————————————————————————————————————————— class C_AO_BSO_Beetle : public C_AO { public: //---------------------------------------------------------- ~C_AO_BSO_Beetle () { } C_AO_BSO_Beetle () { ao_name = "BSO(Beetle)"; ao_desc = "Beetle Swarm Optimization"; ao_link = "https://www.mql5.com/ru/articles/21292"; popSize = 50; lambda = 0.5; c1_pso = 4.0; c2_pso = 1.5; omega_max = 0.9; omega_min = 0.4; eta = 0.95; delta0 = 1.0; c2_bas = 2.0; ArrayResize (params, 9); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "lambda"; params [1].val = lambda; params [2].name = "c1"; params [2].val = c1_pso; params [3].name = "c2"; params [3].val = c2_pso; params [4].name = "omega_max"; params [4].val = omega_max; params [5].name = "omega_min"; params [5].val = omega_min; params [6].name = "eta"; params [6].val = eta; params [7].name = "delta0"; params [7].val = delta0; params [8].name = "c2_bas"; params [8].val = c2_bas; } void SetParams () { popSize = (int)params [0].val; lambda = params [1].val; c1_pso = params [2].val; c2_pso = params [3].val; omega_max = params [4].val; omega_min = params [5].val; eta = params [6].val; delta0 = params [7].val; c2_bas = params [8].val; } bool Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0); void Moving (); void Revision (); //------------------------------------------------------------------ double lambda; // баланс PSO/BAS [0,1] double c1_pso; // когнитивный коэффициент PSO double c2_pso; // социальный коэффициент PSO double omega_max; // макс инерционный вес double omega_min; // мин инерционный вес double eta; // коэффициент затухания шага BAS double delta0; // начальный размер шага BAS double c2_bas; // d = delta / c2_bas private: //--------------------------------------------------------- double V []; // скорости жуков [popSize * coords] double fR []; // фитнес правой антенны [popSize] double fL []; // фитнес левой антенны [popSize] double Vmax []; // макс скорость [coords] double delta; double d_ant; double omega; int phase; int totalBSOepochs; int bsoEpoch; int Idx (int i, int c) { return i * coords + c; } double Clamp (double val, double minV, double maxV) { if (val < minV) return minV; if (val > maxV) return maxV; return val; } }; //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— bool C_AO_BSO_Beetle::Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0) { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //--- кастомные массивы (только то, чего нет в родительском классе) ArrayResize (V, popSize * coords); ArrayResize (fR, popSize); ArrayResize (fL, popSize); ArrayResize (Vmax, coords); //--- Vmax --------------------------------------------------------- for (int c = 0; c < coords; c++) { Vmax [c] = (rangeMax [c] - rangeMin [c]) * 0.5; } //------------------------------------------------------------------ for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { a [i].cP [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); V [Idx (i, c)] = u.RNDfromCI (-Vmax [c], Vmax [c]); } } //--- параметры BAS ------------------------------------------------ delta = delta0; d_ant = delta / c2_bas; //--- подсчёт итераций BSO ----------------------------------------- totalBSOepochs = (epochsP - 1) / 3; if (totalBSOepochs < 1) totalBSOepochs = 1; bsoEpoch = 0; phase = -1; return true; } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— void C_AO_BSO_Beetle::Moving () { //--- ФАЗА -1: начальные позиции из cP → c для первой оценки ------- if (phase == -1) { 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; } //--- ФАЗА 0: правая антенна — X_rs = cP + V * d/2 ----------------- if (phase == 0) { for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { double xrs = a [i].cP [c] + V [Idx (i, c)] * d_ant / 2.0; a [i].c [c] = u.SeInDiSp (xrs, rangeMin [c], rangeMax [c], rangeStep [c]); } } return; } //--- ФАЗА 1: левая антенна — X_ls = cP - V * d/2 ------------------ if (phase == 1) { for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { double xls = a [i].cP [c] - V [Idx (i, c)] * d_ant / 2.0; a [i].c [c] = u.SeInDiSp (xls, rangeMin [c], rangeMax [c], rangeStep [c]); } } return; } //--- ФАЗА 2: позиции жуков — cP → c для оценки -------------------- if (phase == 2) { 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; } } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— void C_AO_BSO_Beetle::Revision () { //--- ФАЗА -1: инициализация личных и глобального лучших ----------- if (phase == -1) { for (int i = 0; i < popSize; i++) { 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); } } phase = 0; return; } //--- ФАЗА 0: сохранить фитнес правых антенн ----------------------- if (phase == 0) { for (int i = 0; i < popSize; i++) fR [i] = a [i].f; phase = 1; return; } //--- ФАЗА 1: сохранить фитнес левых антенн + обновить ξ, V, cP ---- if (phase == 1) { for (int i = 0; i < popSize; i++) fL [i] = a [i].f; // Формула (8): ω omega = omega_max - (omega_max - omega_min) / (double)totalBSOepochs * (double)(bsoEpoch + 1); if (omega < omega_min) omega = omega_min; for (int i = 0; i < popSize; i++) { double signVal = 0.0; if (fR [i] > fL [i]) signVal = 1.0; else if (fR [i] < fL [i]) signVal = -1.0; for (int c = 0; c < coords; c++) { int idx = Idx (i, c); // Формула (9): ξ = δ * V * sign(fR - fL) double xi = delta * V [idx] * signVal; // Формула (7): V_new = ω*V + c1*r1*(cB_i - cP) + c2*r2*(cB_g - cP) double r1 = u.RNDfromCI (0.0, 1.0); double r2 = u.RNDfromCI (0.0, 1.0); double vNew = omega * V [idx] + c1_pso * r1 * (a [i].cB [c] - a [i].cP [c]) + c2_pso * r2 * (cB [c] - a [i].cP [c]); vNew = Clamp (vNew, -Vmax [c], Vmax [c]); // Формула (6): X_new = X + λ*V_new + (1-λ)*ξ double xNew = a [i].cP [c] + lambda * vNew + (1.0 - lambda) * xi; xNew = Clamp (xNew, rangeMin [c], rangeMax [c]); V [idx] = vNew; a [i].cP [c] = xNew; } } // Формула (4): δ = η*δ, Формула (5): d = δ/c2_bas delta = eta * delta; d_ant = delta / c2_bas; bsoEpoch++; phase = 2; return; } //--- ФАЗА 2: оценка позиций, обновление лучших -------------------- if (phase == 2) { 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); } } phase = 0; return; } } //————————————————————————————————————————————————————————————————————