//+——————————————————————————————————————————————————————————————————+ //| C_AO_HS | //| Copyright 2007-2025, Andrey Dik | //| https://www.mql5.com/ru/users/joo | //+——————————————————————————————————————————————————————————————————+ #include "#C_AO.mqh" //———————————————————————————————————————————————————————————————————— class C_AO_HS : public C_AO { public: //------------------------------------------------------------ ~C_AO_HS() { } C_AO_HS() { ao_name = "HS"; ao_desc = "Harmony Search"; ao_link = "https://www.mql5.com/ru/articles/11230"; popSize = 50; Eh = 0.9; Ep = 0.1; rangeKo = 0.1; ArrayResize(params, 4); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "Eh"; params [1].val = Eh; params [2].name = "Ep"; params [2].val = Ep; params [3].name = "rangeKo"; params [3].val = rangeKo; } void SetParams() { popSize = (int)params [0].val; Eh = params [1].val; Ep = params [2].val; rangeKo = params [3].val; } bool Init(const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0); void Moving(); void Revision(); //------------------------------------------------------------------ double Eh; // частота случайного выбора аккорда из гармонии double Ep; // частота пошаговой настройки double rangeKo; // диапазон случайного отклонения private: //----------------------------------------------------------- int epochs; int epochNow; double freq []; // ширина диапазона по каждой координате }; //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— bool C_AO_HS::Init(const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0) { if(!StandardInit(rangeMinP, rangeMaxP, rangeStepP)) return false; //-------------------------------------------------------------------- epochs = epochsP; epochNow = 0; ArrayResize(freq, coords); for(int c = 0; c < coords; c++) { freq [c] = rangeMax [c] - rangeMin [c]; } return true; } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— void C_AO_HS::Moving() { //-------------------------------------------------------------------- if(!revision) { 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]); } } revision = true; return; } //-------------------------------------------------------------------- epochNow++; double r = 0.0; int addr = 0; double minB = 0.0; double maxB = 0.3; double B = 0.0; if(epochs > 0) B = ((epochs - epochNow) / (double)epochs) * (maxB - minB) + minB; else B = maxB; for(int i = 0; i < popSize; i++) { for(int c = 0; c < coords; c++) { r = u.RNDfromCI(0.0, 1.0); if(r <= Eh) { // выбрать аккорд из случайной гармонии r = u.RNDfromCI(0.0, popSize - 1); addr = (int)MathRound(r); if(addr < 0) addr = 0; if(addr > popSize - 1) addr = popSize - 1; a [i].c [c] = a [addr].cB [c]; // пошаговая настройка с вероятностью Ep r = u.RNDfromCI(0.0, 1.0); if(r < Ep) { r = u.RNDfromCI(-1.0, 1.0); a [i].c [c] = a [i].c [c] + r * B * freq [c]; } } else { // случайное отклонение от личного лучшего r = u.RNDfromCI(-1.0, 1.0); a [i].c [c] = a [i].cB [c] + r * rangeKo * freq [c]; } a [i].c [c] = u.SeInDiSp(a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } //———————————————————————————————————————————————————————————————————— //———————————————————————————————————————————————————————————————————— void C_AO_HS::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); } // обновление личного лучшего if(a [i].f > a [i].fB) { a [i].fB = a [i].f; ArrayCopy(a [i].cB, a [i].c, 0, 0, WHOLE_ARRAY); } } } //————————————————————————————————————————————————————————————————————