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