Files
Population-optimization-alg…/MQL5/Include/Math/AOs/PopulationAO/AO_CRO_ChemicalReactionOptimisation.mqh
T

526 lines
33 KiB
Plaintext
Raw Normal View History

2024-06-12 20:52:55 +05:00
//+————————————————————————————————————————————————————————————————————————————+
//| 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);
}
//——————————————————————————————————————————————————————————————————————————————