preview
Алгоритм анархической социальной оптимизации — Anarchic Society Optimization (ASO)

Алгоритм анархической социальной оптимизации — Anarchic Society Optimization (ASO)

MetaTrader 5Примеры | 16 августа 2024, 14:54
400 0
Andrey Dik
Andrey Dik

Содержание
  1. Введение
  2. Реализация алгоритма
  3. Результаты тестов


1. Введение

Меня всегда привлекала тема социальных отношений и возможности построения алгоритма в концепции социальных связей, так как это является наиболее интересным явлением в развитии общества, и предполагает обширное поле деятельности для возможностей алгоритмически описать структуру системы взаимоотношений и реализовать на этом алгоритм оптимизации.

Ранее в статьях мы уже рассматривали алгоритмы социального поведения, такие как evolution of social groups, artificial cooperative search. В данной статье мы постараемся разобраться с концепцией анархического общества — системой социального взаимодействия, в которой отсутствует централизованная власть и иерархические структуры, и предполагается, что люди могут организовывать свою жизнь и взаимодействовать на основе добровольных соглашений.

В основе анархического общества заложены принципы автономии и свободы, когда каждый человек может самостоятельно и независимо принимать решения, касающиеся своей жизни, без внешнего вмешательства, принципы добровольного сотрудничества, при которых люди взаимодействуют на основе согласия всех участников без принуждения, равенства прав и возможностей, а также принципы солидарности, взаимопомощи и сотрудничества. Идея очень интересная для реализации алгоритма, и уже есть попытки воплощения такого социального построения в алгоритм оптимизации Anarchic Society Optimization (ASO). Алгоритм был предложен Ахмади Джавидом и опубликован в 2011 году.

Основной идеей, которую пытался донести создатель алгоритма ASO, является разработка оптимизационного метода, инспирированного поведением индивидуумов в анархических обществах. В отличие от существующих методов роевого интеллекта, разработанных на основе роев насекомых или животных, таких как PSO и ACO, разработка алгоритма на основе изучения построения стандартного общества людей может иметь лишь ограниченный успех, поскольку хорошо организованный социум не имеет возможности достичь своих желаний индивидуальными решениями. Кроме того, ни один из членов общества не является действительно независимым и автономным, и не может радикально улучшить свою ситуацию за определенный период времени. Осознание этого привело создателя алгоритма к идее заимствовать основную концепцию для разработки у общества, основанного на аномальном устройстве. 

Основой ASO является группа индивидуумов, они непостоянны, авантюрны, не любят стабильности и часто ведут себя иррационально, перемещаясь к худшим позициям, которые посетили в фазе исследования. Уровень анархического поведения среди членов усиливается по мере увеличения различий в их ситуациях. Используя этих участников, ASO исследует пространство решений и старается избегать попадания в ловушки локального оптимума. Таким образом, создатель ASO пытается донести мысль о том, что изучение и применение принципов, основанных на аномальном поведении сообщества, может привести к созданию эффективных алгоритмов, способных решать сложные задачи оптимизации. Мы рассмотрим унифицированную структуру для ASO, которая может быть легко использована как для непрерывных, так и для дискретных задач.


2. Реализация алгоритма

Перед написанием кода алгоритма нам необходимо понять, как он устроен, и какие основные механизмы в него заложил автор. Алгоритм ASO представляет собой метод оптимизации, который сочетает в себе преимущества алгоритма particle swarm optimisation (PSO) с новыми механизмами, характерными для анархического социального поведения. Адаптивная природа и способность балансировать между различными стратегиями движения является основной "изюминкой" алгоритма.

Начнем с подробного описания алгоритма ASO:

1. Инициализация:

  • Создается популяция (popSize) из членов общества.
  • Каждый член инициализируется случайной позицией в пространстве поиска.
  • Для каждого члена сохраняется его личная лучшая и предыдущая позиции.

2. Основной цикл оптимизации:

   На каждой итерации алгоритм выполняет следующие шаги для каждого члена общества:

   a) Расчет индексов:

  • Fickleness Index (FI) — индекс непостоянства отражает нестабильность члена общества и измеряет его недовольство по сравнению с другими индивидуумами.   
  • External Irregularity Index (EI)  — внешний индекс нерегулярности оценивает разнообразие позиций в обществе и показывает отклонение от глобального лучшего решения.
  • Internal Irregularity Index (II) — внутренний индекс нерегулярности оценивает изменения положения индивидуума за итерацию и отражает отклонение от личного лучшего решения.

   b) Выбор политики движения:

      На основе сравнения индексов FI, EI и II выбирается одна из трех политик движения:

  • Current Movement Policy (CurrentMP)  — использует формулу PSO с инерцией и коэффициентами ускорения.
  • Society Movement Policy (SocietyMP)  — применяет кроссовер со случайно выбранным членом общества.
  • Past Movement Policy (PastMP)  — использует информацию о предыдущей позиции индивидуума.

   c) Анархическое поведение: с вероятностью "anarchyProb" позиция индивидуума может быть полностью рандомизированна.

   d) Обновление позиции: новая позиция проверяется на соответствие ограничениям пространства поиска.

   e) Обновление лучших позиций:

  • Обновляется личная лучшая позиция "pBest", если текущая позиция лучше.
  • Обновляется глобальная лучшая позиция "gBest", если найдено новое лучшее решение.

3. Адаптация параметров:

  • Вероятность анархического поведения "anarchyProb" постепенно уменьшается.
  • Параметр "alpha" для расчета "FI" постепенно увеличивается.
  • Инерционный вес "omega" постепенно уменьшается.

4. Параметры алгоритма:

  • popSize — размер популяции.
  • omega, lambda1, lambda2 - параметры для расчета скорости в "CurrentMP" (как в PSO).
  • anarchyProb  — вероятность анархического поведения.
  • alpha, theta, delta  — параметры для расчета индексов "FI","EI", "II" соответственно.

