306 lines
18 KiB
Plaintext
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;
|
|
}
|
|
}
|
|
//————————————————————————————————————————————————————————————————————
|