This commit is contained in:
JQSakaJoo
2026-06-30 00:36:33 +04:00
parent 05e4ca47cf
commit dea4bde628
4 changed files with 435 additions and 0 deletions
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>
+1
View File
@@ -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)