Files
Population-optimization-alg…/MQL5/Include/Math/AOs/PopulationAO/AO_ACMO_AtmosphereCloudsModelOptimization.mqh
T
2024-09-24 12:20:18 +05:00

671 lines
43 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_ACMO |
//| Copyright 2007-2024, Andrey Dik |
//| https://www.mql5.com/ru/users/joo |
//—————————————————————————————————————————————————————————————————————————————+
//Article: https://www.mql5.com/ru/articles/15921
#include "#C_AO.mqh"
/*
1. создать случайные капли по пространству
2. внести информацию о влажности и давлении по регионам согласно выпавшим в регионах каплях
3.
*/
//——————————————————————————————————————————————————————————————————————————————
// Region structure
struct S_ACMO_Region
{
double humidity; //humidity in the region
double pressure; //pressure in the region
double centre; //the center of the region
double x; //point of highest pressure in the region
void Init ()
{
humidity = -DBL_MAX;
pressure = 0;
}
};
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
struct S_ACMO_Area
{
S_ACMO_Region regions [];
};
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
// Cloud structure
struct S_ACMO_Cloud
{
double center []; // cloud center
double entropy []; // entropy
double entropyStart []; // initial entropy
double hyperEntropy; // hyperEntropy
int regionIndex []; // index of regions
double averageHumidity; // average humidity by regions
double droplets; // droplets
void Init (int coords)
{
ArrayResize (center, coords);
ArrayResize (entropy, coords);
ArrayResize (entropyStart, coords);
ArrayResize (regionIndex, coords);
droplets = 0.0;
}
};
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
class C_AO_ACMO : public C_AO
{
public: //--------------------------------------------------------------------
~C_AO_ACMO () { }
C_AO_ACMO ()
{
ao_name = "ACMO";
ao_desc = "Atmospheric Cloud Model Optimization";
ao_link = "https://www.mql5.com/ru/articles/15921";
popSize = 50; //population size
cloudsNumber = 4; // Number of clouds
regionsNumber = 10; // Number of regions per dimension (M)
dMin = 0.2; // Minimum number of drops relative to the average number of drops in the clouds (dN)
EnM0 = 0.2; // Initial value of entropy
HeM0 = 2.0; // Initial value of hyperentropy
λ = 0.9; // Threshold factor (threshold of the rainiest regions)
γ = 0.9; // Weaken rate
ArrayResize (params, 8);
params [0].name = "popSize"; params [0].val = popSize;
params [1].name = "cloudsNumber"; params [1].val = cloudsNumber;
params [2].name = "regionsNumber"; params [2].val = regionsNumber;
params [3].name = "dMin"; params [3].val = dMin;
params [4].name = "EnM0"; params [4].val = EnM0;
params [5].name = "HeM0"; params [5].val = HeM0;
params [6].name = "λ"; params [6].val = λ;
params [7].name = "γ"; params [7].val = γ;
}
void SetParams ()
{
popSize = (int)params [0].val;
cloudsNumber = (int)params [1].val;
regionsNumber = (int)params [2].val;
dMin = params [3].val;
EnM0 = params [4].val;
HeM0 = params [5].val;
λ = params [6].val;
γ = params [7].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 cloudsNumber; // Number of clouds
int regionsNumber; // Number of regions per dimension (M)
double dMin; // Minimum number of drops relative to the average number of drops in the clouds (dN)
double EnM0; // Initial value of entropy
double HeM0; // Initial value of hyperentropy
double λ; // Threshold factor
double γ; // Weaken rate
S_ACMO_Area areas [];
S_ACMO_Cloud clouds [];
private: //-------------------------------------------------------------------
int epochs;
int epochNow;
int dTotal; // Maximum total number of droplets (N)
double entropy []; // Entropy
double minGp; // Minimum global pressure
void MoveClouds (bool &rev);
int GetRegionIndex (double point, int ind);
void RainProcess (bool &rev);
void DropletsDistribution (double &clouds [], int &droplets []);
void UpdateRegionProperties ();
void GenerateClouds ();
double CalculateHumidityThreshold ();
void CalculateNewEntropy (S_ACMO_Cloud &cl, int t);
};
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
bool C_AO_ACMO::Init (const double &rangeMinP [],
const double &rangeMaxP [],
const double &rangeStepP [],
const int epochsP = 0)
{
if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
//----------------------------------------------------------------------------
epochs = epochsP;
epochNow = 0;
//----------------------------------------------------------------------------
dTotal = popSize;
dMin = dMin * (popSize / (double)cloudsNumber);
ArrayResize (entropy, coords);
ArrayResize (areas, coords);
for (int c = 0; c < coords; c++)
{
entropy [c] = (rangeMax [c] - rangeMin [c]) / regionsNumber;
ArrayResize (areas [c].regions, regionsNumber);
for (int r = 0; r < regionsNumber; r++)
{
areas [c].regions [r].Init ();
areas [c].regions [r].centre = rangeMin [c] + entropy [c] * (r + 0.5);
areas [c].regions [r].centre = u.SeInDiSp (areas [c].regions [r].centre, rangeMin [c], rangeMax [c], rangeStep [c]);
areas [c].regions [r].x = areas [c].regions [r].centre;
}
}
ArrayResize (clouds, cloudsNumber);
for (int i = 0; i < cloudsNumber; i++) clouds [i].Init (coords);
minGp = DBL_MAX;
return true;
}
//——————————————————————————————————————————————————————————————————————————————
/*
//------------------------------------------------------------------------------
1. На первой эпохе случайное размещение облаков:
EnCk = EnM0;
HeCk = HeM0;
//------------------------------------------------------------------------------
1.1 Движение облаков в сторону регионов с меньшим давлением:
β = deltaP / normP
d = Tck.x - Cck.c
VC = β * d;
Ck = Ck + VC
изменение поличества капель после движения:
nk = nk × (1 - γ)
изменение энтропии и гиперэнтропии:
α = ΔP / ΔPmax;
EnCk = EnCk * (1 + α)
HeCk = HeCk * (1 - α)
//------------------------------------------------------------------------------
2. Процесс дождя, выпадение капель:
распределение капель между облаками пропорционально влажности региона
увеличение количества капель к существующим в облаках
//------------------------------------------------------------------------------
3. Расчет фитнес-функции для капель
//------------------------------------------------------------------------------
4. Обновление глобального решения и минимального давления в регионах, где выпадали капли
//------------------------------------------------------------------------------
5. Проверка на распад облаков и создание новых в замен распавшихся в регионах больше порога:
правило распада вследствии расширения больше допустимого значения (разрыв облака):
En > 5 * EnM0_t
правило распада при содержании влаги ниже критического значения (высушение облака):
dCk < dMin
пороговое значение, выше которого регионы могут образовать облака:
HT = H_min + λ * (H_max - H_min);
//------------------------------------------------------------------------------
6. Энтропия и гиперэнтропия для новых облаков расчитать:
En = EnM0 / (1+2.72^(-(8-16*(t/maxT))))
He = HeM0 / (1+2.72^((8-16*(t/maxT))))
*/
//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::Moving ()
{
MoveClouds (revision);
RainProcess (revision);
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::MoveClouds (bool &rev)
{
//----------------------------------------------------------------------------
if (!rev)
{
//creating clouds with random centers---------------------------------------
for (int i = 0; i < cloudsNumber; i++)
{
for (int c = 0; c < coords; c++)
{
clouds [i].center [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
clouds [i].center [c] = u.SeInDiSp (clouds [i].center [c], rangeMin [c], rangeMax [c], rangeStep [c]);
clouds [i].regionIndex [c] = GetRegionIndex (clouds [i].center [c], c);
clouds [i].entropy [c] = entropy [c] * EnM0;
clouds [i].entropyStart [c] = clouds [i].entropy [c];
}
if (i != 0) clouds [i].hyperEntropy = HeM0;
else clouds [i].hyperEntropy = 8;
}
return;
}
//----------------------------------------------------------------------------
//search for the region with the lowest pressure------------------------------
int targetRegion = 0;
int lHind []; //lowest humidity index
ArrayResize (lHind, coords);
ArrayInitialize (lHind, 0);
double minP;
double maxP;
double normP [];
ArrayResize (normP, coords);
for (int c = 0; c < coords; c++)
{
minP = DBL_MAX;
maxP = -DBL_MAX;
for (int r = 0; r < regionsNumber; r++)
{
if (areas [c].regions [r].pressure < areas [c].regions [lHind [c]].pressure)
{
lHind [c] = r;
}
if (areas [c].regions [r].pressure < minP) minP = areas [c].regions [r].pressure;
if (areas [c].regions [r].pressure > maxP) maxP = areas [c].regions [r].pressure;
}
normP [c] = maxP - minP + DBL_EPSILON;
}
//moving the cloud to a region with less pressure-----------------------------
int clRegIND = 0;
double deltaP = 0.0;
double α = 0.0; // Entropy factor
double β = 0.0; // Atmospheric pressure factor
double VC = 0.0; // Cloud velocity
double d = 0.0; // Cloud direction
for (int i = 0; i < cloudsNumber; i++)
{
//create an artificial cloud in the region with the highest humidity,
//even if it is the region with the highest pressure.
if (i == 0)
{
for (int c = 0; c < coords; c++)
{
clouds [i].regionIndex [c] = GetRegionIndex (cB [c], c);
clouds [i].center [c] = cB [c];
}
}
else
{
for (int c = 0; c < coords; c++)
{
//find a region with lower pressure-------------------------------------
if (clouds [i].regionIndex [c] == lHind [c]) continue;
clRegIND = clouds [i].regionIndex [c];
do targetRegion = u.RNDminusOne (regionsNumber);
while (areas [c].regions [clRegIND].pressure < areas [c].regions [targetRegion].pressure);
//------------------------------------------------------------------------
deltaP = areas [c].regions [clRegIND].pressure - areas [c].regions [targetRegion].pressure;
β = deltaP / normP [c];
d = areas [c].regions [targetRegion].x - areas [c].regions [clRegIND].centre;
//d = clouds [i].entropy [c];
VC = β * d;
clouds [i].center [c] += VC;
clouds [i].center [c] = u.SeInDiSp (clouds [i].center [c], rangeMin [c], rangeMax [c], rangeStep [c]);
clouds [i].regionIndex [c] = GetRegionIndex (clouds [i].center [c], c);
α = β;
clouds [i].entropy [c] *=(1 + α);
}
clouds [i].droplets *=(1 - γ);
clouds [i].hyperEntropy *=(1 + α);
if (clouds [i].hyperEntropy > 8) clouds [i].hyperEntropy = 8;
}
}
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
int C_AO_ACMO::GetRegionIndex (double point, int ind)
{
if (point <= rangeMin [ind]) return 0;
if (point >= rangeMax [ind]) return regionsNumber - 1;
int regPos = (int)((point - rangeMin [ind]) / entropy [ind]);
return regPos;
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::RainProcess (bool &rev)
{
//to shed drops from every cloud----------------------------------------------
double cloud [];
int drops [];
ArrayResize (cloud, cloudsNumber);
ArrayResize (drops, cloudsNumber);
if (!rev)
{
ArrayInitialize (cloud, 1.0);
}
else
{
ArrayInitialize (cloud, 0.0);
double humidity;
for (int i = 0; i < cloudsNumber; i++)
{
for (int c = 0; c < coords; c++)
{
humidity = areas [c].regions [clouds [i].regionIndex [c]].humidity;
if (humidity != -DBL_MAX) cloud [i] += humidity;
else cloud [i] += minGp;
}
}
}
DropletsDistribution (cloud, drops);
//ArrayPrint (drops);
double dist = 0.0;
double centre = 0.0;
double xMin = 0.0;
double xMax = 0.0;
double x = 0.0;
int dCNT = 0;
for (int i = 0; i < cloudsNumber; i++)
{
for (int dr = 0; dr < drops [i]; dr++)
{
for (int c = 0; c < coords; c++)
{
dist = clouds [i].entropy [c];
centre = clouds [i].center [c];
xMin = centre - dist;
xMax = centre + dist;
x = u.GaussDistribution (centre, xMin, xMax, clouds [i].hyperEntropy);
if (x < rangeMin [c]) x = u.RNDfromCI (rangeMin [c], centre);
if (x > rangeMax [c]) x = u.RNDfromCI (centre, rangeMax [c]);
x = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]);
int p = u.RNDminusOne (popSize);
if (a [p].f > a [dCNT].f)
{
if (u.RNDprobab () < 0.95) a [dCNT].c [c] = a [p].c [c];
}
else
{
a [dCNT].c [c] = x;
}
}
dCNT++;
}
clouds [i].droplets += drops [i];
}
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::DropletsDistribution (double &cloud [], int &droplets [])
{
double minHumidity = DBL_MAX;
int indMinHumidity = -1;
double totalHumidity = DBL_EPSILON; //total amount of humidity in all clouds
for (int i = 0; i < ArraySize (cloud); i++)
{
totalHumidity += cloud [i];
if (cloud [i] < minHumidity)
{
minHumidity = cloud [i];
indMinHumidity = i;
}
}
if (totalHumidity == 0.0) totalHumidity = DBL_EPSILON;
// Filling the droplets array in proportion to the value in clouds
for (int i = 0; i < ArraySize (clouds); i++)
{
droplets [i] = int((cloud [i] / totalHumidity) * popSize); //proportional distribution of droplets
}
// Distribute the remaining drops, if any
int totalDrops = 0;
for (int i = 0; i < ArraySize (droplets); i++)
{
totalDrops += droplets [i];
}
// If not all drops are distributed, add the remaining drops to the element with the lowest humidity
int remainingDrops = popSize - totalDrops;
if (remainingDrops > 0)
{
droplets [indMinHumidity] += remainingDrops; //add the remaining drops to the lightest cloud
}
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::Revision ()
{
//----------------------------------------------------------------------------
int ind = -1;
for (int i = 0; i < popSize; i++)
{
if (a [i].f > fB)
{
fB = a [i].f;
ind = i;
}
if (a [i].f < minGp) minGp = a [i].f;
}
if (ind != -1) ArrayCopy (cB, a [ind].c, 0, 0, WHOLE_ARRAY);
//----------------------------------------------------------------------------
UpdateRegionProperties (); //updating humidity and pressure in the regions
GenerateClouds (); //disappearance of clouds and the creation of new ones
revision = true;
epochNow++;
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::UpdateRegionProperties ()
{
int regionIndex = 0;
for (int i = 0; i < dTotal; i++)
{
for (int c = 0; c < coords; c++)
{
regionIndex = GetRegionIndex (a [i].c [c], c);
if (a [i].f > areas [c].regions [regionIndex].humidity)
{
areas [c].regions [regionIndex].humidity = a [i].f;
areas [c].regions [regionIndex].pressure += 1.0;
areas [c].regions [regionIndex].x = a [i].c [c];
}
}
}
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::GenerateClouds ()
{
//Collecting statistics of regions capable of creating clouds-----------------
double Ht = CalculateHumidityThreshold ();
struct S_Areas
{
int regsIND []; //index of the potential region
};
S_Areas ar [];
ArrayResize (ar, coords);
int sizePr = 0;
for (int i = 0; i < coords; i++)
{
for (int r = 0; r < regionsNumber; r++)
{
if (areas [i].regions [r].humidity > Ht)
{
sizePr = ArraySize (ar [i].regsIND);
sizePr++;
ArrayResize (ar [i].regsIND, sizePr, coords);
ar [i].regsIND [sizePr - 1] = r;
}
}
}
//Check the conditions for cloud decay----------------------------------------
bool cloudDecay = false;
for (int i = 0; i < cloudsNumber; i++)
{
if (i != 0)
{
cloudDecay = false;
//checking the cloud for too much entropy---------------------------------
for (int c = 0; c < coords; c++)
{
if (clouds [i].entropy [c] > 5 * clouds [i].entropyStart [c])
{
cloudDecay = true;
break;
}
}
//checking the cloud for decay--------------------------------------------
if (!cloudDecay)
{
if (clouds [i].droplets < dMin)
{
cloudDecay = true;
}
}
//if the cloud has decayed------------------------------------------------
int regIND = 0;
if (cloudDecay)
{
//creating a cloud in a very humid region-------------------------------
for (int c = 0; c < coords; c++)
{
regIND = u.RNDminusOne (ArraySize (ar [c].regsIND));
regIND = ar [c].regsIND [regIND];
clouds [i].center [c] = areas [c].regions [regIND].x;
clouds [i].regionIndex [c] = regIND;
}
CalculateNewEntropy (clouds [i], epochNow);
}
}
}
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
double C_AO_ACMO::CalculateHumidityThreshold ()
{
double H_max = fB;
double H_min = DBL_MAX;
for (int c = 0; c < coords; c++)
{
for (int r = 0; r < regionsNumber; r++)
{
if (areas [c].regions [r].humidity != -DBL_MAX)
{
if (areas [c].regions [r].humidity < H_min)
{
H_min = areas [c].regions [r].humidity;
}
}
}
}
return H_min + λ * (H_max - H_min);
}
//——————————————————————————————————————————————————————————————————————————————
//——————————————————————————————————————————————————————————————————————————————
void C_AO_ACMO::CalculateNewEntropy (S_ACMO_Cloud &cl, int t)
{
//----------------------------------------------------------------------------
//En: 1/(1+2.72^(-(8-16*(t/maxT))))
for (int c = 0; c < coords; c++)
{
cl.entropy [c] = entropy [c] * EnM0 / (1.0 + pow (M_E, (-(8.0 - 16.0 * (t / epochs)))));
//cl.entropy [c] = entropy [c] * EnM0 * (1-0.9999*(t / epochs));
cl.entropyStart [c] = cl.entropy [c] = entropy [c];
}
//----------------------------------------------------------------------------
//He: 1/(1+2.72^((8-16*(t/maxT))))
cl.hyperEntropy = 1.0 / (1.0 + pow (M_E, ((8.0 - 16.0 * (t / epochs)))));
cl.hyperEntropy = u.Scale (cl.hyperEntropy, 0.0, 8.0, HeM0, 8.0);
}
//——————————————————————————————————————————————————————————————————————————————