Алгоритм достаточно сложный и я постараюсь очень доходчиво и структурировано для простоты понимания расписать его механизм работы. Следующим шагом разберем формулы, задействованные в алгоритме.

Основная формула в алгоритме ASO унаследована из алгоритма PSO и представляет собой вычисление обновления скорости: V_i (k+1) = ω * V_i (k) + λ1 * r1 * (P_i (k) - X_i (k)) + λ2 * r2 * (G (k) - X_i (k)), где:

  • V_i (k)  — скорость частицы "i"в итерации "k".
  • X_i (k)  — позиция частицы "i" в итерации "k".
  • P_i (k)  — лучшая позиция, найденная частицей "i" до итерации "k".
  • G (k)  — глобально лучшая позиция, найденная всеми частицами до итерации "k".
  • ω — инерционный коэффициент.
  • λ1, λ2 — коэффициенты ускорения.
  • r1, r2 — случайные числа из интервала (0, 1).

Автор указывает, что формула PSO является частным случаем общей структуры ASO, когда определены соответствующие политики движения и правило комбинации. В оригинальной версии участвовала в расчетах предыдущая скорость агента. Я изменил подход, оставив только текущее значение скорости, что привело к заметному улучшению результативности алгоритма.

Формулы (1) и (2) определяют индекс изменчивости "fickleness index", "FI" для члена общества "i" на итерации "k" в алгоритме ASO. Эти формулы помогают оценить степень неудовлетворенности индивидуума своей текущей позицией по сравнению с другими позициями. Рассмотрим их подробно:

1. Формула (1) для вычисления индекса непостоянства: (kFI)i = α - α (f (Xi (k)) - f (Pi (k))) / (f (Xi (k*)) - f (Xi (k))).

Эта формула показывает, насколько текущая позиция индивидуума "i" отличается от его лучшей личной позиции и лучшей глобальной позиции, взвешенной с учетом параметра "α" (alpha).

2. Формула (2) для вычисления индекса непостоянства индивидуума "i" на итерации "k": (kFI)i = α - α (f (Xi (k)) - f (Pi (k))) / (f (G (k)) - f (Xi (k))).

Эта формула аналогична первой, но используется для других целей, там где сравниваются текущая позиция, лучшая личная позиция и лучшая глобальная позиция.

Обе формулы служат для оценки степени неудовлетворенности членов общества, что позволяет им принимать более обоснованные решения о том, как изменять свои позиции в поиске оптимального решения.

Формулы (3) и (4) описывают индексы внешней и внутренней изменчивости "external irregularity index" и "internal irregularity index" для членов общества в алгоритме.

3. Формула (3) — внешний индекс изменчивости индивидуума "i" на итерации "k": (kEI)i = exp (-(θi) (f (G) - f (Xi (k)))).

4. Формула (4) — внутренний индекс изменчивости индивидуума "i" на итерации "k": (kEI)i = 1 - exp (-δi (kD)).

Где:

  • (kFI)i  — индекс непостоянства индивидуума "i" на итерации "k".
  • α  — неотрицательное число "alpha" в интервале [0,1].
  • f (Xi (k))  — значение целевой функции для позиции индивидуума "i" на итерации "k".
  • f (Pi (k))  — значение целевой функции для лучшей позиции, ранее посещенной индивидуумом "i".
  • f (Xi (k))  — значение целевой функции для позиции лучшего индивидуума на итерации "k".
  • f (G (k))  — значение целевой функции для глобально лучшей позиции, посещенной обществом до итерации "k".
  • (kEI)i  — индекс внешней нерегулярности индивидуума "i" на итерации "k".
  • θi  — положительное число "theta".
  • kD — подходящая мера разнообразия в обществе, например, коэффициент вариации значений целевой функции индивидуумов.
  • δi — положительное число "delta".

Эти формулы показывают, что если разнообразие в обществе увеличивается (то есть, индивидуумы имеют более отличающиеся значения целевой функции), индивидуумы будут более склонны вести себя нерегулярно. Формулы служат для оценки изменчивости поведения членов общества в алгоритме ASO, что позволяет им принимать более разнообразные и адаптивные решения в процессе поиска оптимального решения.

FI200

Рисунок 1. Если текущее лучшее решение агента (200) намного меньше по значению к лучшему решению по популяции агентов (1000), то линия на графике изменяется практически линейно.

FI800

Рисунок 2. Чем меньше разница между текущим лучшим решением агента (800) и лучшим решением по популяции агентов (1000), тем больше линия на графике нелинейна.

theta

Рисунок 3. График зависимости индексов внешней и внутренней нерегулярностей в зависимости от коэффициентов "theta" и "delta" (на примере значений от 0.01 до 0.9).

Таким образом, члены общества могут использовать информацию о других членах для принятия решений о своих движениях, а также как их поведение может варьироваться в зависимости от уровня разнообразия в обществе.

Теперь мы уже немного больше знаем об алгоритме ASO и на основе полученной теории можем перейти к практической части, т.е. составим псевдокод алгоритма для его реализации в коде. Алгоритм ASO псевдокод:

Инициализация:
1. Задать параметры: popSize, omega, lambda1, lambda2, anarchyProb, alpha, theta, delta, rangeMin [], rangeMax [], rangeStep []
2. Создать популяцию из popSize членов: для каждого члена i от 0 до popSize-1: для каждой координаты c от 0 до coords-1:
    position [i].[c] = случайное число между rangeMin [c] и rangeMax [c]
    pBest [i].[c] = position [i].[c]
    prevPosition [i].[c] = position [i].[c]
    pBestFitness [i] = -бесконечность
3. Установить gBest = лучшая позиция из начальной популяции
4. Установить gBestFitness = фитнес gBest

Основной цикл:
5. Пока не достигнут критерий остановки: для каждого члена i от 0 до popSize-1:
5.1 Рассчитать индексы
    FI = CalculateFI (i)
    EI = CalculateEI (i)
    II = CalculateII (i)   
