Add NBE
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,433 @@
|
||||
//+——————————————————————————————————————————————————————————————————+
|
||||
//| C_AO_NBE |
|
||||
//| Copyright 2007-2026, Andrey Dik |
|
||||
//| https://www.mql5.com/ru/users/joo |
|
||||
//———————————————————————————————————————————————————————————————————+
|
||||
|
||||
#include "#C_AO.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
struct S_Bacteroid
|
||||
{
|
||||
double c []; // генотип (валидные координаты)
|
||||
double f; // фитнес
|
||||
double E; // энергия
|
||||
|
||||
void Init(int coords)
|
||||
{
|
||||
ArrayResize(c, coords);
|
||||
f = -DBL_MAX;
|
||||
E = 0.0;
|
||||
}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class C_AO_NBE : public C_AO
|
||||
{
|
||||
public:
|
||||
~C_AO_NBE() {}
|
||||
C_AO_NBE()
|
||||
{
|
||||
ao_name = "NBE";
|
||||
ao_desc = "Numaoka Bacterial Evolution";
|
||||
ao_link = "https://www.mql5.com/ru/articles/23267";
|
||||
|
||||
popSize = 30; // число бактероидов
|
||||
stepSize = 0.1; // стартовый масштаб движения (доля диапазона)
|
||||
pPlasmid = 0.1; // вероятность плазмидного переноса на бактероид/эпоху
|
||||
transFrac = 0.2; // длина плазмиды как доля coords (0..1]
|
||||
cost = 0.5; // метаболическая стоимость (приход в [0,1])
|
||||
pDeath = 0.0005; // «средовая» вероятность гибели на бактероид/эпоху
|
||||
|
||||
ArrayResize(params, 6);
|
||||
params [0].name = "popSize"; params [0].val = popSize;
|
||||
params [1].name = "stepSize"; params [1].val = stepSize;
|
||||
params [2].name = "pPlasmid"; params [2].val = pPlasmid;
|
||||
params [3].name = "transFrac"; params [3].val = transFrac;
|
||||
params [4].name = "cost"; params [4].val = cost;
|
||||
params [5].name = "pDeath"; params [5].val = pDeath;
|
||||
}
|
||||
|
||||
void SetParams()
|
||||
{
|
||||
popSize = (int)params [0].val;
|
||||
stepSize = params [1].val;
|
||||
pPlasmid = params [2].val;
|
||||
transFrac = params [3].val;
|
||||
cost = params [4].val;
|
||||
pDeath = params [5].val;
|
||||
|
||||
//--- предохранители
|
||||
if(popSize < 1)
|
||||
popSize = 1;
|
||||
if(stepSize <= 0.0)
|
||||
stepSize = 0.001;
|
||||
if(pPlasmid < 0.0)
|
||||
pPlasmid = 0.0;
|
||||
if(pPlasmid > 1.0)
|
||||
pPlasmid = 1.0;
|
||||
if(transFrac <= 0.0)
|
||||
transFrac = 0.01;
|
||||
if(transFrac > 1.0)
|
||||
transFrac = 1.0;
|
||||
if(cost < 0.0)
|
||||
cost = 0.0;
|
||||
if(pDeath < 0.0)
|
||||
pDeath = 0.0;
|
||||
if(pDeath > 1.0)
|
||||
pDeath = 1.0;
|
||||
}
|
||||
|
||||
bool Init(const double &rangeMinP [],
|
||||
const double &rangeMaxP [],
|
||||
const double &rangeStepP [],
|
||||
const int epochsP = 0);
|
||||
|
||||
void Moving();
|
||||
void Revision();
|
||||
|
||||
//--- видимые параметры
|
||||
double stepSize; // стартовый масштаб движения
|
||||
double pPlasmid; // вероятность переноса
|
||||
double transFrac; // доля coords для плазмиды
|
||||
double cost; // метаболическая стоимость
|
||||
double pDeath; // средовая гибель
|
||||
|
||||
private:
|
||||
//--- данные (массивы структур)
|
||||
S_Bacteroid bro []; // [popSize] — бактероиды
|
||||
int actType []; // [popSize] 0=движение, 1=перенос (на эпоху)
|
||||
int allIdx []; // [popSize] — 0..popSize-1
|
||||
int living []; // [popSize] — живые в текущем Revision
|
||||
|
||||
int transLen; // длина плазмиды (из transFrac)
|
||||
|
||||
//--- прогресс прогона (для отжига шага)
|
||||
int epochsDen;
|
||||
int epochNow;
|
||||
|
||||
//--- константы
|
||||
double E0; // стартовая энергия
|
||||
double Emax; // потолок энергии
|
||||
double STEP_MIN_RATIO;
|
||||
|
||||
//--- вспомогательные
|
||||
double Gauss();
|
||||
double StepNow();
|
||||
int RouletteByE(int &pool [], int n, int exclude);
|
||||
void Respawn(int i);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Init |
|
||||
//+------------------------------------------------------------------+
|
||||
bool C_AO_NBE::Init(const double &rangeMinP [],
|
||||
const double &rangeMaxP [],
|
||||
const double &rangeStepP [],
|
||||
const int epochsP = 0)
|
||||
{
|
||||
if(!StandardInit(rangeMinP, rangeMaxP, rangeStepP))
|
||||
return false;
|
||||
|
||||
//--- длина плазмиды
|
||||
transLen = (int)MathRound(transFrac * coords);
|
||||
if(transLen < 1)
|
||||
transLen = 1;
|
||||
if(transLen > coords)
|
||||
transLen = coords;
|
||||
|
||||
//--- прогресс / константы
|
||||
epochsDen = (epochsP > 1) ? epochsP - 1 : 1;
|
||||
epochNow = 0;
|
||||
E0 = 1.0;
|
||||
Emax = 5.0;
|
||||
STEP_MIN_RATIO = 0.025;
|
||||
|
||||
//--- буферы
|
||||
ArrayResize(bro, popSize);
|
||||
ArrayResize(actType, popSize);
|
||||
ArrayResize(allIdx, popSize);
|
||||
ArrayResize(living, popSize);
|
||||
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
bro [i].Init(coords);
|
||||
allIdx [i] = i;
|
||||
}
|
||||
|
||||
//--- стартовая популяция
|
||||
for(int i = 0; i < popSize; i++)
|
||||
Respawn(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Respawn — случайный генотип, стартовая энергия |
|
||||
//+------------------------------------------------------------------+
|
||||
void C_AO_NBE::Respawn(int i)
|
||||
{
|
||||
for(int c = 0; c < coords; c++)
|
||||
bro [i].c [c] = u.SeInDiSp(u.RNDfromCI(rangeMin [c], rangeMax [c]),
|
||||
rangeMin [c], rangeMax [c], rangeStep [c]);
|
||||
bro [i].f = -DBL_MAX;
|
||||
bro [i].E = E0;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gauss — стандартное нормальное (Box–Muller) |
|
||||
//+------------------------------------------------------------------+
|
||||
double C_AO_NBE::Gauss()
|
||||
{
|
||||
double u1 = u.RNDfromCI(0.0, 1.0);
|
||||
double u2 = u.RNDfromCI(0.0, 1.0);
|
||||
if(u1 < 1e-15)
|
||||
u1 = 1e-15;
|
||||
return MathSqrt(-2.0 * MathLog(u1)) * MathCos(2.0 * M_PI * u2);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| StepNow — масштаб движения с линейным отжигом |
|
||||
//+------------------------------------------------------------------+
|
||||
double C_AO_NBE::StepNow()
|
||||
{
|
||||
double t = (double)epochNow / (double)epochsDen;
|
||||
if(t > 1.0)
|
||||
t = 1.0;
|
||||
return stepSize * (STEP_MIN_RATIO + (1.0 - STEP_MIN_RATIO) * (1.0 - t));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| RouletteByE — индекс из pool[0..n-1], взвешенный по энергии, |
|
||||
//| с исключением exclude (или -1) |
|
||||
//+------------------------------------------------------------------+
|
||||
int C_AO_NBE::RouletteByE(int &pool [], int n, int exclude)
|
||||
{
|
||||
double sum = 0.0;
|
||||
for(int k = 0; k < n; k++)
|
||||
{
|
||||
int idx = pool [k];
|
||||
if(idx == exclude)
|
||||
continue;
|
||||
double e = bro [idx].E;
|
||||
if(e < 1e-12)
|
||||
e = 1e-12;
|
||||
sum += e;
|
||||
}
|
||||
|
||||
if(sum <= 0.0)
|
||||
{
|
||||
int idx = pool [u.RNDminusOne(n)];
|
||||
return idx;
|
||||
}
|
||||
|
||||
double r = u.RNDprobab() * sum;
|
||||
double acc = 0.0;
|
||||
for(int k = 0; k < n; k++)
|
||||
{
|
||||
int idx = pool [k];
|
||||
if(idx == exclude)
|
||||
continue;
|
||||
double e = bro [idx].E;
|
||||
if(e < 1e-12)
|
||||
e = 1e-12;
|
||||
acc += e;
|
||||
if(acc >= r)
|
||||
return idx;
|
||||
}
|
||||
return pool [n - 1];
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving |
|
||||
//| Каждый бактероид этой эпохой делает ЛИБО плазмидный перенос, |
|
||||
//| ЛИБО хемотаксис-движение. Кандидат пишется в a[i].c. |
|
||||
//+------------------------------------------------------------------+
|
||||
void C_AO_NBE::Moving()
|
||||
{
|
||||
//--- первый прогон: генотипы -> слоты для первичной оценки
|
||||
if(!revision)
|
||||
{
|
||||
for(int i = 0; i < popSize; i++)
|
||||
for(int c = 0; c < coords; c++)
|
||||
a [i].c [c] = bro [i].c [c];
|
||||
return;
|
||||
}
|
||||
|
||||
epochNow++;
|
||||
double step = StepNow();
|
||||
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
//--- стартуем кандидата с текущего генотипа
|
||||
for(int c = 0; c < coords; c++)
|
||||
a [i].c [c] = bro [i].c [c];
|
||||
|
||||
if(popSize > 1 && u.RNDprobab() < pPlasmid)
|
||||
{
|
||||
//--- ПЛАЗМИДНЫЙ ПЕРЕНОС: блок от донора (рулетка по энергии)
|
||||
actType [i] = 1;
|
||||
|
||||
int donor = RouletteByE(allIdx, popSize, i);
|
||||
int span = coords - transLen + 1;
|
||||
if(span < 1)
|
||||
span = 1;
|
||||
int start = u.RNDminusOne(span);
|
||||
|
||||
for(int t = 0; t < transLen; t++)
|
||||
{
|
||||
int c = start + t;
|
||||
if(c < coords)
|
||||
a [i].c [c] = bro [donor].c [c];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- ХЕМОТАКСИС: покоординатное гауссово движение
|
||||
actType [i] = 0;
|
||||
|
||||
for(int c = 0; c < coords; c++)
|
||||
{
|
||||
double rng = rangeMax [c] - rangeMin [c];
|
||||
double v = bro [i].c [c] + Gauss() * step * rng;
|
||||
a [i].c [c] = u.SeInDiSp(v, rangeMin [c], rangeMax [c], rangeStep [c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Revision |
|
||||
//| Приёмка хода -> энергобаланс -> гибель -> деление. |
|
||||
//+------------------------------------------------------------------+
|
||||
void C_AO_NBE::Revision()
|
||||
{
|
||||
//--- глобальный лучший
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
if(a [i].f > fB)
|
||||
{
|
||||
fB = a [i].f;
|
||||
ArrayCopy(cB, a [i].c, 0, 0, coords);
|
||||
}
|
||||
}
|
||||
|
||||
//--- первичная фиксация
|
||||
if(!revision)
|
||||
{
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
bro [i].f = a [i].f;
|
||||
bro [i].E = E0;
|
||||
}
|
||||
revision = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//--- приёмка хода: перенос безусловно, движение — greedy
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
if(actType [i] == 1)
|
||||
{
|
||||
for(int c = 0; c < coords; c++)
|
||||
bro [i].c [c] = a [i].c [c];
|
||||
bro [i].f = a [i].f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(a [i].f >= bro [i].f)
|
||||
{
|
||||
for(int c = 0; c < coords; c++)
|
||||
bro [i].c [c] = a [i].c [c];
|
||||
bro [i].f = a [i].f;
|
||||
}
|
||||
//--- иначе откат: bro[i] остаётся прежним
|
||||
}
|
||||
}
|
||||
|
||||
//--- энергобаланс: приход ~ популяционно-относительной адаптированности
|
||||
double fmin = DBL_MAX;
|
||||
double fmax = -DBL_MAX;
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
if(bro [i].f < fmin)
|
||||
fmin = bro [i].f;
|
||||
if(bro [i].f > fmax)
|
||||
fmax = bro [i].f;
|
||||
}
|
||||
double span = fmax - fmin;
|
||||
if(span < 1e-12)
|
||||
span = 1e-12;
|
||||
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
double gain = (bro [i].f - fmin) / span; // [0,1]
|
||||
bro [i].E += gain - cost;
|
||||
if(bro [i].E > Emax)
|
||||
bro [i].E = Emax;
|
||||
}
|
||||
|
||||
//--- гибель: энергетическая (E<=0) или средовая (pDeath)
|
||||
int nLiving = 0;
|
||||
bool dead [];
|
||||
ArrayResize(dead, popSize);
|
||||
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
bool die = (bro [i].E <= 0.0) || (u.RNDprobab() < pDeath);
|
||||
dead [i] = die;
|
||||
if(!die)
|
||||
{
|
||||
living [nLiving] = i;
|
||||
nLiving++;
|
||||
}
|
||||
}
|
||||
|
||||
//--- заполнение освободившихся слотов делением (или массовый респаун)
|
||||
if(nLiving == 0)
|
||||
{
|
||||
for(int i = 0; i < popSize; i++)
|
||||
Respawn(i);
|
||||
return;
|
||||
}
|
||||
|
||||
double step = StepNow();
|
||||
|
||||
for(int i = 0; i < popSize; i++)
|
||||
{
|
||||
if(!dead [i])
|
||||
continue;
|
||||
|
||||
//--- родитель — энергичный живой (рулетка по энергии)
|
||||
int p = RouletteByE(living, nLiving, -1);
|
||||
|
||||
//--- деление: потомок = мутированная копия родителя рядом
|
||||
for(int c = 0; c < coords; c++)
|
||||
{
|
||||
double rng = rangeMax [c] - rangeMin [c];
|
||||
double v = bro [p].c [c] + Gauss() * step * rng;
|
||||
bro [i].c [c] = u.SeInDiSp(v, rangeMin [c], rangeMax [c], rangeStep [c]);
|
||||
}
|
||||
|
||||
//--- энергия делится пополам
|
||||
double half = bro [p].E * 0.5;
|
||||
bro [i].E = half;
|
||||
bro [p].E = bro [p].E - half;
|
||||
|
||||
//--- фитнес потомка оценится на следующей эпохе; оценка-заглушка
|
||||
bro [i].f = bro [p].f;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -109,6 +109,7 @@
|
||||
<tr><td>CSA(Crow)</td><td><a href="https://www.mql5.com/ru/articles/19669" target="_blank">crow search algorithm</a></td></tr>
|
||||
<tr><td>ACMO</td><td><a href="https://www.mql5.com/ru/articles/15921" target="_blank">atmospheric cloud model optimization</a></td></tr>
|
||||
<tr><td>ADAMm</td><td><a href="https://www.mql5.com/ru/articles/16443" target="_blank">adaptive moment estimation M</a></td></tr>
|
||||
<tr><td>NBE</td><td><a href="https://www.mql5.com/ru/articles/23267" target="_blank">numaoka bacterial evolution</a></td></tr>
|
||||
<tr><td>CryStAlm</td><td><a href="https://www.mql5.com/ru/articles/19899" target="_blank">crystal structure algorithm M</a></td></tr>
|
||||
<tr><td>BOA</td><td><a href="https://www.mql5.com/ru/articles/21209" target="_blank">butterfly optimization algorithm</a></td></tr>
|
||||
<tr><td>CoSO</td><td><a href="https://www.mql5.com/ru/articles/18886" target="_blank">community of scientist optimization</a></td></tr>
|
||||
|
||||
@@ -59,6 +59,7 @@ CLA_L (competitive learning algorithm)
|
||||
CSA(CROW) (crow search algorithm)
|
||||
ACMO (atmospheric cloud model optimization)
|
||||
ADAMm (adaptive moment estimation)
|
||||
NBE (numaoka bacterial evolution)
|
||||
CryStAlm (crystal structure algorithm M)
|
||||
BOA (butterfly optimization algorithm)
|
||||
CoSO (community of scientist optimization)
|
||||
|
||||
Reference in New Issue
Block a user