This commit is contained in:
JQSakaJoo
2026-06-07 00:18:38 +04:00
parent b5dbcdc3e3
commit 1ffbc1bc5c
4 changed files with 329 additions and 1 deletions
Binary file not shown.
@@ -0,0 +1,326 @@
//+——————————————————————————————————————————————————————————————————+
//| C_AO_CVO |
//| Copyright 2007-2026, Andrey Dik |
//| https://www.mql5.com/ru/users/joo |
//———————————————————————————————————————————————————————————————————+
#include "#C_AO.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
struct S_CVO_Patient
{
double c [];
double f;
};
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class C_AO_CVO : public C_AO
{
public:
~C_AO_CVO() {}
C_AO_CVO()
{
ao_name = "CVO";
ao_desc = "Corona Virus Optimization";
ao_link = "https://www.mql5.com/ru/articles/22887";
popSize = 50; // бюджет FE на эпоху (= кандидатов за проход)
nPop = 200; // потолок инфекционной популяции
basePop = 5; // стартовая инфекционная популяция
R0 = 5; // потомков-восприимчивых на одного носителя
rho = 0.1; // контактность: общий множитель масштаба λ
ArrayResize(params, 5);
params [0].name = "popSize"; params [0].val = popSize;
params [1].name = "nPop"; params [1].val = nPop;
params [2].name = "basePop"; params [2].val = basePop;
params [3].name = "R0"; params [3].val = R0;
params [4].name = "rho"; params [4].val = rho;
}
void SetParams()
{
popSize = (int)params [0].val;
nPop = (int)params [1].val;
basePop = (int)params [2].val;
R0 = (int)params [3].val;
rho = params [4].val;
//--- предохранители
if(popSize < 1) popSize = 1;
if(nPop < 1) nPop = 1;
if(R0 < 1) R0 = 1;
if(rho < 0.0) rho = 0.0;
if(basePop < 1) basePop = 1;
if(basePop > popSize) basePop = popSize; // пул засевается из 1-го батча
if(basePop > nPop) basePop = nPop;
}
bool Init(const double &rangeMinP [],
const double &rangeMaxP [],
const double &rangeStepP [],
const int epochsP = 0);
void Moving();
void Revision();
//--- видимые параметры
int nPop; // потолок инфекционной популяции
int basePop; // стартовая инфекционная популяция
int R0; // потомков на носителя
double rho; // множитель масштаба λ
private:
//--- инфекционный пул (массив структур: координаты + фитнес вместе)
S_CVO_Patient inf []; // [nPop]
int infCount; // текущий размер пула (<= nPop)
//--- привязка слота-кандидата к носителю
int parentOf []; // [popSize]
//--- временный пул пересборки
S_CVO_Patient tmp []; // [nPop + popSize]
//--- стандартное нормальное (Box-Muller), Eq.3
double Gauss();
//--- индексная сортировка по убыванию f
void ArgSortDesc(const double &f [], int &idx [], const int count);
};
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Init |
//+------------------------------------------------------------------+
bool C_AO_CVO::Init(const double &rangeMinP [],
const double &rangeMaxP [],
const double &rangeStepP [],
const int epochsP = 0)
{
if(!StandardInit(rangeMinP, rangeMaxP, rangeStepP))
return false;
//--- стартовый случайный батч в cP[] (оценится на первом проходе)
for(int i = 0; i < popSize; i++)
for(int c = 0; c < coords; c++)
a [i].cP [c] = u.RNDfromCI(rangeMin [c], rangeMax [c]);
//--- инфекционный пул и временный пул (массивы структур)
ArrayResize(inf, nPop);
for(int i = 0; i < nPop; i++)
ArrayResize(inf [i].c, coords);
ArrayResize(tmp, nPop + popSize);
for(int i = 0; i < nPop + popSize; i++)
ArrayResize(tmp [i].c, coords);
ArrayResize(parentOf, popSize);
infCount = 0;
return true;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Moving |
//| |
//| Первый проход: случайный батч cP -> c (стенд его оценит, далее |
//| Revision засеет инфекционный пул лучшими basePop особями). |
//| Боевой проход: каждый слот-кандидат = восприимчивый, рождённый |
//| носителем p = (k/R0) % infCount возмущением λ (покоординатно). |
//+------------------------------------------------------------------+
void C_AO_CVO::Moving()
{
//--- первый прогон: cP -> c
if(!revision)
{
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]);
return;
}
//--- генерация кандидатов-восприимчивых
for(int k = 0; k < popSize; k++)
{
int denom = infCount > 0 ? infCount : 1; // защита от %0
int p = (k / R0) % denom; // носитель данного слота
parentOf [k] = p;
for(int c = 0; c < coords; c++)
{
double phi = Gauss(); // Eq.3, [D1] свой на координату
double frac = (double)(infCount + k) / (double)nPop; // I/N, Eq.1*Eq.2, [D3]
if(frac > 1.0)
frac = 1.0;
double lam = rho * phi * frac; // абсолютный шаг, ТОЧНО по статье (Eq.1*2*3)
double v = inf [p].c [c] + lam * (rangeMax [c] - rangeMin [c]);
a [k].c [c] = u.SeInDiSp(v, rangeMin [c], rangeMax [c], rangeStep [c]);
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Revision |
//| |
//| 1. обновление личных и глобального лучших по кандидатам; |
//| 2. первый проход: посев пула лучшими basePop особями; |
//| 3. LocalBest эпохи; решение замена/рост пула; |
//| 4. приёмка восприимчивых (иммунитет >= носителя); |
//| 5. отсечение пула до nPop по убыванию f (выздоровление). |
//+------------------------------------------------------------------+
void C_AO_CVO::Revision()
{
//--- сохранить прежний глобальный лучший ДО обновления (для решения замена/рост)
double fB_prev = fB;
//--- 1) обновление лучших
for(int i = 0; i < popSize; i++)
{
if(!MathIsValidNumber(a [i].f)) // нечисло не должно отравлять лучших/пул
continue;
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) первый проход: посев инфекционного пула лучшими basePop
if(!revision)
{
int idx [];
double af [];
ArrayResize(idx, popSize);
ArrayResize(af, popSize);
for(int i = 0; i < popSize; i++) af [i] = a [i].f;
ArgSortDesc(af, idx, popSize);
infCount = basePop; // basePop <= popSize (зажато в SetParams)
for(int n = 0; n < infCount; n++)
{
int s = idx [n];
ArrayCopy(inf [n].c, a [s].c, 0, 0, coords);
inf [n].f = a [s].f;
}
revision = true;
return;
}
//--- 3) лучший кандидат эпохи и решение замена/рост
double localBest = -DBL_MAX;
for(int i = 0; i < popSize; i++)
if(MathIsValidNumber(a [i].f) && a [i].f > localBest)
localBest = a [i].f;
bool improved = (localBest > fB_prev);
//--- 4) сборка обновлённого пула во временный пул (предвыделен в Init)
int cnt = 0;
if(!improved)
{
//--- рост: сначала весь прежний пул
for(int n = 0; n < infCount; n++)
{
ArrayCopy(tmp [cnt].c, inf [n].c, 0, 0, coords);
tmp [cnt].f = inf [n].f;
cnt++;
}
}
//--- принятые восприимчивые: иммунитет не лучше носителя -> заразился
// (читаем inf[p].f ДО перезаписи пула — наложения нет)
for(int k = 0; k < popSize; k++)
{
int p = parentOf [k];
if(MathIsValidNumber(a [k].f) && a [k].f >= inf [p].f)
{
ArrayCopy(tmp [cnt].c, a [k].c, 0, 0, coords);
tmp [cnt].f = a [k].f;
cnt++;
}
}
//--- защита: при замене с пустым набором сохраняем прежний пул
if(cnt == 0)
return;
//--- 5) отсечение до nPop (выздоровление/смерть слабейших)
if(cnt > nPop)
{
int idx [];
double tf [];
ArrayResize(idx, cnt);
ArrayResize(tf, cnt);
for(int n = 0; n < cnt; n++)
tf [n] = tmp [n].f;
ArgSortDesc(tf, idx, cnt);
for(int n = 0; n < nPop; n++)
{
int s = idx [n];
ArrayCopy(inf [n].c, tmp [s].c, 0, 0, coords);
inf [n].f = tmp [s].f;
}
infCount = nPop;
}
else
{
for(int n = 0; n < cnt; n++)
{
ArrayCopy(inf [n].c, tmp [n].c, 0, 0, coords);
inf [n].f = tmp [n].f;
}
infCount = cnt;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Gauss — стандартное нормальное (Box-Muller) |
//+------------------------------------------------------------------+
double C_AO_CVO::Gauss()
{
double u1 = u.RNDfromCI(0.0, 1.0);
double u2 = u.RNDfromCI(0.0, 1.0);
if(u1 < 1e-15)
u1 = 1e-15; // защита от ln(0)
return MathSqrt(-2.0 * MathLog(u1)) * MathCos(2.0 * M_PI * u2);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| ArgSortDesc — порядок индексов по убыванию f |
//+------------------------------------------------------------------+
void C_AO_CVO::ArgSortDesc(const double &f [], int &idx [], const int count)
{
for(int i = 0; i < count; i++)
idx [i] = i;
for(int i = 0; i < count - 1; i++)
{
int b = i;
for(int j = i + 1; j < count; j++)
if(f [idx [j]] > f [idx [b]])
b = j;
if(b != i)
{
int t = idx [i];
idx [i] = idx [b];
idx [b] = t;
}
}
}
//+------------------------------------------------------------------+
@@ -109,7 +109,7 @@
<tr><td>ACMO</td><td><a href="https://www.mql5.com/ru/articles/15921" target="_blank">atmospheric cloud model optimization</a></td></tr>
<tr><td>ADAMm</td><td><a href="https://www.mql5.com/ru/articles/16443" target="_blank">adaptive moment estimation M</a></td></tr>
<tr><td>CryStAlm</td><td><a href="https://www.mql5.com/ru/articles/19899" target="_blank">crystal structure algorithm M</a></td></tr>
<tr><td>BOA</td><td><a href="https://www.mql5.com/ru/articles/21209" target="_blank">butterfly optimization algorithm</a></td></tr>
<tr><td>BOA</td><td><a href="https://www.mql5.com/ru/articles/21209" target="_blank">butterfly optimization algorithm</a></td></tr>
<tr><td>CoSO</td><td><a href="https://www.mql5.com/ru/articles/18886" target="_blank">community of scientist optimization</a></td></tr>
<tr><td>CGO</td><td><a href="https://www.mql5.com/ru/articles/17047" target="_blank">chaos game optimization</a></td></tr>
<tr><td>BSO(Beetle)</td><td><a href="https://www.mql5.com/ru/articles/21292" target="_blank">beetle swarm optimization</a></td></tr>
@@ -151,6 +151,7 @@
<tr><td>ASSA</td><td><a href="https://www.mql5.com/ru/articles/21671" target="_blank">artificial searching swarm algorithm</a></td></tr>
<tr><td>CHA</td><td><a href="https://www.mql5.com/ru/articles/18132" target="_blank">color harmony algorithm</a></td></tr>
<tr><td>GSA</td><td><a href="https://www.mql5.com/ru/articles/12072" target="_blank">gravitational search algorithm</a></td></tr>
<tr><td>CVO</td><td><a href="https://www.mql5.com/ru/articles/22887" target="_blank">corona virus optimization</a></td></tr>
<tr><td>ACCS</td><td><a href="https://www.mql5.com/ru/articles/19861" target="_blank">artificial coronary circulation system</a></td></tr>
<tr><td>BFO</td><td><a href="https://www.mql5.com/ru/articles/12031" target="_blank">bacterial foraging optimization</a></td></tr>
<tr><td>ABC</td><td><a href="https://www.mql5.com/ru/articles/11736" target="_blank">artificial bee colony</a></td></tr>
+1
View File
@@ -93,6 +93,7 @@ CPA (cyclic parthenogenesis algorithm)
CA_Cricket (cricket algorithm)
ASSA (artificial searching swarm algorithm)
CHA (color harmony algorithm)
CVO (corona virus optimization)
ACCS (Artificial Coronary Circulation System)
AAA (artificial algae algorithm)
Boids (boids algorithm)