Files
2026-03-15 16:01:30 +04:00

188 lines
13 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//+------------------------------------------------------------------+
//| 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;
}
}
//————————————————————————————————————————————————————————————————————