322 lines
24 KiB
Plaintext
322 lines
24 KiB
Plaintext
//+————————————————————————————————————————————————————————————————————————————+
|
|
//| C_AO_BBO |
|
|
//| Copyright 2007-2025, Andrey Dik |
|
|
//| https://www.mql5.com/ru/users/joo |
|
|
//—————————————————————————————————————————————————————————————————————————————+
|
|
|
|
//Article: https://www.mql5.com/ru/articles/18354
|
|
|
|
#include "#C_AO.mqh"
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
class C_AO_BBO : public C_AO
|
|
{
|
|
public: //--------------------------------------------------------------------
|
|
~C_AO_BBO () { }
|
|
C_AO_BBO ()
|
|
{
|
|
ao_name = "BBO";
|
|
ao_desc = "Biogeography-Based Optimization";
|
|
ao_link = "https://www.mql5.com/ru/articles/18354";
|
|
|
|
popSize = 50; // размер популяции (количество хабитатов)
|
|
immigrationMax = 1.0; // максимальная скорость иммиграции
|
|
emigrationMax = 1.0; // максимальная скорость эмиграции
|
|
mutationProb = 0.5; // вероятность мутации
|
|
elitismCount = 2; // количество элитных решений
|
|
speciesMax = 50; // максимальное количество видов
|
|
|
|
ArrayResize (params, 6);
|
|
|
|
params [0].name = "popSize"; params [0].val = popSize;
|
|
params [1].name = "immigrationMax"; params [1].val = immigrationMax;
|
|
params [2].name = "emigrationMax"; params [2].val = emigrationMax;
|
|
params [3].name = "mutationProb"; params [3].val = mutationProb;
|
|
params [4].name = "elitismCount"; params [4].val = elitismCount;
|
|
params [5].name = "speciesMax"; params [5].val = speciesMax;
|
|
}
|
|
|
|
void SetParams ()
|
|
{
|
|
popSize = (int)params [0].val;
|
|
immigrationMax = params [1].val;
|
|
emigrationMax = params [2].val;
|
|
mutationProb = params [3].val;
|
|
elitismCount = (int)params [4].val;
|
|
speciesMax = (int)params [5].val;
|
|
}
|
|
|
|
bool Init (const double &rangeMinP [], // минимальные значения
|
|
const double &rangeMaxP [], // максимальные значения
|
|
const double &rangeStepP [], // шаг изменения
|
|
const int epochsP = 0); // количество эпох
|
|
|
|
void Moving ();
|
|
void Revision ();
|
|
|
|
//----------------------------------------------------------------------------
|
|
double immigrationMax; // максимальная скорость иммиграции
|
|
double emigrationMax; // максимальная скорость эмиграции
|
|
double mutationProb; // вероятность мутации
|
|
int elitismCount; // количество элитных решений
|
|
int speciesMax; // максимальное количество видов
|
|
|
|
private: //-------------------------------------------------------------------
|
|
struct S_HabitatData
|
|
{
|
|
int speciesCount; // количество видов в хабитате
|
|
double immigration; // скорость иммиграции
|
|
double emigration; // скорость эмиграции
|
|
double probability; // вероятность существования
|
|
};
|
|
|
|
S_HabitatData habitatData []; // данные для каждого хабитата
|
|
double probabilities []; // вероятности для подсчета мутаций
|
|
|
|
// Вспомогательные методы
|
|
void InitializePopulation ();
|
|
void CalculateRates ();
|
|
void Migration ();
|
|
void Mutation ();
|
|
double CalculateProbability (int speciesCount);
|
|
};
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
bool C_AO_BBO::Init (const double &rangeMinP [], // минимальные значения
|
|
const double &rangeMaxP [], // максимальные значения
|
|
const double &rangeStepP [], // шаг изменения
|
|
const int epochsP = 0) // количество эпох
|
|
{
|
|
if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Инициализация массивов для каждого хабитата
|
|
ArrayResize (habitatData, popSize);
|
|
ArrayResize (probabilities, speciesMax + 1);
|
|
|
|
// Расчет вероятностей для различного количества видов
|
|
double sum = 0.0;
|
|
for (int i = 0; i <= speciesMax; i++)
|
|
{
|
|
probabilities [i] = CalculateProbability (i);
|
|
sum += probabilities [i];
|
|
}
|
|
|
|
// Нормализация вероятностей
|
|
if (sum > 0)
|
|
{
|
|
for (int i = 0; i <= speciesMax; i++)
|
|
{
|
|
probabilities [i] /= sum;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//+----------------------------------------------------------------------------+
|
|
//| Основной метод оптимизации |
|
|
//+----------------------------------------------------------------------------+
|
|
void C_AO_BBO::Moving ()
|
|
{
|
|
// Первая итерация - инициализация начальной популяции
|
|
if (!revision)
|
|
{
|
|
InitializePopulation ();
|
|
revision = true;
|
|
return;
|
|
}
|
|
|
|
// Основной процесс оптимизации
|
|
// 1. Сортировка популяции по HSI (fitness)
|
|
static S_AO_Agent aTemp []; ArrayResize (aTemp, popSize);
|
|
u.Sorting (a, aTemp, popSize);
|
|
|
|
// 2. Расчет скоростей иммиграции и эмиграции
|
|
CalculateRates ();
|
|
|
|
// 3. Миграция (обмен SIV между хабитатами)
|
|
Migration ();
|
|
|
|
// 4. Мутация на основе вероятностей
|
|
Mutation ();
|
|
|
|
// 5. Сохранение состояния для следующей итерации
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
a [i].fP = a [i].f;
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//+----------------------------------------------------------------------------+
|
|
//| Обновление лучшего решения |
|
|
//+----------------------------------------------------------------------------+
|
|
void C_AO_BBO::Revision ()
|
|
{
|
|
// Поиск лучшего решения в текущей популяции
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
// Обновление лучшего решения
|
|
if (a [i].f > fB)
|
|
{
|
|
fB = a [i].f;
|
|
ArrayCopy (cB, a [i].c, 0, 0, WHOLE_ARRAY);
|
|
}
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//+----------------------------------------------------------------------------+
|
|
//| Инициализация начальной популяции |
|
|
//+----------------------------------------------------------------------------+
|
|
void C_AO_BBO::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]);
|
|
}
|
|
|
|
// Инициализация данных хабитата
|
|
habitatData [i].speciesCount = 0;
|
|
habitatData [i].immigration = 0.0;
|
|
habitatData [i].emigration = 0.0;
|
|
habitatData [i].probability = 0.0;
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//+----------------------------------------------------------------------------+
|
|
//| Расчет скоростей иммиграции и эмиграции |
|
|
//+----------------------------------------------------------------------------+
|
|
void C_AO_BBO::CalculateRates ()
|
|
{
|
|
// Для линейной модели миграции
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
// Количество видов обратно пропорционально рангу (лучшие решения имеют больше видов)
|
|
habitatData [i].speciesCount = speciesMax - (i * speciesMax / popSize);
|
|
|
|
// Скорость иммиграции уменьшается с увеличением количества видов
|
|
habitatData [i].immigration = immigrationMax * (1.0 - (double)habitatData [i].speciesCount / speciesMax);
|
|
|
|
// Скорость эмиграции увеличивается с увеличением количества видов
|
|
habitatData [i].emigration = emigrationMax * (double)habitatData [i].speciesCount / speciesMax;
|
|
|
|
// Вероятность существования хабитата
|
|
if (habitatData [i].speciesCount <= speciesMax)
|
|
{
|
|
habitatData [i].probability = probabilities [habitatData [i].speciesCount];
|
|
}
|
|
else
|
|
{
|
|
habitatData [i].probability = 0.0;
|
|
}
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//+----------------------------------------------------------------------------+
|
|
//| Миграция (обмен SIV между хабитатами) |
|
|
//+----------------------------------------------------------------------------+
|
|
void C_AO_BBO::Migration ()
|
|
{
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
// Пропускаем элитные решения
|
|
if (i < elitismCount) continue;
|
|
|
|
// Определяем, будет ли хабитат модифицирован
|
|
if (u.RNDprobab () < habitatData [i].immigration)
|
|
{
|
|
// Для каждой координаты (SIV)
|
|
for (int c = 0; c < coords; c++)
|
|
{
|
|
// Определяем, будет ли эта координата модифицирована
|
|
if (u.RNDprobab () < habitatData [i].immigration)
|
|
{
|
|
// Выбор источника миграции на основе скоростей эмиграции
|
|
double sumEmigration = 0.0;
|
|
for (int j = 0; j < popSize; j++)
|
|
{
|
|
if (j != i) sumEmigration += habitatData [j].emigration;
|
|
}
|
|
|
|
if (sumEmigration > 0)
|
|
{
|
|
// Рулеточная селекция источника
|
|
double roulette = u.RNDprobab () * sumEmigration;
|
|
double cumSum = 0.0;
|
|
|
|
for (int j = 0; j < popSize; j++)
|
|
{
|
|
if (j != i)
|
|
{
|
|
cumSum += habitatData [j].emigration;
|
|
if (roulette <= cumSum)
|
|
{
|
|
// Копирование SIV из хабитата j в хабитат i
|
|
a [i].c [c] = a [j].c [c];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//+----------------------------------------------------------------------------+
|
|
//| Мутация на основе вероятностей |
|
|
//+----------------------------------------------------------------------------+
|
|
void C_AO_BBO::Mutation ()
|
|
{
|
|
for (int i = 0; i < popSize; i++)
|
|
{
|
|
// Пропускаем элитные решения
|
|
if (i < elitismCount) continue;
|
|
|
|
// Скорость мутации обратно пропорциональна вероятности существования
|
|
double mutationRate = mutationProb * (1.0 - habitatData [i].probability);
|
|
|
|
if (u.RNDprobab () < mutationRate)
|
|
{
|
|
// Выбираем случайную координату для мутации
|
|
int mutateCoord = MathRand () % coords;
|
|
|
|
// Генерируем новое значение для выбранной координаты
|
|
a [i].c [mutateCoord] = u.RNDfromCI (rangeMin [mutateCoord], rangeMax [mutateCoord]);
|
|
a [i].c [mutateCoord] = u.SeInDiSp (a [i].c [mutateCoord],
|
|
rangeMin [mutateCoord],
|
|
rangeMax [mutateCoord],
|
|
rangeStep [mutateCoord]);
|
|
}
|
|
}
|
|
}
|
|
//——————————————————————————————————————————————————————————————————————————————
|
|
|
|
//+----------------------------------------------------------------------------+
|
|
//| Расчет вероятности для заданного количества видов |
|
|
//+----------------------------------------------------------------------------+
|
|
double C_AO_BBO::CalculateProbability (int speciesCount)
|
|
{
|
|
// Упрощенная модель вероятности
|
|
// Максимальная вероятность в середине диапазона (равновесие)
|
|
int equilibrium = speciesMax / 2;
|
|
double distance = MathAbs (speciesCount - equilibrium);
|
|
double probability = MathExp (-distance * distance / (2.0 * equilibrium * equilibrium));
|
|
|
|
return probability;
|
|
}
|
|
//—————————————————————————————————————————————————————————————————————————————— |