Files
Population-optimization-alg…/MQL5/Include/Math/AOs/PopulationAO/AO_CSO_CompetitiveSwarmOptimizer.mqh
T

188 lines
13 KiB
Plaintext
Raw Normal View History

2026-03-15 16:01:30 +04:00
//+------------------------------------------------------------------+
//| C_AO_CSO |
//| Copyright 2007-2026, Andrey Dik |
//| https://www.mql5.com/ru/users/joo |
//+------------------------------------------------------------------+
#include "#C_AO.mqh"
//————————————————————————————————————————————————————————————————————
class C_AO_CSO : public C_AO
{
public: //----------------------------------------------------------
~C_AO_CSO () { }
C_AO_CSO ()
{
ao_name = "CSO";
ao_desc = "Competitive Swarm Optimizer";
ao_link = "https://www.mql5.com/ru/articles/21727";
popSize = 50;
phi = 0.2;
ArrayResize (params, 2);
params [0].name = "popSize"; params [0].val = popSize;
params [1].name = "phi"; params [1].val = phi;
}
void SetParams ()
{
popSize = (int)params [0].val;
phi = params [1].val;
}
bool Init (const double &rangeMinP [],
const double &rangeMaxP [],
const double &rangeStepP [],
const int epochsP = 0);
void Moving ();
void Revision ();
//------------------------------------------------------------------
double phi; // коэффициент притяжения к центру роя φ ∈ [0, 1]
private: //---------------------------------------------------------
double V []; // скорости частиц [popSize * coords]
double Vmax []; // ограничение скорости [coords]
double center []; // центр роя [coords]
int rlist []; // вспомогательный массив перемешивания [popSize]
int nPairs; // число пар = popSize / 2
bool initialized;
int Idx (int i, int c) { return i * coords + c; }
double Clamp (double v, double lo, double hi) { return v < lo ? lo : v > hi ? hi : v; }
void Shuffle (); // Fisher-Yates перемешивание rlist
};
//————————————————————————————————————————————————————————————————————
//————————————————————————————————————————————————————————————————————
bool C_AO_CSO::Init (const double &rangeMinP [],
const double &rangeMaxP [],
const double &rangeStepP [],
const int epochsP = 0)
{
if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
//------------------------------------------------------------------
nPairs = popSize / 2; // нечётный агент не участвует в соревновании
ArrayResize (V, popSize * coords);
ArrayResize (Vmax, coords);
ArrayResize (center, coords);
ArrayResize (rlist, popSize);
// Vmax = половина диапазона по каждой оси
for (int c = 0; c < coords; c++) Vmax [c] = (rangeMax [c] - rangeMin [c]) * 0.5;
// Начальные позиции — случайные; скорости = 0 (как в оригинальной статье)
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)] = 0.0;
}
a [i].fB = -DBL_MAX;
}
initialized = false;
return true;
}
//————————————————————————————————————————————————————————————————————
//————————————————————————————————————————————————————————————————————
// Moving: копируем текущие позиции cP → c для внешней оценки фитнеса
void C_AO_CSO::Moving ()
{
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]);
}
//————————————————————————————————————————————————————————————————————
//————————————————————————————————————————————————————————————————————
// Revision:
// 1. Обновить личные / глобальный лучшие
// 2. Вычислить центр роя
// 3. Сформировать случайные пары, определить победителей / проигравших
// 4. Обновить скорости и позиции проигравших (формулы из статьи)
void C_AO_CSO::Revision ()
{
//--- 1. Обновление лучших ----------------------------------------
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);
}
}
initialized = true;
//--- 2. Центр роя: center = (1/m) * Σ cP_i ---------------------
ArrayInitialize (center, 0.0);
for (int i = 0; i < popSize; i++) for (int c = 0; c < coords; c++) center [c] += a [i].cP [c];
for (int c = 0; c < coords; c++) center [c] /= (double)popSize;
//--- 3. Случайные пары ------------------------------------------
Shuffle ();
//--- 4. Попарные соревнования и обновление проигравших ----------
for (int k = 0; k < nPairs; k++)
{
int ai = rlist [k];
int bi = rlist [k + nPairs];
// Максимизация: проигравший = агент с меньшим фитнесом
int li = (a [ai].f < a [bi].f) ? ai : bi; // loser
int wi = (a [ai].f < a [bi].f) ? bi : ai; // winner
// Формула скорости (Eq. 3 из статьи):
// v_l(t+1) = r1⊙v_l(t) + r2⊙(x_w(t)x_l(t)) + φ·r3⊙(x̄(t)x_l(t))
//
// Формула позиции:
// x_l(t+1) = x_l(t) + v_l(t+1)
for (int c = 0; c < coords; c++)
{
double r1 = u.RNDfromCI (0.0, 1.0);
double r2 = u.RNDfromCI (0.0, 1.0);
double r3 = u.RNDfromCI (0.0, 1.0);
int idx = Idx (li, c);
double vNew = r1 * V [idx]
+ r2 * (a [wi].cP [c] - a [li].cP [c])
+ phi * r3 * (center [c] - a [li].cP [c]);
vNew = Clamp (vNew, -Vmax [c], Vmax [c]);
double xNew = Clamp (a [li].cP [c] + vNew, rangeMin [c], rangeMax [c]);
V [idx] = vNew;
a [li].cP [c] = xNew;
// Позиция победителя cP[wi] не изменяется
}
}
}
//————————————————————————————————————————————————————————————————————
//————————————————————————————————————————————————————————————————————
// Fisher-Yates перемешивание массива rlist
void C_AO_CSO::Shuffle ()
{
for (int i = 0; i < popSize; i++) rlist [i] = i;
for (int i = popSize - 1; i > 0; i--)
{
int j = (int)(u.RNDfromCI (0.0, 1.0) * (i + 1));
if (j > i) j = i;
int tmp = rlist [i];
rlist [i] = rlist [j];
rlist [j] = tmp;
}
}
//————————————————————————————————————————————————————————————————————