Files
Population-optimization-alg…/MQL5/Include/Math/AOs/PopulationAO/AO_CRO_ChemicalReactionOptimisation.mqh
T
2024-06-12 20:52:55 +05:00

526 lines
33 KiB
Plaintext
Raw 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_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);
}
//——————————————————————————————————————————————————————————————————————————————