526 lines
33 KiB
Plaintext
526 lines
33 KiB
Plaintext
//+————————————————————————————————————————————————————————————————————————————+
|
||
//| C_AO_CRO |
|
||
//| Copyright 2007-2024, Andrey Dik |
|
||
//| https://www.mql5.com/ru/users/joo |
|
||
//—————————————————————————————————————————————————————————————————————————————+
|
||
|
||
//Article: https://www.mql5.com/ru/articles/15041
|
||
|
||
#include "#C_AO.mqh"
|
||
|
||
enum E_ReactionType
|
||
{
|
||
synthesis,
|
||
interMolecularInefColl,
|
||
decomposition,
|
||
inefCollision
|
||
};
|
||
|
||
// Структура молекулы
|
||
struct S_CRO_Agent
|
||
{
|
||
double structure [];
|
||
int NumHit;
|
||
int indMolecule_1;
|
||
int indMolecule_2;
|
||
double KE;
|
||
double f;
|
||
E_ReactionType rType;
|
||
|
||
|
||
// Метод инициализации
|
||
void Init (int coords)
|
||
{
|
||
ArrayResize (structure, coords);
|
||
NumHit = 0;
|
||
indMolecule_1 = 0;
|
||
indMolecule_2 = 0;
|
||
f = -DBL_MAX;
|
||
KE = -DBL_MAX;
|
||
}
|
||
};
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
class C_AO_CRO : public C_AO
|
||
{
|
||
public: //--------------------------------------------------------------------
|
||
~C_AO_CRO () { }
|
||
C_AO_CRO ()
|
||
{
|
||
ao_name = "CRO";
|
||
ao_desc = "Chemical Reaction Optimisation";
|
||
ao_link = "https://www.mql5.com/ru/articles/15041";
|
||
|
||
popSize = 50; //population size
|
||
|
||
moleColl = 0.9;
|
||
alpha = 200;
|
||
beta = 0.01;
|
||
molecPerturb = 0.5;
|
||
|
||
ArrayResize (params, 5);
|
||
|
||
params [0].name = "popSize"; params [0].val = popSize;
|
||
params [1].name = "moleColl"; params [1].val = moleColl;
|
||
params [2].name = "alpha"; params [2].val = alpha;
|
||
params [3].name = "beta"; params [3].val = beta;
|
||
params [4].name = "molecPerturb"; params [4].val = molecPerturb;
|
||
|
||
}
|
||
|
||
void SetParams ()
|
||
{
|
||
popSize = (int)params [0].val;
|
||
|
||
moleColl = params [1].val;
|
||
alpha = (int)params [2].val;
|
||
beta = params [3].val;
|
||
molecPerturb = params [4].val;
|
||
}
|
||
|
||
bool Init (const double &rangeMinP [], //minimum search range
|
||
const double &rangeMaxP [], //maximum search range
|
||
const double &rangeStepP [], //step search
|
||
const int epochsP = 0); //number of epochs
|
||
|
||
void Moving ();
|
||
void Revision ();
|
||
|
||
S_CRO_Agent Mparent [];
|
||
S_CRO_Agent Mfilial [];
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
double moleColl;
|
||
int alpha;
|
||
double beta;
|
||
double molecPerturb;
|
||
|
||
private: //-------------------------------------------------------------------
|
||
bool Synthesis (int index1, int index2, int &molCNT);
|
||
bool InterMolInefColl (int index1, int index2, int &molCNT);
|
||
bool Decomposition (int index, int &molCNT);
|
||
bool InefCollision (int index, int &molCNT);
|
||
|
||
void PostSynthesis (S_CRO_Agent &mol);
|
||
void PostInterMolInefColl (S_CRO_Agent &mol);
|
||
void PostDecomposition (S_CRO_Agent &mol);
|
||
void PostInefCollision (S_CRO_Agent &mol);
|
||
|
||
void N (double &coord, int coordPos);
|
||
};
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
bool C_AO_CRO::Init (const double &rangeMinP [], //minimum search range
|
||
const double &rangeMaxP [], //maximum search range
|
||
const double &rangeStepP [], //step search
|
||
const int epochsP = 0) //number of epochs
|
||
{
|
||
if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
|
||
|
||
//----------------------------------------------------------------------------
|
||
ArrayResize (Mparent, popSize);
|
||
ArrayResize (Mfilial, popSize);
|
||
|
||
for (int i = 0; i < popSize; i++)
|
||
{
|
||
Mparent [i].Init (coords);
|
||
Mfilial [i].Init (coords);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
void C_AO_CRO::Moving ()
|
||
{
|
||
//----------------------------------------------------------------------------
|
||
if (!revision)
|
||
{
|
||
for (int i = 0; i < popSize; i++)
|
||
{
|
||
for (int c = 0; c < coords; c++)
|
||
{
|
||
Mparent [i].structure [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); // Случайная структура в диапазоне от rangeMin до rangeMax
|
||
Mparent [i].structure [c] = u.SeInDiSp (Mparent [i].structure [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
||
|
||
a [i].c [c] = Mparent [i].structure [c];
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
//----------------------------------------------------------------------------
|
||
double minKE = DBL_MAX;
|
||
|
||
for (int i = 0; i < popSize; i++)
|
||
{
|
||
if (Mparent [i].f < minKE) minKE = Mparent [i].f;
|
||
}
|
||
for (int i = 0; i < popSize; i++)
|
||
{
|
||
Mparent [i].KE = u.Scale (Mparent [i].f, minKE, fB, 0.0, 1.0);
|
||
}
|
||
|
||
//----------------------------------------------------------------------------
|
||
int molCNT = 0;
|
||
|
||
while (!IsStopped ())
|
||
{
|
||
if (u.RNDprobab () < moleColl)
|
||
{
|
||
// Выбор двух случайных молекул M1 и M2
|
||
int index1 = u.RNDminusOne (popSize);
|
||
int index2 = u.RNDminusOne (popSize);
|
||
|
||
// Если KE ≤ β:
|
||
if (Mparent [index1].KE >= beta && Mparent [index2].KE >= beta)
|
||
{
|
||
// Выполнить Синтез
|
||
if (!Synthesis (index1, index2, molCNT)) break;
|
||
}
|
||
else
|
||
{
|
||
// Выполнить Межмолекулярное Неэффективное Столкновение
|
||
if (!InterMolInefColl (index1, index2, molCNT)) break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Выбор случайной молекулы M
|
||
int index = u.RNDminusOne (popSize);
|
||
|
||
// Если NumHit > α:
|
||
if (Mparent [index].NumHit > alpha)
|
||
{
|
||
// Выполнить Разложение
|
||
if (!Decomposition (index, molCNT)) break;
|
||
}
|
||
else
|
||
{
|
||
// Выполнить Столкновение
|
||
if (!InefCollision (index, molCNT)) break;
|
||
}
|
||
}
|
||
}
|
||
|
||
for (int i = 0; i < popSize; i++)
|
||
{
|
||
ArrayCopy (a [i].c, Mfilial [i].structure);
|
||
}
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
void C_AO_CRO::Revision ()
|
||
{
|
||
//----------------------------------------------------------------------------
|
||
int ind = -1;
|
||
|
||
for (int i = 0; i < popSize; i++)
|
||
{
|
||
if (a [i].f > fB)
|
||
{
|
||
fB = a [i].f;
|
||
ind = i;
|
||
}
|
||
}
|
||
|
||
if (ind != -1) ArrayCopy (cB, a [ind].c, 0, 0, WHOLE_ARRAY);
|
||
|
||
//----------------------------------------------------------------------------
|
||
if (!revision)
|
||
{
|
||
for (int i = 0; i < popSize; i++)
|
||
{
|
||
for (int c = 0; c < coords; c++)
|
||
{
|
||
Mparent [i].f = a [i].f;
|
||
}
|
||
}
|
||
|
||
revision = true;
|
||
return;
|
||
}
|
||
|
||
//----------------------------------------------------------------------------
|
||
for (int i = 0; i < popSize; i++)
|
||
{
|
||
for (int c = 0; c < coords; c++)
|
||
{
|
||
Mfilial [i].f = a [i].f;
|
||
}
|
||
|
||
switch (Mfilial [i].rType)
|
||
{
|
||
case synthesis:
|
||
PostSynthesis (Mfilial [i]);
|
||
break;
|
||
case interMolecularInefColl:
|
||
PostInterMolInefColl (Mfilial [i]);
|
||
break;
|
||
case decomposition:
|
||
PostDecomposition (Mfilial [i]);
|
||
break;
|
||
case inefCollision:
|
||
PostInefCollision (Mfilial [i]);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
// Синтез. Получение новой молекулы путём слияния двух родительских
|
||
bool C_AO_CRO::Synthesis (int index1, int index2, int &molCNT)
|
||
{
|
||
if (molCNT >= popSize) return false;
|
||
|
||
// Создание новой молекулы M_ω' из M_ω1 и M_ω2
|
||
for (int i = 0; i < coords; i++)
|
||
{
|
||
if (u.RNDprobab () < 0.5) Mfilial [molCNT].structure [i] = Mparent [index1].structure [i];
|
||
else Mfilial [molCNT].structure [i] = Mparent [index2].structure [i];
|
||
}
|
||
|
||
Mfilial [molCNT].indMolecule_1 = index1; //сохраним индекс первой родительской молекулы
|
||
Mfilial [molCNT].indMolecule_2 = index2; //сохраним индекс второй родительской молекулы
|
||
Mfilial [molCNT].rType = synthesis;
|
||
Mfilial [molCNT].NumHit = 0;
|
||
|
||
molCNT++;
|
||
return true;
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
// Обработка результатов синтеза.
|
||
void C_AO_CRO::PostSynthesis (S_CRO_Agent &mol)
|
||
{
|
||
int ind1 = mol.indMolecule_1;
|
||
int ind2 = mol.indMolecule_2;
|
||
|
||
if (mol.f > Mparent [ind1].f && mol.f > Mparent [ind2].f)
|
||
{
|
||
if (Mparent [ind1].f < Mparent [ind2].f)
|
||
{
|
||
ArrayCopy (Mparent [ind1].structure, mol.structure);
|
||
Mparent [ind1].f = mol.f;
|
||
Mparent [ind1].NumHit = 0;
|
||
}
|
||
else
|
||
{
|
||
ArrayCopy (Mparent [ind2].structure, mol.structure);
|
||
Mparent [ind2].f = mol.f;
|
||
Mparent [ind2].NumHit = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Mparent [ind1].NumHit++;
|
||
Mparent [ind2].NumHit++;
|
||
}
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
// Межмолекулярное неэффективное столкновение. Получение новых двух молекул путём изменения двух родительских
|
||
bool C_AO_CRO::InterMolInefColl (int index1, int index2, int &molCNT)
|
||
{
|
||
if (molCNT >= popSize - 1) return false;
|
||
|
||
int index1_ = molCNT;
|
||
int index2_ = molCNT + 1;
|
||
|
||
// Получение молекул
|
||
ArrayCopy (Mfilial [index1_].structure, Mparent [index1].structure);
|
||
ArrayCopy (Mfilial [index2_].structure, Mparent [index2].structure);
|
||
|
||
// Генерация новых молекул ω'_1 = N(ω1) и ω'_2 = N(ω2) в окрестности ω1 и ω2
|
||
for (int c = 0; c < coords; c++)
|
||
{
|
||
N (Mfilial [index1_].structure [c], c);
|
||
N (Mfilial [index2_].structure [c], c);
|
||
}
|
||
|
||
for (int c = 0; c < coords; c++)
|
||
{
|
||
Mfilial [index1_].structure [c] = u.SeInDiSp (Mfilial [index1_].structure [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
||
Mfilial [index2_].structure [c] = u.SeInDiSp (Mfilial [index2_].structure [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
||
}
|
||
|
||
Mfilial [index1_].indMolecule_1 = index1; //сохраним индекс первой родительской молекулы
|
||
Mfilial [index1_].indMolecule_2 = index2_; //сохраним индекс второй дочерней молекулы
|
||
Mfilial [index1_].rType = interMolecularInefColl;
|
||
Mfilial [index1_].NumHit = 0;
|
||
|
||
Mfilial [index2_].indMolecule_1 = index2; //сохраним индекс второй родительской молекулы
|
||
Mfilial [index2_].indMolecule_2 = -1; //пометим молекулу, чтобы не обрабатывать её дважды
|
||
Mfilial [index2_].rType = interMolecularInefColl;
|
||
Mfilial [index2_].NumHit = 0;
|
||
|
||
molCNT += 2;
|
||
return true;
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
// Обработка результатов межмолекулярного неэффективного столкновения.
|
||
void C_AO_CRO::PostInterMolInefColl (S_CRO_Agent &mol)
|
||
{
|
||
if (mol.indMolecule_2 == -1) return;
|
||
|
||
int ind1 = mol.indMolecule_1;
|
||
int ind2 = Mfilial [mol.indMolecule_2].indMolecule_1;
|
||
|
||
Mparent [ind1].NumHit++;
|
||
Mparent [ind2].NumHit++;
|
||
|
||
if (mol.f + Mfilial [mol.indMolecule_2].f > Mparent [ind1].f + Mparent [ind2].f)
|
||
{
|
||
ArrayCopy (Mparent [ind1].structure, mol.structure);
|
||
Mparent [ind1].f = mol.f;
|
||
|
||
ArrayCopy (Mparent [ind2].structure, Mfilial [mol.indMolecule_2].structure);
|
||
Mparent [ind2].f = Mfilial [mol.indMolecule_2].f;
|
||
}
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
// Разложение. Получение новых двух молекул путём разложения одной родительской.
|
||
bool C_AO_CRO::Decomposition (int index, int &molCNT)
|
||
{
|
||
if (molCNT >= popSize - 1) return false;
|
||
|
||
// Создание двух новых молекул M_ω'_1 и M_ω'_2 из M_ω
|
||
int index1_ = molCNT;
|
||
int index2_ = molCNT + 1;
|
||
|
||
ArrayCopy (Mfilial [index1_].structure, Mparent [index].structure);
|
||
ArrayCopy (Mfilial [index2_].structure, Mparent [index].structure);
|
||
|
||
for (int c = 0; c < coords / 2; c++)
|
||
{
|
||
N (Mfilial [index1_].structure [c], c);
|
||
Mfilial [index1_].structure [c] = u.SeInDiSp (Mfilial [index1_].structure [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
||
}
|
||
for (int c = coords / 2; c < coords; c++)
|
||
{
|
||
N (Mfilial [index2_].structure [c], c);
|
||
Mfilial [index2_].structure [c] = u.SeInDiSp (Mfilial [index2_].structure [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
||
}
|
||
|
||
Mfilial [index1_].indMolecule_1 = index; //сохраним индекс родительской молекулы
|
||
Mfilial [index1_].indMolecule_2 = index2_; //сохраним индекс второй дочерней молекулы
|
||
Mfilial [index1_].rType = decomposition;
|
||
Mfilial [index1_].NumHit = 0;
|
||
|
||
Mfilial [index2_].indMolecule_1 = index1_; //сохраним индекс первой дочерней молекулы
|
||
Mfilial [index2_].indMolecule_2 = -1; //пометим молекулу, чтобы не обрабатывать её дважды
|
||
Mfilial [index2_].rType = decomposition;
|
||
Mfilial [index2_].NumHit = 0;
|
||
|
||
molCNT += 2;
|
||
return true;
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
// Обработка результатов разложения.
|
||
void C_AO_CRO::PostDecomposition (S_CRO_Agent &mol)
|
||
{
|
||
if (mol.indMolecule_2 == -1) return;
|
||
|
||
int ind = mol.indMolecule_1;
|
||
|
||
int index2_ = mol.indMolecule_2;
|
||
int index1_ = Mfilial [index2_].indMolecule_1;
|
||
|
||
bool flag = false;
|
||
|
||
if (Mfilial [index1_].f > Mfilial [index2_].f && Mfilial [index1_].f > Mparent [ind].f)
|
||
{
|
||
ArrayCopy (Mparent [ind].structure, Mfilial [index1_].structure);
|
||
Mparent [ind].f = Mfilial [index1_].f;
|
||
Mparent [ind].NumHit = 0;
|
||
flag = true;
|
||
}
|
||
|
||
if (!flag)
|
||
{
|
||
if (Mfilial [index2_].f > Mfilial [index1_].f && Mfilial [index2_].f > Mparent [ind].f)
|
||
{
|
||
ArrayCopy (Mparent [ind].structure, Mfilial [index2_].structure);
|
||
Mparent [ind].f = Mfilial [index2_].f;
|
||
Mparent [ind].NumHit = 0;
|
||
flag = true;
|
||
}
|
||
}
|
||
|
||
if (!flag)
|
||
{
|
||
Mparent [ind].NumHit++;
|
||
}
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
// Неэффективное столкновение. Получение новой молекулы путём смещения одной родительской.
|
||
bool C_AO_CRO::InefCollision (int index, int &molCNT)
|
||
{
|
||
if (molCNT >= popSize) return false;
|
||
|
||
int index1_ = molCNT;
|
||
|
||
ArrayCopy (Mfilial [index1_].structure, Mparent [index].structure);
|
||
|
||
for (int c = 0; c < coords; c++)
|
||
{
|
||
N (Mfilial [index1_].structure [c], c);
|
||
Mfilial [index1_].structure [c] = u.SeInDiSp (Mfilial [index1_].structure [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
||
}
|
||
|
||
Mfilial [index1_].indMolecule_1 = index; //сохраним индекс родительской молекулы
|
||
Mfilial [index1_].rType = inefCollision;
|
||
Mfilial [index1_].NumHit = 0;
|
||
|
||
molCNT++;
|
||
return true;
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
// Обработка результатов неэффективного столкновения.
|
||
void C_AO_CRO::PostInefCollision (S_CRO_Agent &mol)
|
||
{
|
||
int ind = mol.indMolecule_1;
|
||
|
||
if (mol.f > Mparent [ind].f)
|
||
{
|
||
ArrayCopy (Mparent [ind].structure, mol.structure);
|
||
Mparent [ind].f = mol.f;
|
||
Mparent [ind].NumHit = 0;
|
||
}
|
||
else
|
||
{
|
||
Mparent [ind].NumHit++;
|
||
}
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
|
||
//——————————————————————————————————————————————————————————————————————————————
|
||
void C_AO_CRO::N (double &coord, int coordPos)
|
||
{
|
||
double dist = (rangeMax [coordPos] - rangeMin [coordPos]) * molecPerturb;
|
||
|
||
double min = coord - dist; if (min < rangeMin [coordPos]) min = rangeMin [coordPos];
|
||
double max = coord + dist; if (max > rangeMax [coordPos]) max = rangeMax [coordPos];
|
||
|
||
coord = u.GaussDistribution (coord, min, max, 8);
|
||
}
|
||
//——————————————————————————————————————————————————————————————————————————————
|