diff --git a/MQL5/Include/Math/AOs/PopulationAO/#C_AO_enum.mqh b/MQL5/Include/Math/AOs/PopulationAO/#C_AO_enum.mqh index bccdb56..3addc25 100644 Binary files a/MQL5/Include/Math/AOs/PopulationAO/#C_AO_enum.mqh and b/MQL5/Include/Math/AOs/PopulationAO/#C_AO_enum.mqh differ diff --git a/MQL5/Include/Math/AOs/PopulationAO/AO_NBE_NumaokaBacterialEvolution.mqh b/MQL5/Include/Math/AOs/PopulationAO/AO_NBE_NumaokaBacterialEvolution.mqh new file mode 100644 index 0000000..c39f94c --- /dev/null +++ b/MQL5/Include/Math/AOs/PopulationAO/AO_NBE_NumaokaBacterialEvolution.mqh @@ -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; + } + } +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/MQL5/Include/Math/AOs/PopulationAO/links.html b/MQL5/Include/Math/AOs/PopulationAO/links.html index 891c7f2..d5aa4ba 100644 --- a/MQL5/Include/Math/AOs/PopulationAO/links.html +++ b/MQL5/Include/Math/AOs/PopulationAO/links.html @@ -109,6 +109,7 @@ CSA(Crow)crow search algorithm ACMOatmospheric cloud model optimization ADAMmadaptive moment estimation M + NBEnumaoka bacterial evolution CryStAlmcrystal structure algorithm M BOAbutterfly optimization algorithm CoSOcommunity of scientist optimization diff --git a/README.md b/README.md index 8f98f8f..a16d367 100644 --- a/README.md +++ b/README.md @@ -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)