188 lines
13 KiB
Plaintext
188 lines
13 KiB
Plaintext
//+------------------------------------------------------------------+
|
||
//| 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;
|
||
}
|
||
}
|
||
//———————————————————————————————————————————————————————————————————— |