Files
2026-02-11 00:07:44 +04:00

306 lines
18 KiB
Plaintext

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