5.2 Выбрать политику движения
    Если FI > EI и FI > II: newPosition = CurrentMP (i)
    Иначе если EI > FI и EI > II: newPosition = SocietyMP (i)
    Иначе: newPosition = PastMP (i)
5.3 Применить анархическое поведение
    Если случайное число < anarchyProb: для каждой координаты c от 0 до coords-1:
        newPosition [c] = случайное число между rangeMin [c] и rangeMax [c]  
5.4 Обновить позицию для каждой координаты c от 0 до coords-1:
    prevPosition [i].[c] = position [i].[c]
    position [i].[c] = ограничить (newPosition [c], rangeMin [c], rangeMax [c], rangeStep [c])
5.5 Оценить новую позицию fitness = оценить_фитнес (position [i])
5.6 Обновить личный best если fitness > pBestFitness [i]:
    pBestFitness [i] = fitness
    pBest [i] = position [i]
5.7 Обновить глобальный best если fitness > gBestFitness:
    gBestFitness = fitness
    gBest = position [i]
5.8 Адаптировать параметр AdaptParameters ()
5.9 Функция CalculateFI (i): return 1 - alpha * (fitness [i] - pBestFitness [i]) / (gBestFitness - fitness [i])
5.10 Функция CalculateEI (i): return 1 - exp(-(gBestFitness - fitness [i]) / theta)
5.11 Функция CalculateII (i): return 1 - exp(-(pBestFitness [i] - fitness [i]) / delta)
5.12 Функция CurrentMP (i): для каждой координаты c от 0 до coords-1:
    r1 = случайное число между 0 и 1
    r2 = случайное число между 0 и 1
velocity = omega * (position [i].[c] - pBest [i].[c]) + lambda1 * r1 * (pBest [i].[c] - position [i].[c]) + lambda2 * r2 * (gBest [c] - position [i].[c])
    newPosition [c] = position [i].[c] + velocity
    return newPosition
5.13 Функция SocietyMP (i): j = случайный член популяции, не равный i, для каждой координаты c от 0 до coords - 1:
    Если случайное число < 0.5:
        newPosition [c] = position [i].[c]
    Иначе: newPosition [c] = position [j].[c]
    return newPosition
