488 lines
30 KiB
Plaintext
488 lines
30 KiB
Plaintext
//+————————————————————————————————————————————————————————————————————————————+
|
|
//| C_AO_BCOm |
|
|
//| Copyright 2007-2024, Andrey Dik |
|
|
//| https://www.mql5.com/ru/users/joo |
|
|
//—————————————————————————————————————————————————————————————————————————————+
|
|
|
|
//Article: https://www.mql5.com/ru/articles/15711
|
|
|
|
#include "#C_AO.mqh"
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
struct S_BCO_Bacterium
|
|
{
|
|
double fPrev; // предыдущее значение целевой функции
|
|
double fHistory []; // история значений целевой функции
|
|
|
|
void Init (int coords, int historySize)
|
|
{
|
|
ArrayResize (fHistory, historySize);
|
|
ArrayInitialize (fHistory, 0.0);
|
|
fPrev = -DBL_MAX;
|
|
}
|
|
};
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
class C_AO_BCOm : public C_AO
|
|
{
|
|
public: //--------------------------------------------------------------------
|
|
~C_AO_BCOm () { }
|
|
C_AO_BCOm ()
|
|
{
|
|
ao_name = "BCOm";
|
|
ao_desc = "Bacterial Chemotaxis Optimization M";
|
|
ao_link = "https://www.mql5.com/ru/articles/15711";
|
|
|
|
popSize = 50; // размер популяции (количество бактерий)
|
|
hs = 10; // количество шагов для вычисления среднего изменения
|
|
|
|
ArrayResize (params, 2);
|
|
|
|
params [0].name = "popSize"; params [0].val = popSize;
|
|
params [1].name = "hs"; params [1].val = hs;
|
|
}
|
|
|
|
void SetParams ()
|
|
{
|
|
popSize = (int)params [0].val;
|
|
hs = (int)params [1].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 ();
|
|
|
|
//----------------------------------------------------------------------------
|
|
int hs;
|
|
|
|
S_BCO_Bacterium bacterium [];
|
|
|
|
private: //-------------------------------------------------------------------
|
|
double allowedDispl []; //допустимые смещения бактерии
|
|
|
|
double CalculateAverageDeltaFpr (int bacteriumIndex);
|
|
};
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
bool C_AO_BCOm::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 (bacterium, popSize);
|
|
for (int i = 0; i < popSize; i++) bacterium [i].Init (coords, hs);
|
|
|
|
ArrayResize (allowedDispl, coords);
|
|
for (int c = 0; c < coords; c++) allowedDispl [c] = rangeMax [c] - rangeMin [c];
|
|
|
|
return true;
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
void C_AO_BCOm::Moving ()
|
|
{
|
|
//----------------------------------------------------------------------------
|
|
if (!revision)
|
|
{
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
|
|
a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
|
}
|
|
}
|
|
|
|
revision = true;
|
|
return;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double x = 0.0;
|
|
double xMin = 0.0;
|
|
double xMax = 0.0;
|
|
double Δ = 0.0;
|
|
double ΔAve = 0.0;
|
|
double dist = 0.0;
|
|
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
ΔAve = CalculateAverageDeltaFpr (i) + DBL_EPSILON;
|
|
|
|
Δ = fabs (a [i].f - bacterium [i].fPrev) / ΔAve;
|
|
|
|
Δ = 1.0 - Δ;
|
|
|
|
if (Δ < 0.0001) Δ = 0.0001;
|
|
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
if (u.RNDprobab () < 0.5)
|
|
{
|
|
dist = allowedDispl [c] * Δ;
|
|
|
|
x = a [i].c [c];
|
|
xMin = x - dist;
|
|
xMax = x + dist;
|
|
|
|
x = u.GaussDistribution (x, xMin, xMax, 8);
|
|
|
|
if (x > rangeMax [c]) x = u.RNDfromCI (xMin, rangeMax [c]);
|
|
if (x < rangeMin [c]) x = u.RNDfromCI (rangeMin [c], xMax);
|
|
|
|
a [i].c [c] = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]);
|
|
}
|
|
else a [i].c [c] = cB [c];
|
|
}
|
|
|
|
bacterium [i].fPrev = a [i].f;
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
void C_AO_BCOm::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);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Обновление истории значений целевой функции
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
for (int j = 1; j < hs; j++)
|
|
{
|
|
bacterium [i].fHistory [j - 1] = bacterium [i].fHistory [j];
|
|
}
|
|
|
|
bacterium [i].fHistory [hs - 1] = a [i].f;
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
double C_AO_BCOm::CalculateAverageDeltaFpr (int bacteriumIndex)
|
|
{
|
|
double sum = 0;
|
|
|
|
for (int i = 1; i < hs; i++)
|
|
{
|
|
sum += bacterium [bacteriumIndex].fHistory [i] - bacterium [bacteriumIndex].fHistory [i - 1];
|
|
}
|
|
|
|
return sum / (hs - 1);
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
/*
|
|
#include "#C_AO.mqh"
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
struct S_BCO_Bacterium
|
|
{
|
|
double fPrev; // previous value of the objective function
|
|
double fHistory []; // history of objective function values
|
|
|
|
void Init (int coords, int historySize)
|
|
{
|
|
ArrayResize (fHistory, historySize);
|
|
ArrayInitialize (fHistory, 0.0);
|
|
fPrev = -DBL_MAX;
|
|
}
|
|
};
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
class C_AO_BCO : public C_AO
|
|
{
|
|
public: //--------------------------------------------------------------------
|
|
~C_AO_BCO () { }
|
|
C_AO_BCO ()
|
|
{
|
|
ao_name = "BCO";
|
|
ao_desc = "Bacterial Chemotaxis Optimization";
|
|
ao_link = "https://www.mql5.com/ru/articles/15711";
|
|
|
|
popSize = 50; // population size (number of bacteria)
|
|
hs = 10; // number of steps to calculate average change
|
|
T0 = 1.0; // initial temperature
|
|
b = 0.5; // parameter b
|
|
tau_c = 1.0; // parameter tau_c
|
|
v = 1.0; // velocity
|
|
|
|
ArrayResize (params, 6);
|
|
|
|
params [0].name = "popSize"; params [0].val = popSize;
|
|
params [1].name = "hs"; params [1].val = hs;
|
|
params [2].name = "T0"; params [2].val = T0;
|
|
params [3].name = "b"; params [3].val = b;
|
|
params [4].name = "tau_c"; params [4].val = tau_c;
|
|
params [5].name = "v"; params [5].val = v;
|
|
}
|
|
|
|
void SetParams ()
|
|
{
|
|
popSize = (int)params [0].val;
|
|
hs = (int)params [1].val;
|
|
T0 = params [2].val;
|
|
b = params [3].val;
|
|
tau_c = params [4].val;
|
|
v = params [5].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 ();
|
|
|
|
//----------------------------------------------------------------------------
|
|
int hs;
|
|
double T0;
|
|
double b;
|
|
double tau_c;
|
|
double v;
|
|
|
|
S_BCO_Bacterium bacterium [];
|
|
|
|
private: //-------------------------------------------------------------------
|
|
double CalculateAverageDeltaFpr (int bacteriumIndex);
|
|
void CalculateNewAngles (double &angles []);
|
|
void CalculateNewPosition (double l, const double &angles [], double &new_position [], const double ¤t_position []);
|
|
double GenerateFromExponentialDistribution (double T);
|
|
double CalculateCorrectedB (double f_tr, double f_pr, int bacteriumIndex);
|
|
double CalculateRotationAngle ();
|
|
int RNDdir ();
|
|
};
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
bool C_AO_BCO::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 (bacterium, popSize);
|
|
for (int i = 0; i < popSize; i++) bacterium [i].Init (coords, hs);
|
|
|
|
return true;
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
void C_AO_BCO::Moving ()
|
|
{
|
|
//----------------------------------------------------------------------------
|
|
if (!revision)
|
|
{
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
|
|
a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
|
}
|
|
}
|
|
|
|
revision = true;
|
|
return;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
double f_tr = a [i].f;
|
|
double f_pr = bacterium [i].fPrev;
|
|
|
|
double T;
|
|
|
|
if (f_tr <= f_pr)
|
|
{
|
|
T = T0;
|
|
}
|
|
else
|
|
{
|
|
double b_corr = CalculateCorrectedB (f_tr, f_pr, i);
|
|
|
|
T = T0 * exp (b_corr * (f_tr - f_pr));
|
|
}
|
|
|
|
double tau = GenerateFromExponentialDistribution (T);
|
|
|
|
double new_angles [];
|
|
ArrayResize (new_angles, coords - 1);
|
|
CalculateNewAngles (new_angles);
|
|
|
|
double l = v * tau;
|
|
double new_position [];
|
|
ArrayResize (new_position, coords);
|
|
CalculateNewPosition (l, new_angles, new_position, a [i].c);
|
|
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
a [i].c [c] = u.SeInDiSp (new_position [c], rangeMin [c], rangeMax [c], rangeStep [c]);
|
|
}
|
|
|
|
bacterium [i].fPrev = a [i].f;
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
void C_AO_BCO::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);
|
|
}
|
|
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
for (int j = 1; j < hs; j++)
|
|
{
|
|
bacterium [i].fHistory [j - 1] = bacterium [i].fHistory [j];
|
|
}
|
|
|
|
bacterium [i].fHistory [hs - 1] = a [i].f;
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
double C_AO_BCO::CalculateAverageDeltaFpr (int bacteriumIndex)
|
|
{
|
|
double sum = 0;
|
|
|
|
for (int i = 1; i < hs; i++)
|
|
{
|
|
sum += bacterium [bacteriumIndex].fHistory [i] - bacterium [bacteriumIndex].fHistory [i - 1];
|
|
}
|
|
|
|
return sum / (hs - 1);
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
void C_AO_BCO::CalculateNewAngles (double &angles [])
|
|
{
|
|
for (int i = 0; i < coords - 1; i++)
|
|
{
|
|
double theta = CalculateRotationAngle ();
|
|
double mu = 62 * (1 - MathCos (theta)) * M_PI / 180.0;
|
|
double sigma = 26 * (1 - MathCos (theta)) * M_PI / 180.0;
|
|
|
|
angles [i] = u.GaussDistribution (mu, mu - M_PI, mu + M_PI, 8);
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
void C_AO_BCO::CalculateNewPosition (double l, const double &angles [], double &new_position [], const double ¤t_position [])
|
|
{
|
|
new_position [0] = current_position [0] + l * (rangeMax [0] - rangeMin [0]);
|
|
|
|
for (int k = 0; k < coords - 1; k++)
|
|
{
|
|
new_position [0] *= MathCos (angles [k]);
|
|
}
|
|
|
|
new_position [0] *= RNDdir ();
|
|
|
|
for (int i = 1; i < coords - 1; i++)
|
|
{
|
|
new_position [i] = current_position [i] + l * MathSin (angles [i - 1]) * (rangeMax [0] - rangeMin [0]);
|
|
|
|
for (int k = i; k < coords - 1; k++)
|
|
{
|
|
new_position [i] *= MathCos (angles [k]);
|
|
}
|
|
|
|
new_position [i] *= RNDdir ();
|
|
}
|
|
|
|
if (coords > 1)
|
|
{
|
|
new_position [coords - 1] = current_position [coords - 1] + l * MathSin (angles [coords - 2]);
|
|
}
|
|
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
int C_AO_BCO::RNDdir ()
|
|
{
|
|
if (u.RNDbool () < 0.5) return -1;
|
|
|
|
return 1;
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
double C_AO_BCO::GenerateFromExponentialDistribution (double T)
|
|
{
|
|
return -T * MathLog (u.RNDprobab ());
|
|
}
|
|
|
|
double C_AO_BCO::CalculateCorrectedB (double f_tr, double f_pr, int bacteriumIndex)
|
|
{
|
|
double delta_f_tr = f_tr - f_pr;
|
|
double delta_f_pr = CalculateAverageDeltaFpr (bacteriumIndex);
|
|
|
|
if (MathAbs (delta_f_pr) < DBL_EPSILON)
|
|
{
|
|
return b;
|
|
}
|
|
else
|
|
{
|
|
return b * (1 / (MathAbs (delta_f_tr / delta_f_pr) + 1) + 1 / (MathAbs (f_pr) + 1));
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
double C_AO_BCO::CalculateRotationAngle ()
|
|
{
|
|
double cos_theta = MathExp (-tau_c / T0);
|
|
return MathArccos (cos_theta);
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
*/ |