316 lines
21 KiB
Plaintext
316 lines
21 KiB
Plaintext
//+————————————————————————————————————————————————————————————————————————————+
|
||||
|
|
//| C_AO_TSm |
|
|||
|
|
//| Copyright 2007-2024, Andrey Dik |
|
|||
|
|
//| https://www.mql5.com/ru/users/joo |
|
|||
|
|
//—————————————————————————————————————————————————————————————————————————————+
|
|||
|
|
|
|||
|
|
//Article: https://www.mql5.com/ru/articles/15654
|
|||
|
|
|
|||
|
|
#include "#C_AO.mqh"
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
Каждая координата разбивается на указанное количество секторов равной длины.
|
|||
|
|
Популяция: 50
|
|||
|
|
Количество секторов на каждой координате: 100
|
|||
|
|
|
|||
|
|
1. Инициализировать популяцию случайными числами в диапазоне каждой координаты.
|
|||
|
|
2. Вычислить приспособленность особи.
|
|||
|
|
3. Проверить каждую особь:
|
|||
|
|
a) если приспособленность особи улучшилась, то прибавить счетчики в соответсвующем секторе в белом листе.
|
|||
|
|
b) если приспособленность особи ухудшилась, то прибавить счетчики в соответсвующем секторе в черном листе.
|
|||
|
|
4. Для каждой особи сгенерировать новые координаты в соответсвующих секторах пропорционально из вероятности (на основе счетчиков по секторам в белом листе).
|
|||
|
|
5. Для каждой особи проверить сгенерированные координаты по черному листу, вычислить вероятность,
|
|||
|
|
если она выпадает на сектор черного списка, то выбрать случайно сектор и сгенерировать новую координату.
|
|||
|
|
6. Повторить с п.2
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
struct S_TSmSector
|
|||
|
|
{
|
|||
|
|
int sector [];
|
|||
|
|
};
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
struct S_TSmAgent
|
|||
|
|
{
|
|||
|
|
S_TSmSector blacklist []; //черный лист по секторам каждой координаты
|
|||
|
|
S_TSmSector whitelist []; //белый лист по секторам каждой координаты
|
|||
|
|
|
|||
|
|
double fPrev; //предыдущая приспособленность
|
|||
|
|
|
|||
|
|
void Init (int coords, int sectorsPerCord)
|
|||
|
|
{
|
|||
|
|
ArrayResize (blacklist, coords);
|
|||
|
|
ArrayResize (whitelist, coords);
|
|||
|
|
|
|||
|
|
for (int i = 0; i < coords; i++)
|
|||
|
|
{
|
|||
|
|
ArrayResize (blacklist [i].sector, sectorsPerCord);
|
|||
|
|
ArrayResize (whitelist [i].sector, sectorsPerCord);
|
|||
|
|
|
|||
|
|
ArrayInitialize (blacklist [i].sector, 0);
|
|||
|
|
ArrayInitialize (whitelist [i].sector, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fPrev = -DBL_MAX;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
class C_AO_TSm : public C_AO
|
|||
|
|
{
|
|||
|
|
public: //--------------------------------------------------------------------
|
|||
|
|
C_AO_TSm ()
|
|||
|
|
{
|
|||
|
|
ao_name = "TSm";
|
|||
|
|
ao_desc = "Tabu Search M";
|
|||
|
|
ao_link = "https://www.mql5.com/ru/articles/15654";
|
|||
|
|
|
|||
|
|
popSize = 50;
|
|||
|
|
sectorsPerCoord = 100;
|
|||
|
|
bestProbab = 0.8;
|
|||
|
|
|
|||
|
|
ArrayResize (params, 3);
|
|||
|
|
|
|||
|
|
params [0].name = "popSize"; params [0].val = popSize;
|
|||
|
|
params [1].name = "sectorsPerCoord"; params [1].val = sectorsPerCoord;
|
|||
|
|
params [2].name = "bestProbab"; params [2].val = bestProbab;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SetParams ()
|
|||
|
|
{
|
|||
|
|
popSize = (int)params [0].val;
|
|||
|
|
sectorsPerCoord = (int)params [1].val;
|
|||
|
|
bestProbab = params [2].val;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Init (const double &rangeMinP [], //minimum search range
|
|||
|
|
const double &rangeMaxP [], //maximum search range
|
|||
|
|
const double &rangeStepP [], //step search
|
|||
|
|
const int epochsP = 0);
|
|||
|
|
|
|||
|
|
void Moving ();
|
|||
|
|
void Revision ();
|
|||
|
|
|
|||
|
|
//----------------------------------------------------------------------------
|
|||
|
|
int sectorsPerCoord;
|
|||
|
|
double bestProbab;
|
|||
|
|
|
|||
|
|
S_TSmAgent agents [];
|
|||
|
|
|
|||
|
|
private: //-------------------------------------------------------------------
|
|||
|
|
void InitializePopulation ();
|
|||
|
|
void UpdateLists ();
|
|||
|
|
void GenerateNewCoordinates ();
|
|||
|
|
int GetSectorIndex (double coord, int dimension);
|
|||
|
|
int ChooseSectorFromWhiteList (int agentIndex, int dimension);
|
|||
|
|
double GenerateCoordInSector (int sectorIndex, int dimension);
|
|||
|
|
bool IsInBlackList (int agentIndex, int dimension, int sectorIndex);
|
|||
|
|
|
|||
|
|
};
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
bool C_AO_TSm::Init (const double &rangeMinP [], //minimum search range
|
|||
|
|
const double &rangeMaxP [], //maximum search range
|
|||
|
|
const double &rangeStepP [], //step search
|
|||
|
|
const int epochsP = 0)
|
|||
|
|
{
|
|||
|
|
if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
|
|||
|
|
|
|||
|
|
//----------------------------------------------------------------------------
|
|||
|
|
ArrayResize (agents, popSize);
|
|||
|
|
|
|||
|
|
for (int i = 0; i < popSize; i++) agents [i].Init (coords, sectorsPerCoord);
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
void C_AO_TSm::Moving ()
|
|||
|
|
{
|
|||
|
|
//----------------------------------------------------------------------------
|
|||
|
|
if (!revision)
|
|||
|
|
{
|
|||
|
|
InitializePopulation ();
|
|||
|
|
revision = true;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//----------------------------------------------------------------------------
|
|||
|
|
GenerateNewCoordinates ();
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
void C_AO_TSm::Revision ()
|
|||
|
|
{
|
|||
|
|
//----------------------------------------------------------------------------
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
if (a [i].f > fB)
|
|||
|
|
{
|
|||
|
|
fB = a [i].f;
|
|||
|
|
ArrayCopy (cB, a [i].c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//----------------------------------------------------------------------------
|
|||
|
|
UpdateLists ();
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
void C_AO_TSm::InitializePopulation ()
|
|||
|
|
{
|
|||
|
|
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]);
|
|||
|
|
}
|
|||
|
|
agents [i].fPrev = -DBL_MAX;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
void C_AO_TSm::UpdateLists ()
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
for (int c = 0; c < coords; c++)
|
|||
|
|
{
|
|||
|
|
int sectorIndex = GetSectorIndex (a [i].c [c], c);
|
|||
|
|
|
|||
|
|
if (a [i].f > agents [i].fPrev)
|
|||
|
|
{
|
|||
|
|
agents [i].whitelist [c].sector [sectorIndex]++;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
if (a [i].f < agents [i].fPrev)
|
|||
|
|
{
|
|||
|
|
agents [i].blacklist [c].sector [sectorIndex]++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
agents [i].fPrev = a [i].f;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
void C_AO_TSm::GenerateNewCoordinates ()
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < popSize; i++)
|
|||
|
|
{
|
|||
|
|
for (int c = 0; c < coords; c++)
|
|||
|
|
{
|
|||
|
|
if (u.RNDprobab () < bestProbab)
|
|||
|
|
{
|
|||
|
|
a [i].c [c] = cB [c];
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
int sectorIndex = ChooseSectorFromWhiteList (i, c);
|
|||
|
|
double newCoord = GenerateCoordInSector (sectorIndex, c);
|
|||
|
|
|
|||
|
|
if (IsInBlackList (i, c, sectorIndex))
|
|||
|
|
{
|
|||
|
|
sectorIndex = u.RNDminusOne (sectorsPerCoord);
|
|||
|
|
newCoord = GenerateCoordInSector (sectorIndex, c);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
a [i].c [c] = newCoord;
|
|||
|
|
|
|||
|
|
// Проверка и коррекция границ
|
|||
|
|
if (a [i].c [c] < rangeMin [c]) a [i].c [c] = rangeMin [c];
|
|||
|
|
if (a [i].c [c] > rangeMax [c]) a [i].c [c] = rangeMax [c];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
int C_AO_TSm::GetSectorIndex (double coord, int dimension)
|
|||
|
|
{
|
|||
|
|
if (rangeMax [dimension] == rangeMin [dimension]) return 0;
|
|||
|
|
|
|||
|
|
double sL = (rangeMax [dimension] - rangeMin [dimension]) / sectorsPerCoord;
|
|||
|
|
|
|||
|
|
int ind = (int)MathFloor ((coord - rangeMin [dimension]) / sL);
|
|||
|
|
|
|||
|
|
// Особая обработка для максимального значения
|
|||
|
|
if (coord == rangeMax [dimension]) return sectorsPerCoord - 1;
|
|||
|
|
|
|||
|
|
if (ind >= sectorsPerCoord) return sectorsPerCoord - 1;
|
|||
|
|
if (ind < 0) return 0;
|
|||
|
|
|
|||
|
|
return ind;
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
int C_AO_TSm::ChooseSectorFromWhiteList (int agentIndex, int dimension)
|
|||
|
|
{
|
|||
|
|
int totalCount = 0;
|
|||
|
|
|
|||
|
|
for (int s = 0; s < sectorsPerCoord; s++)
|
|||
|
|
{
|
|||
|
|
totalCount += agents [agentIndex].whitelist [dimension].sector [s];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (totalCount == 0)
|
|||
|
|
{
|
|||
|
|
int randomSector = u.RNDminusOne (sectorsPerCoord);
|
|||
|
|
return randomSector;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int randomValue = u.RNDminusOne (totalCount);
|
|||
|
|
int cumulativeCount = 0;
|
|||
|
|
|
|||
|
|
for (int s = 0; s < sectorsPerCoord; s++)
|
|||
|
|
{
|
|||
|
|
cumulativeCount += agents [agentIndex].whitelist [dimension].sector [s];
|
|||
|
|
|
|||
|
|
if (randomValue <= cumulativeCount)
|
|||
|
|
{
|
|||
|
|
return s;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return sectorsPerCoord - 1;
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
double C_AO_TSm::GenerateCoordInSector (int sectorIndex, int dimension)
|
|||
|
|
{
|
|||
|
|
double sectorSize = (rangeMax [dimension] - rangeMin [dimension]) / sectorsPerCoord;
|
|||
|
|
double sectorStart = rangeMin [dimension] + sectorIndex * sectorSize;
|
|||
|
|
double sectorEnd = sectorStart + sectorSize;
|
|||
|
|
|
|||
|
|
double newCoord = u.RNDfromCI (sectorStart, sectorEnd);
|
|||
|
|
|
|||
|
|
return newCoord;
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
bool C_AO_TSm::IsInBlackList (int agentIndex, int dimension, int sectorIndex)
|
|||
|
|
{
|
|||
|
|
int blackCount = agents [agentIndex].blacklist [dimension].sector [sectorIndex];
|
|||
|
|
int whiteCount = agents [agentIndex].whitelist [dimension].sector [sectorIndex];
|
|||
|
|
int totalCount = blackCount + whiteCount;
|
|||
|
|
|
|||
|
|
if (totalCount == 0) return false;
|
|||
|
|
|
|||
|
|
double blackProbability = (double)blackCount / totalCount;
|
|||
|
|
return u.RNDprobab () < blackProbability;
|
|||
|
|
}
|
|||
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|||
|
|
�
|