5.14 Функция PastMP (i): для каждой координаты c от 0 до coords - 1:
    Если случайное число < 0.5:
        newPosition [c] = position [i].[c]
    Иначе: newPosition [c] = prevPosition [i].[c]
    return newPosition

    Теперь, когда у нас готов псевдокод, можем приступать к написанию по нему кода алгоритма. Опишем структуру "S_ASO_Member", которая используется для представления участника (агента) в алгоритме.

    1. Поля структуры:    

    • pPrev []  — массив предыдущих позиций участников. 
    • pBest [] — массив наилучших известных позиций участников (личные лучшие). 
    • pBestFitness  — переменная хранит значение фитнеса (качества) наилучшей известной позиции.

    2. Метод "Init" инициализирует массивы "pPrev" и "pBest", устанавливая их размер в соответствии с количеством координат (или размерностью пространства поиска), переданным в качестве параметра "coords". "ArrayResize(pBest, coords)" и "ArrayResize(pPrev, coords)" — эти вызовы изменяют размер массивов до значения "coords". "pBestFitness = -DBL_MAX" — устанавливает начальное значение для фитнеса наилучшей позиции, чтобы гарантировать, что любое найденное значение будет лучше этого.

    Структура "S_ASO_Member" предназначена для хранения информации о каждом участнике в алгоритме оптимизации. Она позволяет отслеживать как текущие, так и лучшие позиции участника, а также их приспособленность. 

    //——————————————————————————————————————————————————————————————————————————————
    struct S_ASO_Member
    {
        double pPrev [];     // Previous position
        double pBest  [];    // Personal best position
        double pBestFitness; // Personal best fitness
    
    
        void Init (int coords)
        {
          ArrayResize (pBest, coords);
          ArrayResize (pPrev, coords);
          pBestFitness = -DBL_MAX;
        }
    };
    //——————————————————————————————————————————————————————————————————————————————
    

    Определим класс "C_AO_ASO", который наследуется от базового класса "C_AO". Разберем его более подробно:

    1. Параметры:

    • popSize — размер популяции (количество членов общества).
    • anarchyProb — вероятность анархического поведения, некоторые участники могут действовать независимо от других.
    • omega, lambda1, lambda2 — параметры, связанные с инерцией и ускорением, используемые для управления поведением участников.
    • alpha, theta, delta — параметры, используемые для вычисления показателей (FI, EI, II).

    2. params — массив параметров, где каждый элемент содержит имя и значение. 

    3. SetParams ()  — метод обновляет значения параметров из массива "params", что позволяет изменять параметры алгоритма после его инициализации.

    4. Init ()  — метод инициализирует алгоритм с заданными диапазонами и шагами. Он принимает массивы "rangeMinP", "rangeMaxP" и "rangeStepP", а также количество эпох "epochsP".

    5. Moving() и Revision ()  — методы реализуют основную логику движения участников и их пересмотра (обновления) в процессе оптимизации. 

    6. Поля класса:

      S_ASO_Member member []  — массив членов общества хранит информацию о каждом участнике алгоритма.

    7. Приватные методы:

    • CalculateFI — метод для вычисления значения FI (Fitness Indicator) для конкретного участника.
    • CalculateEI  — метод для вычисления значения EI (Exploration Indicator).
    • CalculateII — метод для вычисления значения II (Inertia Indicator).
    • CurrentMP, SocietyMP, PastMP  — методы реализуют логику взаимодействия участников с их текущими, общественными и прошлыми позициями.

    Класс "C_AO_ASO" представляет собой реализацию концепции "анархического общества", где участники могут действовать как совместно, так и независимо друг от друга, и включает в себя параметры, которые управляют поведением участников и методы для их инициализации и обновления. 

    //——————————————————————————————————————————————————————————————————————————————
    class C_AO_ASO : public C_AO
    {
      public: //--------------------------------------------------------------------
      ~C_AO_ASO () { }
      C_AO_ASO ()
      {
        ao_name = "ASO";
        ao_desc = "Anarchy Society Optimization";
        ao_link = "https://www.mql5.com/ru/articles/15511";
    
        popSize     = 50;     // Population size
        anarchyProb = 0.1;    // Probability of anarchic behavior
    
        omega       = 0.7;    // Inertia weight
        lambda1     = 1.5;    // Acceleration coefficient for P-best
        lambda2     = 1.5;    // Acceleration coefficient for G-best
    
        alpha       = 0.5;    // Parameter for FI calculation
        theta       = 1.0;    // Parameter for EI calculation
        delta       = 1.0;    // Parameter for II calculation
    
        ArrayResize (params, 8);
    
        params [0].name = "popSize";     params [0].val = popSize;
        params [1].name = "anarchyProb"; params [1].val = anarchyProb;
    
        params [2].name = "omega";       params [2].val = omega;
        params [3].name = "lambda1";     params [3].val = lambda1;
        params [4].name = "lambda2";     params [4].val = lambda2;
    
        params [5].name = "alpha";       params [5].val = alpha;
        params [6].name = "theta";       params [6].val = theta;
        params [7].name = "delta";       params [7].val = delta;
      }
    
      void SetParams ()
      {
        popSize     = (int)params [0].val;
        anarchyProb = params      [1].val;
    
        omega       = params      [2].val;
        lambda1     = params      [3].val;
        lambda2     = params      [4].val;
    
        alpha       = params      [5].val;
        theta       = params      [6].val;
        delta       = params      [7].val;
      }
    
      bool Init (const double &rangeMinP  [],
                 const double &rangeMaxP  [],
                 const double &rangeStepP [],
                 const int     epochsP = 0);
    
      void Moving   ();
      void Revision ();
    
      //----------------------------------------------------------------------------
      double anarchyProb; // Probability of anarchic behavior
      double omega;       // Inertia weight
      double lambda1;     // Acceleration coefficient for P-best
      double lambda2;     // Acceleration coefficient for G-best
      double alpha;       // Parameter for FI calculation
      double theta;       // Parameter for EI calculation
      double delta;       // Parameter for II calculation
    
      S_ASO_Member member []; // Vector of society members
    
      private: //-------------------------------------------------------------------
    
      double CalculateFI (int memberIndex);
      double CalculateEI (int memberIndex);
      double CalculateII (int memberIndex);
      void   CurrentMP   (S_AO_Agent &agent, S_ASO_Member &memb, int coordInd);
      void   SocietyMP   (S_AO_Agent &agent, int coordInd);
      void   PastMP      (S_AO_Agent &agent, S_ASO_Member &memb, int coordInd);
    };
    //——————————————————————————————————————————————————————————————————————————————

    Давайте разберем следующий метод "Init" класса "C_AO_ASO". Логика метода:

    • StandardInit — метод вызывается для выполнения стандартной инициализации с использованием переданных диапазонов. Если этот метод возвращает "false" — значит, произошла ошибка.
    • ArrayResize  — метод изменяет размер массива "member" до значения "popSize", который определяет количество участников (членов общества) в алгоритме.
    Далее цикл инициализирует каждого члена массива "member". Метод"Init" для каждого члена устанавливает начальные координаты, которые определены в массиве "coords". Метод "Init" предназначен для инициализации алгоритма. Он устанавливает диапазоны значений для параметров, изменяет размер массива участников и инициализирует каждого участника. 

    //——————————————————————————————————————————————————————————————————————————————
    
    bool C_AO_ASO::Init (const double &rangeMinP  [],
                         const double &rangeMaxP  [],
                         const double &rangeStepP [],
                         const int     epochsP = 0)
    {
    
      if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
    
      //----------------------------------------------------------------------------
      ArrayResize (member, popSize);
    
      for (int i = 0; i < popSize; i++) member [i].Init (coords);
    
      return true;
    
    }
    //——————————————————————————————————————————————————————————————————————————————

    Разберем далее код метода "Moving" класса "C_AO_ASO". Структура и логика метода:

    1. Проверка на первый вызов:

    • Если "revision" равно "false", метод инициализирует массив "a" случайными значениями в пределах заданных диапазонов "rangeMin" и "rangeMax".
    • Для каждой координаты "c" для каждого члена популяции "i" вызывается метод "u.RNDfromCI", который генерирует случайное значение, и затем это значение нормализуется с помощью "u.SeInDiSp".
    • Значения сохраняются в "member [i].pPrev [c]" для дальнейшего использования.
    • После этого "revision" устанавливается в "true", и метод завершает выполнение.

    2. Основная логика перемещения:

    • Для каждого члена популяции "i" вычисляются три индекса: "fi", "ei", и "ii", которые представляют собой метрики, характеризующие состояние члена популяции.
    • Для каждой координаты "c" выполняется следующее:
      • сохраняется текущее значение в "member [i].pPrev [c]".
      • генерируется случайное число "rnd" с помощью "u.RNDprobab ()".
      • если случайное число меньше "anarchyProb" (что означает исполнение вероятности проявления анархичности в поведении), то координата "c" для члена "i" будет инициализирована случайным образом из диапазона.
      • в противном случае, в зависимости от значений "fi", "ei", и "ii", вызываются методы "CurrentMP", "SocietyMP", "PastMP".
      • После всех изменений для каждой координаты "c" корректируется значение с помощью "u.SeInDiSp".

    Метод "Moving" реализует логику перемещения членов популяции в пространстве решений, основываясь на их текущих состояниях и метриках. 

    //——————————————————————————————————————————————————————————————————————————————
    void C_AO_ASO::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]);
    
            member [i].pPrev [c] = a [i].c [c];
          }
        }
    
        revision = true;
        return;
      }
    
      //----------------------------------------------------------------------------
    
      double fi  = 0.0; //индекс недовольства
      double ei  = 0.0; //индекс внешней нерегулярности
      double ii  = 0.0; //индекс внутренней нерегулярности
      double rnd = 0.0;
    
      for (int i = 0; i < popSize; i++)
      {
        fi = CalculateFI (i);
        ei = CalculateEI (i);
        ii = CalculateII (i);
    
        for (int c = 0; c < coords; c++)
        {
          member [i].pPrev [c] = a [i].c [c];
    
          rnd = u.RNDprobab ();
    
          if (u.RNDprobab () < anarchyProb) a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
          else
          {
            if (rnd > fi) CurrentMP (a [i], member [i], c);
            else
            {
              if (rnd < ei) SocietyMP (a [i], c);
              else
              {
                if (rnd < ii) PastMP (a [i], member [i], c);
              }
            }
          }
        }
    
        for (int c = 0; c < coords; c++)
        {
          a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
        }
      }
    }
    //——————————————————————————————————————————————————————————————————————————————

    От метода "Moving" переходим к методу "Revision". Общая структура и логика:

    1. Переменная "ind" инициализируется значением "-1". Она будет использоваться для хранения индекса члена популяции, который имеет наилучшее значение функции "f".

    2. Метод проходит по всем членам популяции от "0" до "popSize - 1".

    3. Поиск наилучшего значения функции: для каждого члена популяции "a [i]" проверяется, превышает ли его значение функции "f" текущее наилучшее значение "fB". Если это так, то "fB" обновляется на значение "a [i].f", а индекс "ind" устанавливается на "i".

    4. Обновление личного наилучшего значения: метод также проверяет, превышает ли значение функции "a [i].f" текущее наилучшее значение для этого члена популяции "member [i].pBestFitness". Если да, то значение обновляется, и текущие координаты "a[i].c" копируются в "member[i].pBest" с помощью функции "ArrayCopy".

    5. Копирование наилучшего решения: после завершения цикла, если был найден индекс "ind" (т.е. хотя бы один член популяции имел значение функции больше "fB"), то координаты этого члена популяции копируются в "cB" с помощью "ArrayCopy".

    Метод "Revision" отвечает за обновление наилучшего найденного решения в популяции, а также за обновление личных наилучших значений для каждого члена популяции. Он использует простую логику сравнения значений функции, чтобы определить, какие решения являются наилучшими, и сохраняет их для дальнейшего использования. 

    //——————————————————————————————————————————————————————————————————————————————
    void C_AO_ASO::Revision ()
    {
      int ind = -1;
    
      for (int i = 0; i < popSize; i++)
      {
        if (a [i].f > fB)
        {
          fB = a [i].f;
          ind = i;
        }
    
        if (a [i].f > member [i].pBestFitness)
        {
          member [i].pBestFitness = a [i].f;
    
          ArrayCopy (member [i].pBest, a [i].c, 0, 0, WHOLE_ARRAY);
        }
      }
    
      if (ind != -1) ArrayCopy (cB, a [ind].c, 0, 0, WHOLE_ARRAY);
    }
    //——————————————————————————————————————————————————————————————————————————————

    Далее метод "CalculateFI" класса "C_AO_ASO". Описание метода:

    1. Метод принимает индекс члена популяции "memberIndex", для которого будет вычисляться фитнес.

    2. Получение значений фитнеса:

    • currentFitness — получает текущее значение фитнеса члена популяции из массива "a" по индексу "memberIndex".
    • personalBestFitness — получает личное наилучшее значение фитнеса этого члена из массива "member".
    • globalBestFitness — получает глобальное наилучшее значение фитнеса, хранящееся в переменной "fB".

    3. Вычисление фитнес-индекса (FI) — метод возвращает значение, вычисленное по формуле.

    Формула нормализует разницу между личным и текущим фитнесом, деля её на разницу между глобальным и текущим фитнесом. Метод "CalculateFI" вычисляет фитнес-индекс для члена популяции, который используется для оценки его качества по сравнению с личным и глобальным наилучшими значениями фитнеса. 

    //——————————————————————————————————————————————————————————————————————————————
    double C_AO_ASO::CalculateFI (int memberIndex)
    {
      double currentFitness      = a      [memberIndex].f;
      double personalBestFitness = member [memberIndex].pBestFitness;
      double globalBestFitness   = fB;
    
      //1 - 0.9 * (800-x)/(1000-x)
      return 1 - alpha * (personalBestFitness - currentFitness) / (globalBestFitness - currentFitness);
    }
    //——————————————————————————————————————————————————————————————————————————————
    

    Далее следует метод "CalculateEI" класса "C_AO_ASO". Метод выполняет почти те же действия, что и предыдущий метод, но использует для вычисления лучший глобальный и собственный текущий фитнес.

    В результате, метод возвращает значение, которое колеблется между "0" и "1", где "1" указывает на максимальное ожидаемое улучшение, а "0" — на отсутствие улучшения. Метод "CalculateEI" вычисляет коэффициент ожидаемого улучшения для заданного члена популяции, основываясь на его текущем фитнес-значении и глобальном лучшем фитнес-значении. 

    //——————————————————————————————————————————————————————————————————————————————
    double C_AO_ASO::CalculateEI (int memberIndex)
    {
      double currentFitness    = a [memberIndex].f;
      double globalBestFitness = fB;
    
      //1-exp(-(10000-x)/(10000*0.9))
      return 1 - MathExp (-(globalBestFitness - currentFitness) / (globalBestFitness * theta));
    }
    //——————————————————————————————————————————————————————————————————————————————

    Метода "CalculateII" класса "C_AO_ASO" полностью аналогичен предыдущему, но в нём используются лучший и текущий собственный фитнес.

    Экспоненциальная функция помогает сгладить изменения и обеспечивает плавный переход между значениями. Метод "CalculateII" вычисляет индекс улучшения для члена популяции, который учитывает насколько текущее состояние фитнеса соотносится к личным достижениям.

    //——————————————————————————————————————————————————————————————————————————————
    double C_AO_ASO::CalculateII (int memberIndex)
    {
      double currentFitness      = a      [memberIndex].f;
      double personalBestFitness = member [memberIndex].pBestFitness;
    
      //1-exp(-(10000-x)/(10000*0.9))
      return 1 - MathExp (-(personalBestFitness - currentFitness) / (personalBestFitness * delta));
    }
    //——————————————————————————————————————————————————————————————————————————————
    

    Переходим к методу "CurrentMP" класса "C_AO_ASO". Описание:

    1. Генерация случайных чисел:

    • r1 = u.RNDprobab ()  — генерирует случайное число "r1" в диапазоне [0, 1].
    • r2 = u.RNDprobab ()  — генерирует случайное число "r2" в диапазоне [0, 1].

    2. Вычисление скорости "velocity" — формула включает три компонента:

    • omega * (agent.c [coordInd] - memb.pBest [coordInd])  — инерционная составляющая, движение агента с учетом его предыдущего положения.
    • lambda1 * r1 * (memb.pBest[coordInd] - agent.c[coordInd])  — направляет агента с учетом его личного наилучшего положения
    • lambda2 * r2 * (cB[coordInd] - agent.c[coordInd])  — направляет агента с учетом наилучшего положения популяции.

    3. Обновление положения агента путем добавления скорости к текущему значению координаты.

    Метод "CurrentMP" реализует обновление положения агента в пространстве на основе его текущего положения, личного наилучшего положения и наилучшего положения популяции.

    //——————————————————————————————————————————————————————————————————————————————
    void C_AO_ASO::CurrentMP (S_AO_Agent &agent, S_ASO_Member &memb, int coordInd)
    {
      double r1 = u.RNDprobab ();
      double r2 = u.RNDprobab ();
    
      double velocity = omega   *      (agent.c    [coordInd] - memb.pBest [coordInd]) +
                        lambda1 * r1 * (memb.pBest [coordInd] - agent.c    [coordInd]) +
                        lambda2 * r2 * (cB         [coordInd] - agent.c    [coordInd]);
    
      agent.c [coordInd] += velocity;
    }
    //——————————————————————————————————————————————————————————————————————————————

    Метод "SocietyMP" класса "C_AO_ASO" обновляет координату агента, основываясь на случайном выборе между групповой и личной информацией. Это позволяет агенту адаптироваться к состоянию как всей популяции, так и отдельного агента.

    //——————————————————————————————————————————————————————————————————————————————
    void C_AO_ASO::SocietyMP (S_AO_Agent &agent, int coordInd)
    {
      int otherMember = u.RNDminusOne (popSize);
    
      agent.c [coordInd] = u.RNDprobab () < 0.5 ? cB [coordInd] : member [otherMember].pBest [coordInd];
    }
    //——————————————————————————————————————————————————————————————————————————————

    Метод "PastMP" класса "C_AO_ASO" обновляет координату агента, основываясь на случайном выборе между текущим наилучшим состоянием члена популяции и его предыдущим состоянием. Это позволяет агенту учитывать как текущие достижения члена популяции, так и его прошлые результаты. Такой подход повышает комбинаторные свойства алгоритма.

    //——————————————————————————————————————————————————————————————————————————————
    void C_AO_ASO::PastMP (S_AO_Agent &agent, S_ASO_Member &memb, int coordInd)
    {
      agent.c [coordInd] = u.RNDprobab () < 0.5 ? memb.pBest [coordInd] : memb.pPrev [coordInd];
    }
    //——————————————————————————————————————————————————————————————————————————————


    3. Результаты тестов

    Распечатка работы алгоритма ASO на стенде с тестовыми функциями:

    ASO|Anarchy Society Optimization|50.0|0.01|0.7|1.5|1.5|0.5|0.1|0.1|
    =============================
    5 Hilly's; Func runs: 10000; result: 0.8487202680440514
    25 Hilly's; Func runs: 10000; result: 0.746458607174428
    500 Hilly's; Func runs: 10000; result: 0.31465494017509904
    =============================
    5 Forest's; Func runs: 10000; result: 0.9614752193694915
    25 Forest's; Func runs: 10000; result: 0.7915027321897546
    500 Forest's; Func runs: 10000; result: 0.23802894131144553
    =============================
    5 Megacity's; Func runs: 10000; result: 0.5707692307692309
    25 Megacity's; Func runs: 10000; result: 0.5406153846153848
    500 Megacity's; Func runs: 10000; result: 0.16613846153846298
    =============================
    All score: 5.17836 (57.54%)

    Рассматривая визуализацию работы алгоритма, можно сделать некоторые выводы: наблюдается разброс результатов. Однако алгоритм демонстрирует хорошие поисковые способности при работе с функциями большой размерности, что подтверждается также в распечатке результатов его работы. 

    Hilly

      ASO на тестовой функции Hilly

    Forest

    ASO на тестовой функции Forest

    Megacity

    ASO на тестовой функции Megacity

    Рейтинговая таблица популяционных алгоритмов оптимизации: алгоритм ASO после тестирования попал в десятку лучших и занял 9 место в рейтинговой таблице.

    AO Description Hilly Hilly final Forest Forest final Megacity (discrete) Megacity final Final result % of MAX
    10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F)
    1 ANS across neighbourhood search 0,94948 0,84776 0,43857 2,23581 1,00000 0,92334 0,39988 2,32323 0,70923 0,63477 0,23091 1,57491 6,134 68,15
    2 CLA code lock algorithm 0,95345 0,87107 0,37590 2,20042 0,98942 0,91709 0,31642 2,22294 0,79692 0,69385 0,19303 1,68380 6,107 67,86
    3 (P+O)ES (P+O) evolution strategies 0,92256 0,88101 0,40021 2,20379 0,97750 0,87490 0,31945 2,17185 0,67385 0,62985 0,18634 1,49003 5,866 65,17
    4 CTA comet tail algorithm 0,95346 0,86319 0,27770 2,09435 0,99794 0,85740 0,33949 2,19484 0,88769 0,56431 0,10512 1,55712 5,846 64,96
    5 SDSm stochastic diffusion search M 0,93066 0,85445 0,39476 2,17988 0,99983 0,89244 0,19619 2,08846 0,72333 0,61100 0,10670 1,44103 5,709 63,44
    6 ESG evolution of social groups 0,99906 0,79654 0,35056 2,14616 1,00000 0,82863 0,13102 1,95965 0,82333 0,55300 0,04725 1,42358 5,529 61,44
    7 SIA simulated isotropic annealing 0,95784 0,84264 0,41465 2,21513 0,98239 0,79586 0,20507 1,98332 0,68667 0,49300 0,09053 1,27020 5,469 60,76
    8 ACS artificial cooperative search 0,75547 0,74744 0,30407 1,80698 1,00000 0,88861 0,22413 2,11274 0,69077 0,48185 0,13322 1,30583 5,226 58,06
    9 ASO anarchy society optimization 0,84872 0,74646 0,31465 1,90983 0,96148 0,79150 0,23803 1,99101 0,57077 0,54062 0,16614 1,27752 5,178 57,54
    10 TSEA turtle shell evolution algorithm 0,96798 0,64480 0,29672 1,90949 0,99449 0,61981 0,22708 1,84139 0,69077 0,42646 0,13598 1,25322 5,004 55,60
    11 DE differential evolution 0,95044 0,61674 0,30308 1,87026 0,95317 0,78896 0,16652 1,90865 0,78667 0,36033 0,02953 1,17653 4,955 55,06
    12 CRO chemical reaction optimisation 0,94629 0,66112 0,29853 1,90593 0,87906 0,58422 0,21146 1,67473 0,75846 0,42646 0,12686 1,31178 4,892 54,36
    13 BSA bird swarm algorithm 0,89306 0,64900 0,26250 1,80455 0,92420 0,71121 0,24939 1,88479 0,69385 0,32615 0,10012 1,12012 4,809 53,44
    14 HS harmony search 0,86509 0,68782 0,32527 1,87818 0,99999 0,68002 0,09590 1,77592 0,62000 0,42267 0,05458 1,09725 4,751 52,79
    15 SSG saplings sowing and growing 0,77839 0,64925 0,39543 1,82308 0,85973 0,62467 0,17429 1,65869 0,64667 0,44133 0,10598 1,19398 4,676 51,95
    16 (PO)ES (PO) evolution strategies 0,79025 0,62647 0,42935 1,84606 0,87616 0,60943 0,19591 1,68151 0,59000 0,37933 0,11322 1,08255 4,610 51,22
    17 BSO brain storm optimization 0,93736 0,57616 0,29688 1,81041 0,93131 0,55866 0,23537 1,72534 0,55231 0,29077 0,11914 0,96222 4,498 49,98
    18 WOAm wale optimization algorithm M 0,84521 0,56298 0,26263 1,67081 0,93100 0,52278 0,16365 1,61743 0,66308 0,41138 0,11357 1,18803 4,476 49,74
    19 AEFA artificial electric field algorithm 0,87700 0,61753 0,25235 1,74688 0,92729 0,72698 0,18064 1,83490 0,66615 0,11631 0,09508 0,87754 4,459 49,55
    20 ACOm ant colony optimization M 0,88190 0,66127 0,30377 1,84693 0,85873 0,58680 0,15051 1,59604 0,59667 0,37333 0,02472 0,99472 4,438 49,31
    21 BFO-GA bacterial foraging optimization - ga 0,89150 0,55111 0,31529 1,75790 0,96982 0,39612 0,06305 1,42899 0,72667 0,27500 0,03525 1,03692 4,224 46,93
    22 ABHA artificial bee hive algorithm 0,84131 0,54227 0,26304 1,64663 0,87858 0,47779 0,17181 1,52818 0,50923 0,33877 0,10397 0,95197 4,127 45,85
    23 ASBO adaptive social behavior optimization 0,76331 0,49253 0,32619 1,58202 0,79546 0,40035 0,26097 1,45677 0,26462 0,17169 0,18200 0,61831 3,657 40,63
    24 MEC mind evolutionary computation 0,69533 0,53376 0,32661 1,55569 0,72464 0,33036 0,07198 1,12698 0,52500 0,22000 0,04198 0,78698 3,470 38,55
    25 IWO invasive weed optimization 0,72679 0,52256 0,33123 1,58058 0,70756 0,33955 0,07484 1,12196 0,42333 0,23067 0,04617 0,70017 3,403 37,81
    26 Micro-AIS micro artificial immune system 0,79547 0,51922 0,30861 1,62330 0,72956 0,36879 0,09398 1,19233 0,37667 0,15867 0,02802 0,56335 3,379 37,54
    27 COAm cuckoo optimization algorithm M 0,75820 0,48652 0,31369 1,55841 0,74054 0,28051 0,05599 1,07704 0,50500 0,17467 0,03380 0,71347 3,349 37,21
    28 SDOm spiral dynamics optimization M 0,74601 0,44623 0,29687 1,48912 0,70204 0,34678 0,10944 1,15826 0,42833 0,16767 0,03663 0,63263 3,280 36,44
    29 NMm Nelder-Mead method M 0,73807 0,50598 0,31342 1,55747 0,63674 0,28302 0,08221 1,00197 0,44667 0,18667 0,04028 0,67362 3,233 35,92
    30 FAm firefly algorithm M 0,58634 0,47228 0,32276 1,38138 0,68467 0,37439 0,10908 1,16814 0,28667 0,16467 0,04722 0,49855 3,048 33,87
    31 GSA gravitational search algorithm 0,64757 0,49197 0,30062 1,44016 0,53962 0,36353 0,09945 1,00260 0,32667 0,12200 0,01917 0,46783 2,911 32,34
    32 BFO bacterial foraging optimization 0,61171 0,43270 0,31318 1,35759 0,54410 0,21511 0,05676 0,81597 0,42167 0,13800 0,03195 0,59162 2,765 30,72
    33 ABC artificial bee colony 0,63377 0,42402 0,30892 1,36671 0,55103 0,21874 0,05623 0,82600 0,34000 0,14200 0,03102 0,51302 2,706 30,06
    34 BA bat algorithm 0,59761 0,45911 0,35242 1,40915 0,40321 0,19313 0,07175 0,66810 0,21000 0,10100 0,03517 0,34617 2,423 26,93
    35 SA simulated annealing 0,55787 0,42177 0,31549 1,29513 0,34998 0,15259 0,05023 0,55280 0,31167 0,10033 0,02883 0,44083 2,289 25,43
    36 IWDm intelligent water drops M 0,54501 0,37897 0,30124 1,22522 0,46104 0,14704 0,04369 0,65177 0,25833 0,09700 0,02308 0,37842 2,255 25,06
    37 PSO particle swarm optimisation 0,59726 0,36923 0,29928 1,26577 0,37237 0,16324 0,07010 0,60572 0,25667 0,08000 0,02157 0,35823 2,230 24,77
    38 Boids boids algorithm 0,43340 0,30581 0,25425 0,99346 0,35718 0,20160 0,15708 0,71586 0,27846 0,14277 0,09834 0,51957 2,229 24,77
    39 MA monkey algorithm 0,59107 0,42681 0,31816 1,33604 0,31138 0,14069 0,06612 0,51819 0,22833 0,08567 0,02790 0,34190 2,196 24,40
    40 SFL shuffled frog-leaping 0,53925 0,35816 0,29809 1,19551 0,37141 0,11427 0,04051 0,52618 0,27167 0,08667 0,02402 0,38235 2,104 23,38
    41 FSS fish school search 0,55669 0,39992 0,31172 1,26833 0,31009 0,11889 0,04569 0,47467 0,21167 0,07633 0,02488 0,31288 2,056 22,84
    42 RND random 0,52033 0,36068 0,30133 1,18234 0,31335 0,11787 0,04354 0,47476 0,25333 0,07933 0,02382 0,35648 2,014 22,37
    43 GWO grey wolf optimizer 0,59169 0,36561 0,29595 1,25326 0,24499 0,09047 0,03612 0,37158 0,27667 0,08567 0,02170 0,38403 2,009 22,32
    44 CSS charged system search 0,44252 0,35454 0,35201 1,14907 0,24140 0,11345 0,06814 0,42299 0,18333 0,06300 0,02322 0,26955 1,842 20,46
    45 EM electroMagnetism-like algorithm 0,46250 0,34594 0,32285 1,13129 0,21245 0,09783 0,10057 0,41085 0,15667 0,06033 0,02712 0,24412 1,786 19,85



    Выводы

    Исходя из результатов работы алгоритма на тестовых функциях разной размерности, можно сделать следующие выводы: ASO показывает средние результаты на гладкой функции Hilly по сравнению с ближайшими соседями в таблице, но очень достойные результаты на "острой" Forest и в особенности на дискретной Megacity. Общий итоговый балл составил 5.17836 (57.54%). Алгоритм демонстрирует хорошие поисковые способности, особенно при работе с функциями большой размерности, то есть хорошо масштабируется. Алгоритм может быть рекомендован для решения дискретных задач оптимизации, что для трейдеров является приоритетным направлением.

    tab

    Рисунок 4. Цветовая градация алгоритмов по соответствующим тестам. Белым цветом подсвечены результаты больше или равные 0.99

    chart

    Рисунок 5. Гистограмма результатов тестирования алгоритмов (по шкале от 0 до 100, чем больше, тем лучше,

    где 100 - максимально возможный теоретический результат, в архиве скрипт для расчета рейтинговой таблицы)


    Плюсы и минусы алгоритма ASO:

    Плюсы:

    1. Хорошая сходимость на различных функциях.
    2. Отличные результаты на дискретных функциях.

    Минусы:

    1. Большое количество параметров (очень сложно настроить алгоритм).
    2. Разброс результатов на функциях малой размерности.
    3. Сложная реализация.

    К статье прикреплён архив с актуальными версиями кодов алгоритмов. Автор статьи не несёт ответственности за абсолютную точность в описании канонических алгоритмов, во многие из них были внесены изменения для улучшения поисковых возможностей. Выводы и суждения, представленные в статьях, основываются на результатах проведённых экспериментов.

    Прикрепленные файлы |
    ASO.ZIP (26.93 KB)
    Метод группового учета аргументов: реализация многослойного итерационного алгоритма на MQL5 Метод группового учета аргументов: реализация многослойного итерационного алгоритма на MQL5
    В этой статье мы описываем реализацию Многослойного итерационного алгоритма как метода группового учета аргументов на языке MQL5.
    Нейросети в трейдинге: Комплексный метод прогнозирования траекторий (Traj-LLM) Нейросети в трейдинге: Комплексный метод прогнозирования траекторий (Traj-LLM)
    В данной статье я хочу познакомить вас с одним интересным методом прогнозирования траекторий, разработанным для решения задач в области автономного движения транспортных средств. Авторы метода объединили в нем лучшие элементы различных архитектурных решений.
    Алгоритм искусственных водорослей — Artificial Algae Algorithm (AAA) Алгоритм искусственных водорослей — Artificial Algae Algorithm (AAA)
    В данной статье рассматривается алгоритм искусственных водорослей (AAA), разработанный на основе биологических процессов, характерных для микроводорослей. Алгоритм включает спиральное движение, эволюционный процесс и адаптацию, что позволяет ему решать задачи оптимизации. Статья предлагает глубокий анализ принципов работы AAA и его потенциала в математическом моделировании, подчеркивая связь между природой и алгоритмическими решениями.
    Создание самооптимизирующихся советников на MQL5 Создание самооптимизирующихся советников на MQL5
    Создавайте советников, которые адаптируются к любому рынку.