469 lines
32 KiB
Plaintext
469 lines
32 KiB
Plaintext
//+——————————————————————————————————————————————————————————————————+
|
||||
|
|
//| C_AO_FBL |
|
|||
|
|
//| Copyright 2007-2025, Andrey Dik |
|
|||
|
|
//| https://www.mql5.com/ru/users/joo |
|
|||
|
|
//+——————————————————————————————————————————————————————————————————+
|
|||
|
|
#include "#C_AO.mqh"
|
|||
|
|
|
|||
|
|
|
|||
|
|
//────────────────────────────────────────────────────────────────────
|
|||
|
|
class C_AO_FBL : public C_AO
|
|||
|
|
{
|
|||
|
|
public: //------------------------------------------------------------
|
|||
|
|
~C_AO_FBL () { }
|
|||
|
|
C_AO_FBL ()
|
|||
|
|
{
|
|||
|
|
ao_name = "FBL";
|
|||
|
|
ao_desc = "Flock by Leader";
|
|||
|
|
ao_link = "https://www.mql5.com/ru/articles/21821";
|
|||
|
|
|
|||
|
|
popSize = 50;
|
|||
|
|
k = 5;
|
|||
|
|
phi = 0.5; // [F1]
|
|||
|
|
wSep = 0.15; // [F6]
|
|||
|
|
|
|||
|
|
ArrayResize (params, 4);
|
|||
|
|
params [0].name = "popSize"; params [0].val = popSize;
|
|||
|
|
params [1].name = "k"; params [1].val = k;
|
|||
|
|
params [2].name = "phi"; params [2].val = phi;
|
|||
|
|
params [3].name = "wSep"; params [3].val = wSep;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SetParams ()
|
|||
|
|
{
|
|||
|
|
popSize = (int)params [0].val;
|
|||
|
|
k = (int)params [1].val;
|
|||
|
|
phi = params [2].val;
|
|||
|
|
wSep = params [3].val;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Init (const double &rangeMinP [],
|
|||
|
|
const double &rangeMaxP [],
|
|||
|
|
const double &rangeStepP [],
|
|||
|
|
const int epochsP = 0);
|
|||
|
|
|
|||
|
|
void Moving ();
|
|||
|
|
void Revision ();
|
|||
|
|
|
|||
|
|
//------------------------------------------------------------------
|
|||
|
|
int k; // k ближайших соседей для DkNB / DR-kNB / ARF
|
|||
|
|
double phi; // коэффициент притяжения к gBest
|
|||
|
|
double wSep; // вес вектора separation [F6]
|
|||
|
|
|
|||
|
|
private: //---------------------------------------------------------
|
|||
|
|
double V []; // скорости [popSize * coords]
|
|||
|
|
double Vsnap []; // снапшот скоростей [popSize * coords] [F4]
|
|||
|
|
double Vmax []; // ограничение скорости [coords]
|
|||
|
|
double cPsnap []; // снапшот позиций [popSize * coords]
|
|||
|
|
double sepVec []; // вектор separation [coords]
|
|||
|
|
double distM []; // норм. матрица расст. [popSize × popSize]
|
|||
|
|
double dMax []; // d_max^i [popSize]
|
|||
|
|
int dknbSz []; // |DkNB_t(x_i)| [popSize]
|
|||
|
|
int drknbSz []; // |DR-kNB_t(x_i)| [popSize]
|
|||
|
|
double arf []; // ARF_t(A_i) [popSize]
|
|||
|
|
int knnIdx []; // k-NN индексы [popSize * kEff]
|
|||
|
|
int subflockId []; // субфлок агента (-1=выброс) [popSize]
|
|||
|
|
int leaderIdx []; // индекс лидера субфлока [popSize]
|
|||
|
|
int role []; // 0=лидер 1=послед. 2=выброс [popSize]
|
|||
|
|
int prevRole []; // роль предыдущей итерации [popSize]
|
|||
|
|
int centroidBuf []; // центроиды, sorted by ARF↓ [popSize]
|
|||
|
|
int subflockLeader []; // лидер субфлока s [popSize]
|
|||
|
|
double subflockBestF []; // лучший fB в субфлоке s [popSize]
|
|||
|
|
double rankBuf []; // Rank_t(A_i) Formula 5 [popSize] [F7]
|
|||
|
|
double tmpDist []; // буфер k-NN сортировки [popSize]
|
|||
|
|
int tmpIdx_ []; // буфер k-NN индексов [popSize]
|
|||
|
|
int kEff; // min(k, popSize-1)
|
|||
|
|
int nCentroids; // число субфлоков на итерации
|
|||
|
|
|
|||
|
|
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 CalcSep (int i); // вычислить sepVec[] для агента i
|
|||
|
|
};
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
bool C_AO_FBL::Init (const double &rangeMinP [],
|
|||
|
|
const double &rangeMaxP [],
|
|||
|
|
const double &rangeStepP [],
|
|||
|
|
const int epochsP = 0)
|
|||
|
|
{
|
|||
|
|
if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
|
|||
|
|
|
|||
|
|
kEff = MathMin (k, popSize - 1);
|
|||
|
|
if (kEff < 1) kEff = 1;
|
|||
|
|
|
|||
|
|
ArrayResize (V, popSize * coords);
|
|||
|
|
ArrayResize (Vsnap, popSize * coords); // [F4]
|
|||
|
|
ArrayResize (Vmax, coords);
|
|||
|
|
ArrayResize (cPsnap, popSize * coords);
|
|||
|
|
ArrayResize (sepVec, coords);
|
|||
|
|
ArrayResize (distM, popSize * popSize);
|
|||
|
|
ArrayResize (dMax, popSize);
|
|||
|
|
ArrayResize (dknbSz, popSize);
|
|||
|
|
ArrayResize (drknbSz, popSize);
|
|||
|
|
ArrayResize (arf, popSize);
|
|||
|
|
ArrayResize (knnIdx, popSize * kEff);
|
|||
|
|
ArrayResize (subflockId, popSize);
|
|||
|
|
ArrayResize (leaderIdx, popSize);
|
|||
|
|
ArrayResize (role, popSize);
|
|||
|
|
ArrayResize (prevRole, popSize);
|
|||
|
|
ArrayResize (centroidBuf, popSize);
|
|||
|
|
ArrayResize (subflockLeader, popSize);
|
|||
|
|
ArrayResize (subflockBestF, popSize);
|
|||
|
|
ArrayResize (rankBuf, popSize);
|
|||
|
|
ArrayResize (tmpDist, popSize);
|
|||
|
|
ArrayResize (tmpIdx_, popSize);
|
|||
|
|
|
|||
|
|
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)] = 0.0;
|
|||
|
|
Vsnap[Idx (i, c)] = 0.0; // [F4]
|
|||
|
|
}
|
|||
|
|
a [i].fB = -DBL_MAX;
|
|||
|
|
role [i] = 1;
|
|||
|
|
prevRole [i] = 1;
|
|||
|
|
leaderIdx[i] = -1;
|
|||
|
|
}
|
|||
|
|
nCentroids = 0;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
void C_AO_FBL::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]);
|
|||
|
|
}
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
// [O2][F6] Separation-вектор для агента i → sepVec[].
|
|||
|
|
// Отталкивание от k-NN соседей ближе dSep = 0.5 * dMax[i].
|
|||
|
|
// sepVec[] в абсолютных единицах позиций, масштаб задаёт wSep.
|
|||
|
|
void C_AO_FBL::CalcSep (int i)
|
|||
|
|
{
|
|||
|
|
ArrayInitialize (sepVec, 0.0);
|
|||
|
|
double dSep = 0.5 * dMax [i];
|
|||
|
|
if (dSep < 1e-14) return;
|
|||
|
|
|
|||
|
|
for (int m = 0; m < kEff; m++)
|
|||
|
|
{
|
|||
|
|
int j = knnIdx [i * kEff + m];
|
|||
|
|
double normD = distM [i * popSize + j];
|
|||
|
|
if (normD >= dSep) continue;
|
|||
|
|
double w = (normD > 1e-12) ? (dSep - normD) / dSep : 1.0;
|
|||
|
|
for (int c = 0; c < coords; c++)
|
|||
|
|
sepVec [c] += w * (cPsnap [Idx (i, c)] - cPsnap [Idx (j, c)]);
|
|||
|
|
}
|
|||
|
|
for (int c = 0; c < coords; c++) sepVec [c] *= wSep; // [F6]
|
|||
|
|
}
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
void C_AO_FBL::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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 2. Нормированная матрица расстояний ─────────────────────────
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
distM [i * popSize + i] = 0.0;
|
|||
|
|
for (int j = i + 1; j < popSize; j++)
|
|||
|
|
{
|
|||
|
|
double d = 0.0;
|
|||
|
|
for (int c = 0; c < coords; c++)
|
|||
|
|
{
|
|||
|
|
double rng = rangeMax [c] - rangeMin [c];
|
|||
|
|
double df = (rng > 0.0) ? (a [i].cP [c] - a [j].cP [c]) / rng : 0.0;
|
|||
|
|
d += df * df;
|
|||
|
|
}
|
|||
|
|
d = MathSqrt (d);
|
|||
|
|
distM [i * popSize + j] = d;
|
|||
|
|
distM [j * popSize + i] = d;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 3. k-NN → d_max → |DkNB| (Def 5, Formula 3) ───────────────
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
int cnt = 0;
|
|||
|
|
for (int j = 0; j < popSize; j++)
|
|||
|
|
{
|
|||
|
|
if (j == i) continue;
|
|||
|
|
tmpDist [cnt] = distM [i * popSize + j];
|
|||
|
|
tmpIdx_ [cnt] = j;
|
|||
|
|
cnt++;
|
|||
|
|
}
|
|||
|
|
for (int m = 0; m < kEff; m++)
|
|||
|
|
{
|
|||
|
|
int minPos = m;
|
|||
|
|
for (int n = m + 1; n < cnt; n++)
|
|||
|
|
if (tmpDist [n] < tmpDist [minPos]) minPos = n;
|
|||
|
|
if (minPos != m)
|
|||
|
|
{
|
|||
|
|
double td = tmpDist [m];
|
|||
|
|
tmpDist [m] = tmpDist [minPos];
|
|||
|
|
tmpDist [minPos] = td;
|
|||
|
|
int ti = tmpIdx_ [m];
|
|||
|
|
tmpIdx_ [m] = tmpIdx_ [minPos];
|
|||
|
|
tmpIdx_ [minPos] = ti;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
dMax [i] = tmpDist [kEff - 1];
|
|||
|
|
for (int m = 0; m < kEff; m++) knnIdx [i * kEff + m] = tmpIdx_ [m];
|
|||
|
|
|
|||
|
|
dknbSz [i] = 0;
|
|||
|
|
for (int j = 0; j < popSize; j++)
|
|||
|
|
{
|
|||
|
|
if (j == i) continue;
|
|||
|
|
if (distM [i * popSize + j] <= dMax [i]) dknbSz [i]++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 4. |DR-kNB| (Definition 6) ─────────────────────────────────
|
|||
|
|
ArrayInitialize (drknbSz, 0);
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
for (int j = 0; j < popSize; j++)
|
|||
|
|
{
|
|||
|
|
if (j == i) continue;
|
|||
|
|
if (distM [i * popSize + j] <= dMax [j]) drknbSz [i]++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 5. ARF (Formula 4) ──────────────────────────────────────────
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
int denom = drknbSz [i] + dknbSz [i];
|
|||
|
|
arf [i] = (denom > 0) ? (double)drknbSz [i] / (double)denom : 0.5;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 6. Центроиды: ARF >= 0.5, сортировка по Rank↓ (Formula 5) ──
|
|||
|
|
nCentroids = 0;
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
if (arf [i] >= 0.5) centroidBuf [nCentroids++] = i;
|
|||
|
|
|
|||
|
|
if (nCentroids == 0)
|
|||
|
|
{
|
|||
|
|
int bestI = 0;
|
|||
|
|
for (int i = 1; i < popSize; i++) if (arf [i] > arf [bestI]) bestI = i;
|
|||
|
|
centroidBuf [0] = bestI;
|
|||
|
|
nCentroids = 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// [F7] Formula 5: Rank_t(A_i) = Log(|N_i,t| / |N_t| * 10) * ARF_t(A_i)
|
|||
|
|
// |N_i,t| = dknbSz[i] (число соседей агента i)
|
|||
|
|
// |N_t| = popSize (число всех агентов)
|
|||
|
|
// Аргумент Log защищён от нуля: если dknbSz == 0 → rank = 0.
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
double ratio = (double)dknbSz [i] / (double)popSize * 10.0;
|
|||
|
|
rankBuf [i] = (ratio > 1e-12) ? MathLog (ratio) * arf [i] : 0.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Insertion sort центроидов по Rank↓
|
|||
|
|
for (int a_ = 1; a_ < nCentroids; a_++)
|
|||
|
|
{
|
|||
|
|
int key = centroidBuf [a_];
|
|||
|
|
double keyR = rankBuf [key];
|
|||
|
|
int b_ = a_ - 1;
|
|||
|
|
while (b_ >= 0 && rankBuf [centroidBuf [b_]] < keyR)
|
|||
|
|
{
|
|||
|
|
centroidBuf [b_ + 1] = centroidBuf [b_];
|
|||
|
|
b_--;
|
|||
|
|
}
|
|||
|
|
centroidBuf [b_ + 1] = key;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// [F9] Обрезка: оставляем не более popSize/k центроидов.
|
|||
|
|
// Сортировка уже выполнена → в начале массива самые значимые лидеры.
|
|||
|
|
int maxCentroids = MathMax (1, popSize / kEff);
|
|||
|
|
if (nCentroids > maxCentroids) nCentroids = maxCentroids;
|
|||
|
|
|
|||
|
|
//─── 7. Назначение агентов в субфлоки ────────────────────────────
|
|||
|
|
for (int i = 0; i < popSize; i++) subflockId [i] = -1;
|
|||
|
|
|
|||
|
|
for (int s = 0; s < nCentroids; s++)
|
|||
|
|
subflockId [centroidBuf [s]] = s;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
if (subflockId [i] >= 0) continue;
|
|||
|
|
for (int s = 0; s < nCentroids; s++)
|
|||
|
|
{
|
|||
|
|
if (distM [i * popSize + centroidBuf [s]] <= dMax [centroidBuf [s]])
|
|||
|
|
{
|
|||
|
|
subflockId [i] = s;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 8. Лидер субфлока = агент с наилучшим fB в субфлоке ─────────
|
|||
|
|
// [F2] Используем fB (исторический лучший), а не f (текущий шумный).
|
|||
|
|
for (int s = 0; s < nCentroids; s++)
|
|||
|
|
{
|
|||
|
|
subflockLeader [s] = -1;
|
|||
|
|
subflockBestF [s] = -DBL_MAX;
|
|||
|
|
}
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
int s = subflockId [i];
|
|||
|
|
if (s < 0) continue;
|
|||
|
|
if (a [i].fB > subflockBestF [s]) // [F2] fB вместо f
|
|||
|
|
{
|
|||
|
|
subflockBestF [s] = a [i].fB;
|
|||
|
|
subflockLeader [s] = i;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Страховка: если ни один агент субфлока не имел fB > -DBL_MAX
|
|||
|
|
// (например, первая итерация), назначаем центроид лидером,
|
|||
|
|
// чтобы leaderIdx последователей никогда не был -1.
|
|||
|
|
for (int s = 0; s < nCentroids; s++)
|
|||
|
|
if (subflockLeader [s] < 0) subflockLeader [s] = centroidBuf [s];
|
|||
|
|
|
|||
|
|
//─── 9. Роли агентов ─────────────────────────────────────────────
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
int s = subflockId [i];
|
|||
|
|
if (s < 0)
|
|||
|
|
{
|
|||
|
|
role [i] = 2;
|
|||
|
|
leaderIdx [i] = -1;
|
|||
|
|
}
|
|||
|
|
else if (subflockLeader [s] == i)
|
|||
|
|
{
|
|||
|
|
role [i] = 0;
|
|||
|
|
leaderIdx [i] = -1;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
role [i] = 1;
|
|||
|
|
leaderIdx [i] = subflockLeader [s];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 10. Снапшоты позиций и скоростей перед обновлением ──────────
|
|||
|
|
// [F4] Vsnap снимается здесь — Pass 2 использует согласованные
|
|||
|
|
// старые скорости лидеров, а не уже изменённые в Pass 1.
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
for (int c = 0; c < coords; c++)
|
|||
|
|
{
|
|||
|
|
cPsnap [Idx (i, c)] = a [i].cP [c];
|
|||
|
|
Vsnap [Idx (i, c)] = V [Idx (i, c)]; // [F4]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 11. Pass 1: ЛИДЕРЫ ──────────────────────────────────────────
|
|||
|
|
// v = w·v + r1·(cB_i − cP_i) + φ·r2·(gBest − cP_i) + sep
|
|||
|
|
// [F10] w=0.729 — коэффициент сужения Clerc-Kennedy (фиксированный).
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
if (role [i] != 0) continue;
|
|||
|
|
|
|||
|
|
// [F3] Смягчённый сброс скорости при первом появлении в роли лидера.
|
|||
|
|
// Накопленный импульс приглушается вдвое, а не обнуляется.
|
|||
|
|
if (prevRole [i] != 0)
|
|||
|
|
for (int c = 0; c < coords; c++) V [Idx (i, c)] *= 0.5; // [F3]
|
|||
|
|
|
|||
|
|
CalcSep (i);
|
|||
|
|
|
|||
|
|
for (int c = 0; c < coords; c++)
|
|||
|
|
{
|
|||
|
|
double r1 = u.RNDfromCI (0.0, 1.0);
|
|||
|
|
double r2 = u.RNDfromCI (0.0, 1.0);
|
|||
|
|
int idx = Idx (i, c);
|
|||
|
|
double vNew = 0.729 * V [idx] // [F10] инерция
|
|||
|
|
+ r1 * (a [i].cB [c] - cPsnap [idx]) // когнитивный
|
|||
|
|
+ phi * r2 * (cB [c] - cPsnap [idx]) // глобальный
|
|||
|
|
+ sepVec [c]; // separation
|
|||
|
|
|
|||
|
|
vNew = Clamp (vNew, -Vmax [c], Vmax [c]);
|
|||
|
|
a [i].cP [c] = Clamp (cPsnap [idx] + vNew, rangeMin [c], rangeMax [c]);
|
|||
|
|
V [idx] = vNew;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 12. Pass 2: ПОСЛЕДОВАТЕЛИ ───────────────────────────────────
|
|||
|
|
// v = w·v + r1·(cP_L − cP_i) + r2·(Vsnap_L − Vsnap_i)
|
|||
|
|
// + r3·(cB_i − cP_i) + φ·r4·(gBest − cP_i) + sep
|
|||
|
|
// [F4] Выравнивание идёт по Vsnap лидера (старая скорость).
|
|||
|
|
// [F10] w=0.729 — коэффициент сужения Clerc-Kennedy (фиксированный).
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
if (role [i] != 1) continue;
|
|||
|
|
int wi = leaderIdx [i];
|
|||
|
|
|
|||
|
|
CalcSep (i);
|
|||
|
|
|
|||
|
|
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);
|
|||
|
|
double r4 = u.RNDfromCI (0.0, 1.0);
|
|||
|
|
int idx = Idx (i, c);
|
|||
|
|
int idxL = Idx (wi, c);
|
|||
|
|
double vNew = 0.729 * V [idx] // [F10] инерция
|
|||
|
|
+ r1 * (cPsnap [idxL] - cPsnap [idx]) // Cohesion
|
|||
|
|
+ r2 * (Vsnap [idxL] - Vsnap [idx]) // Alignment [F4]
|
|||
|
|
+ r3 * (a [i].cB [c] - cPsnap [idx]) // Когнитивный
|
|||
|
|
+ phi * r4 * (cB [c] - cPsnap [idx]) // Глобальный
|
|||
|
|
+ sepVec [c]; // Separation
|
|||
|
|
|
|||
|
|
vNew = Clamp (vNew, -Vmax [c], Vmax [c]);
|
|||
|
|
a [i].cP [c] = Clamp (cPsnap [idx] + vNew, rangeMin [c], rangeMax [c]);
|
|||
|
|
V [idx] = vNew;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 13. Pass 3: ВЫБРОСЫ ─────────────────────────────────────────
|
|||
|
|
// [F5] r независим для каждой координаты — в многомерном
|
|||
|
|
// пространстве координаты прыгают независимо.
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
if (role [i] != 2) continue;
|
|||
|
|
|
|||
|
|
for (int c = 0; c < coords; c++)
|
|||
|
|
{
|
|||
|
|
double r = u.RNDfromCI (0.0, 1.0); // [F5] per-coordinate
|
|||
|
|
double xNew = (r > 0.5)
|
|||
|
|
? cB [c] + u.RNDfromCI (-1.0, 1.0) * (rangeMax [c] - rangeMin [c]) * 0.2
|
|||
|
|
: u.RNDfromCI (rangeMin [c], rangeMax [c]);
|
|||
|
|
|
|||
|
|
a [i].cP [c] = Clamp (xNew, rangeMin [c], rangeMax [c]);
|
|||
|
|
V [Idx (i, c)] = 0.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//─── 14. Сохранение ролей ────────────────────────────────────────
|
|||
|
|
for (int i = 0; i < popSize; i++) prevRole [i] = role [i];
|
|||
|
|
}
|
|||
|
|
//————————————————————————————————————————————————————————————————————
|
|||
|
|
�
|