preview
Алгоритм сверчков — Cricket Algorithm (CA)

Алгоритм сверчков — Cricket Algorithm (CA)

MetaTrader 5Трейдинг |
77 0
Andrey Dik
Andrey Dik

Содержание

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


Введение

Разберем для целей оптимизации еще один достаточно новый алгоритм. Алгоритм сверчков (Cricket Algorithm, CA) — это метаэвристический метод, разработанный Canayaz и Karci в 2015 году и опубликованный в журнале Applied Intelligence. Алгоритм черпает вдохновение из поведения сверчков в природе, в частности из их способности общаться с помощью звука и ориентироваться на сородичей с наиболее громким стрекотанием. В основу алгоритма положены физические законы распространения звука в атмосфере, что придаёт ему уникальную связь с реальным миром.

Алгоритм объединяет элементы трёх известных метаэвристик: алгоритма летучих мышей (Bat Algorithm), роевой оптимизации частиц (Particle Swarm Optimization) и алгоритма светлячков (Firefly Algorithm). От алгоритма летучих мышей заимствован механизм обновления скорости и позиции на основе частоты, от роевой оптимизации — концепция движения к лучшему решению, а от алгоритма светлячков — притяжение к более «ярким» (в данном случае — более громким) особям.



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

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

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

Скорость звука в воздухе зависит от температуры и вычисляется по формуле:

V = 20.1 × √(273 + C); где V - скорость звука в метрах в секунду, C - температура воздуха в градусах Цельсия. При температуре 20°C скорость звука составляет примерно 343 м/с.

Частота звука связана со скоростью распространения и длиной волны соотношением:

f = V / λ;  где f - частота в герцах, V - скорость звука, λ - длина волны. В контексте алгоритма длина волны интерпретируется как расстояние между сверчком и лучшим решением в популяции.

Интенсивность звука убывает обратно пропорционально квадрату расстояния от источника (закон обратных квадратов):

I = W / (4πr²); где I - интенсивность звука в Вт/м², W - мощность источника в ваттах, r - расстояние от источника в метрах. Отсюда мощность звука выражается как: W = I × 4πr².

Уровень звукового давления на определённом расстоянии от источника рассчитывается по формуле:

Lp = Lw + 10 × log₁₀[Q / (4πr²)]; где Lp - уровень звукового давления в децибелах, Lw - уровень звуковой мощности источника, Q - коэффициент направленности (принимается равным 1 для неровной местности и 2 для плоской), r - расстояние от источника.

При распространении звука в атмосфере происходит его поглощение воздухом. Величина атмосферного поглощения вычисляется согласно стандарту ISO 9613-1:

A_atm = 7.4 × (f² × r / Ø) × 10⁻⁸; где A_atm - коэффициент поглощения, f - частота звука в герцах, r - расстояние в метрах, Ø - относительная влажность воздуха в процентах. Реальный уровень звукового давления с учётом атмосферного поглощения составляет: Lp' = Lp − A_atm.

Эти физические формулы используются в алгоритме для расчёта коэффициента притяжения между агентами, что позволяет моделировать реалистичное затухание «слышимости» сверчков с расстоянием.

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

На этапе инициализации создаётся популяция из "n" агентов, каждый из которых представляет потенциальное решение задачи оптимизации. Позиции агентов инициализируются случайным образом в пределах допустимой области поиска. Для каждого агента вычисляется значение целевой функции, и определяется лучшее решение в популяции.

На каждой итерации для каждого сверчка выполняется следующая последовательность действий. Сначала генерируется случайное число стрекотаний "N" в диапазоне от 0 до 120. По закону Долбира это число преобразуется в температуру воздуха. Формула для температуры в градусах Цельсия имеет вид:

T_C = 10 + (N − 40) / 7. При N = 0 температура составляет примерно 4.3°C, при N = 120 - около 21.4°C. Таким образом, случайное число стрекотаний определяет «индивидуальную» температуру для каждого сверчка на данной итерации.

Далее вычисляется скорость звука при полученной температуре:

V_i = 20.1 × √(273 + T_C). Значение скорости звука варьируется примерно от 335 до 345 м/с в зависимости от температуры. Затем определяется расстояние "λ" от текущего сверчка до лучшего решения в популяции. Это расстояние вычисляется как евклидова норма разности координат:

λ = ‖x_i − x*‖; где x_i - позиция текущего сверчка, x* - позиция лучшего решения. В реализации расстояние нормализуется делением на диагональ пространства поиска, чтобы получить безразмерную величину в диапазоне от 0 до 1.

На основе скорости звука и расстояния вычисляется максимальная частота:

f_max = V_i / λ. Чем ближе сверчок к лучшему решению (меньше λ), тем выше частота, что усиливает притяжение. Чем дальше сверчок (больше λ), тем ниже частота, что позволяет ему более свободно исследовать пространство.

Индивидуальная частота каждого сверчка определяется по формуле из алгоритма летучих мышей:

f_i = f_min + (f_max − f_min) × β; где f_min = 0, а β - случайное число в диапазоне [0, 1]. Таким образом, частота f_i принимает случайное значение от нуля до f_max.

После вычисления частоты обновляются скорость и позиция сверчка. Формула обновления скорости:

v_i^t = v_i^(t−1) + (x* − x_i) × f_i + V_i; где v_i^t - новая скорость, v_i^(t−1) - скорость на предыдущей итерации, (x* − x_i) - направление к лучшему решению, f_i - частота, V_i - скорость звука, добавляющая стохастический импульс. В отличие от оригинального алгоритма летучих мышей, здесь добавляется слагаемое V_i, что является уникальной особенностью алгоритма сверчков.

Новая позиция вычисляется как:

x_i^t = x_i^(t−1) + v_i^t. Важно отметить, что обновление скорости и позиции выполняется для всех сверчков на каждой итерации, независимо от последующего выбора стратегии.

После обновления позиции алгоритм выбирает одну из двух стратегий дальнейшего поиска. Выбор осуществляется на основе коэффициента поглощения звука "γ", который вычисляется с использованием формулы атмосферного поглощения. Генерируется случайное число r в диапазоне [0, 1], и если r > γ, выполняется фаза притяжения к более громким сверчкам (аналог алгоритма светлячков). В противном случае сверчок совершает случайное блуждание вблизи лучшего решения.

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

Фаза притяжения (Firefly-подобная). Если случайное число превышает коэффициент поглощения, сверчок выполняет фазу притяжения к более громким сородичам. Для этого перебираются все остальные сверчки в популяции, и для каждого сверчка "j", чей звук громче (значение целевой функции лучше), чем у текущего сверчка "i", выполняется притяжение.

Сначала вычисляется расстояние между сверчками:

r_ij = ‖x_i − x_j‖. Затем по формулам акустики рассчитываются мощность звука, уровень звукового давления, атмосферное поглощение и реальный уровень звукового давления. На основе этих величин определяется коэффициент притяжения:

K = K_0 × exp(−γ × r_ij²); где K_0 - базовый коэффициент, зависящий от реального уровня звукового давления, γ - параметр затухания притяжения с расстоянием.

Позиция сверчка обновляется по формуле:

x_i = x_i + K × (x_j − x_i) + α × ε; где первое слагаемое - притяжение к более громкому сверчку "j", а второе - случайный шум с амплитудой "α" и случайным вектором "ε". Параметр "α" уменьшается со временем по формуле α = α_0 × 0.95^t, где t - номер итерации, что обеспечивает переход от исследования к эксплуатации.

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

Если случайное число не превышает коэффициент поглощения, сверчок выполняет случайное блуждание вблизи лучшего решения:

x_i = x* + 0.01 × rand(0, 1); где x* - позиция лучшего решения, а случайное число масштабирует отклонение. Эта стратегия обеспечивает локальный поиск в окрестности лучшего найденного решения. При случайном блуждании скорость сверчка обнуляется, что позволяет ему начать заново из новой точки.

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

Алгоритм использует следующие параметры: размер популяции "n" (типичное значение 50), начальный коэффициент шума α_0 = 0.5, коэффициент затухания притяжения γ = 1.0, относительная влажность воздуха Ø = 50%, коэффициент направленности Q = 2. Параметр "α" уменьшается на каждой итерации умножением на 0.95, что обеспечивает постепенный переход от глобального исследования к локальной оптимизации.

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

Коэффициент поглощения звука также требует нормализации для получения значений в диапазоне [0, 1], что обеспечивает осмысленное вероятностное переключение между стратегиями поиска. Без нормализации формула атмосферного поглощения может давать значения, многократно превышающие единицу, что приводит к вырождению алгоритма в чистое случайное блуждание.

Cricket_Algorithm_Illustration

Рисунок 1. Иллюстрация работы алгоритма CA-Cricket

Иллюстрация включает Search Space Dynamics (левая панель): визуализация агентов-сверчков в пространстве поиска; звуковые волны от лучшего решения; стрелки движения (velocity, attraction); обозначение λ (wavelength/distance to best).

Algorithm Flow (центральная панель): пошаговая блок-схема алгоритма этапы 1-5 с формулами; ветвление (rand > γ ?) YES: Firefly Phase, NO: Random Walk. Key Physical Equations (нижняя панель): eq.7-10: звуковые уравнения; eq.11-13: обновление скорости; eq.15-16: коэффициент притяжения. Core Concepts (правая панель): Dolbear's Law с температурной шкалой; Sound Propagation с inverse square lawAdaptive; Strategy SelectionHybrid; Algorithm nature (Bat + Firefly + unique Cricket features)

Напишем псевдокод алгоритма CA-Cricket:

// Инициализация
   FOR i = 1 TO n DO
      xᵢ ← случайная позиция в пределах bounds
      vᵢ ← 0
      fᵢ ← ЦелеваяФункция(xᵢ)
   END FOR
   
   x* ← позиция агента с лучшим f
   f* ← лучшее значение f
   diagonal ← диагональ пространства поиска
   α ← α₀
   
   // Основной цикл
   FOR iter = 1 TO MaxIter DO
      α ← α₀ × 0.95^iter
      IF α < 0.01 THEN α ← 0.01
      
      FOR i = 1 TO n DO
         // Генерация параметров стрекотания
         N ← случайное число из [0, 120]
         T ← 10 + (N - 40) / 7
         V ← 20.1 × √(273 + T)
         
         // Вычисление частоты
         λ ← ‖xᵢ - x*‖ / diagonal
         f_max ← (V / 340) / λ
         fᵢ ← f_max × случайное число из [0, 1]
         
         // Обновление скорости и позиции (выполняется всегда)
         FOR каждой координаты c DO
            направление ← (x*[c] - xᵢ[c]) / диапазон[c]
            импульс ← (V/340 - 1) × 0.1 × случайное из [-1, 1]
            vᵢ[c] ← vᵢ[c] + направление × fᵢ × диапазон[c] × 0.1 + импульс × диапазон[c]
            vᵢ[c] ← ограничить(vᵢ[c], -0.3 × диапазон[c], 0.3 × диапазон[c])
            xᵢ[c] ← xᵢ[c] + vᵢ[c]
         END FOR
         
         // Выбор стратегии
         γ ← 0.1 + 0.4 × (1 - λ)
         r ← случайное число из [0, 1]
         
         IF r > γ THEN
            // Фаза притяжения (Firefly)
            FOR j = 1 TO n DO
               IF fⱼ > fᵢ THEN
                  r_ij ← ‖xᵢ - xⱼ‖ / diagonal
                  K ← вычислить коэффициент притяжения по формулам акустики
                  FOR каждой координаты c DO
                     xᵢ[c] ← xᵢ[c] + K × (xⱼ[c] - xᵢ[c]) + α × диапазон[c] × случайное из [-0.5, 0.5]
                  END FOR
               END IF
            END FOR
         ELSE
            // Случайное блуждание
            FOR каждой координаты c DO
               xᵢ[c] ← x*[c] + α × 0.2 × диапазон[c] × случайное из [-1, 1]
               vᵢ[c] ← 0
            END FOR
         END IF
         
         // Ограничение координат
         xᵢ ← привести к границам bounds
         
         // Обновление лучшего решения
         fᵢ ← ЦелеваяФункция(xᵢ)
         IF fᵢ > f* THEN
            f* ← fᵢ
            x* ← xᵢ
         END IF
      END FOR
   END FOR
   
   RETURN x*, f*
КОНЕЦ

Теперь можем приступить к самой реализации алгоритма. Вспомогательная структура "S_CA_Velocity" будет предназначена для хранения вектора скорости отдельного агента. Структура содержит единственное поле - динамический массив "v", размерность которого соответствует количеству координат в пространстве поиска. Использование отдельной структуры для хранения скоростей позволит нам организовать массив скоростей всех агентов популяции и обеспечит удобный доступ к компонентам скорости каждого агента по индексу координаты.

//————————————————————————————————————————————————————————————————————
struct S_CA_Velocity
{
    double v [];
};
//————————————————————————————————————————————————————————————————————

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

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

Приватные члены класса хранят внутреннее состояние алгоритма. Переменная "alpha" содержит текущее значение коэффициента шума, которое уменьшается с каждой итерацией. Переменная "currentEpoch" отслеживает номер текущей итерации алгоритма. Константа "humidity" задаёт относительную влажность воздуха в процентах и используется в формуле атмосферного поглощения звука. Константа "Q" определяет коэффициент направленности звука, принимающий значение 2 для плоской местности. Массив "vel" типа "S_CA_Velocity" хранит векторы скоростей всех агентов популяции. Константа "pi" содержит значение числа пи для тригонометрических вычислений. Переменная "V_ref" задаёт референсную скорость звука 340 м/с, относительно которой нормализуются вычисляемые скорости. Переменная "maxDiagonal" хранит длину диагонали пространства поиска и используется для нормализации расстояний между агентами.

Метод "SetParams" предназначен для применения параметров, заданных пользователем через массив "params". Метод извлекает значения из массива и присваивает их соответствующим переменным класса: "popSize" получает целочисленное значение первого элемента, "alpha0" - значение второго элемента, "gammaFirefly" — значение третьего элемента. Вызов этого метода необходим после изменения значений в массиве "params" для актуализации внутренних переменных алгоритма.

//————————————————————————————————————————————————————————————————————
class C_AO_CA_Cricket : public C_AO
{
  public: //----------------------------------------------------------
  ~C_AO_CA_Cricket () { }

  C_AO_CA_Cricket ()
  {
    ao_name = "CA_Cricket";
    ao_desc = "Cricket Algorithm";
    ao_link = "https://www.mql5.com/ru/articles/21058";

    popSize      = 50;
    alpha0       = 0.5;
    gammaFirefly = 1.0;

    ArrayResize (params, 3);
    params [0].name = "popSize";      params [0].val = popSize;
    params [1].name = "alpha0";       params [1].val = alpha0;
    params [2].name = "gammaFirefly"; params [2].val = gammaFirefly;
  }

  void SetParams ()
  {
    popSize      = (int)params [0].val;
    alpha0       = params [1].val;
    gammaFirefly = params [2].val;
  }

  bool Init (const double &rangeMinP  [],
             const double &rangeMaxP  [],
             const double &rangeStepP [],
             const int     epochsP);

  void Moving   ();
  void Revision ();

  //------------------------------------------------------------------
  double alpha0;
  double gammaFirefly;

  private://----------------------------------------------------------
  double alpha;
  int    currentEpoch;
  double humidity;
  double Q;

  S_CA_Velocity vel [];

  double pi;
  double V_ref;         // Референсная скорость звука (340 м/с)
  double maxDiagonal;   // Диагональ пространства поиска
};
//————————————————————————————————————————————————————————————————————

Метод "Init" выполняет полную инициализацию алгоритма перед началом оптимизации. Метод принимает четыре параметра: массивы "rangeMinP" и "rangeMaxP" определяют границы пространства поиска по каждой координате, массив "rangeStepP" задаёт шаг дискретизации для каждой координаты, параметр "epochsP" указывает максимальное число итераций.

В начале метода вызывается "StandardInit" базового класса, выполняющий стандартную инициализацию популяции и внутренних структур данных. После успешной стандартной инициализации устанавливаются начальные значения внутренних переменных. Текущий коэффициент шума "alpha" получает значение "alpha0". Счётчик итераций "currentEpoch" обнуляется. Константы среды инициализируются фиксированными значениями: влажность "humidity" - 50 %, коэффициент направленности Q - 2.0, число пи - 3.14, референсная скорость звука "V_ref" - 340 м/с.

Далее вычисляется диагональ пространства поиска "maxDiagonal". Для этого суммируются квадраты диапазонов по каждой координате, после чего извлекается квадратный корень из суммы. Если вычисленная диагональ оказывается меньше 10⁻¹⁰, она принудительно устанавливается равной единице для предотвращения деления на ноль при последующей нормализации расстояний.

Завершающим этапом инициализации является создание массива скоростей. Массив "vel" изменяет размер до "popSize" элементов. Для каждого агента создаётся вектор скорости размерностью "coords", все компоненты которого инициализируются нулями. Метод возвращает "true" при успешном завершении инициализации.

//————————————————————————————————————————————————————————————————————
bool C_AO_CA_Cricket::Init (const double &rangeMinP  [],
                            const double &rangeMaxP  [],
                            const double &rangeStepP [],
                            const int     epochsP)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //------------------------------------------------------------------
  alpha        = alpha0;
  currentEpoch = 0;

  humidity     = 50.0;
  Q            = 2.0;
  pi           = 3.14;
  V_ref        = 340.0;

  // Вычисляем диагональ пространства для нормализации
  maxDiagonal = 0.0;
  for (int c = 0; c < coords; c++)
  {
    double rangeC = rangeMax [c] - rangeMin [c];
    maxDiagonal += rangeC * rangeC;
  }
  maxDiagonal = sqrt (maxDiagonal);
  if (maxDiagonal < 1e-10) maxDiagonal = 1.0;

  ArrayResize (vel, popSize);
  for (int i = 0; i < popSize; i++)
  {
    ArrayResize (vel [i].v, coords);
    for (int c = 0; c < coords; c++)
    {
      vel [i].v [c] = 0.0;
    }
  }

  return true;
}
//————————————————————————————————————————————————————————————————————

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

При первом вызове метода, когда флаг "revision" имеет значение "false", выполняется начальная инициализация позиций агентов. Для каждого агента и каждой координаты генерируется случайное значение в пределах допустимого диапазона с помощью функции "RNDfromCI", после чего значение приводится к сетке дискретизации функцией "SeInDiSp". Компоненты скорости агента обнуляются. После инициализации всех агентов флаг "revision" устанавливается в "true", и метод завершает работу.

При последующих вызовах метода выполняется полный цикл обновления позиций. В начале инкрементируется счётчик итераций "currentEpoch" и пересчитывается коэффициент шума "alpha" по формуле экспоненциального затухания: "alpha" умножается на 0.95 в степени номера итерации. Если "alpha" становится меньше 0.01, значение фиксируется на этом минимальном уровне для сохранения минимальной стохастичности поиска.

Далее для каждого агента популяции выполняется последовательность вычислений согласно псевдокоду алгоритма. Генерируется случайное число стрекотаний "Ni" в диапазоне от 0 до 120. По закону Долбира вычисляется температура воздуха в градусах Цельсия. На основе температуры рассчитывается скорость звука "Vi".

Вычисляется расстояние "lambda_raw" от текущего агента до лучшего решения "cB" как евклидова норма разности координат. Расстояние нормализуется делением на диагональ пространства "maxDiagonal", результат ограничивается диапазоном от 0.001 до 1.0 для численной стабильности.

Скорость звука нормализуется делением на референсное значение "V_ref", давая "Vi_norm" около единицы. Максимальная частота "f_max" вычисляется как отношение "Vi_norm к lambda", ограничиваясь диапазоном от 0.01 до 10.0. Индивидуальная частота "fi" определяется как произведение "f_max" на случайное число "beta" из диапазона от 0 до 1.

Обновление скорости выполняется для каждой координаты агента. Вычисляется нормализованное направление к лучшему решению как разность координат, делённая на диапазон. Импульс "V_impulse" рассчитывается на основе отклонения "Vi_norm" от единицы с добавлением случайного множителя. Новая скорость складывается из предыдущей скорости, произведения направления на частоту и диапазон с коэффициентом 0.1, и импульса, умноженного на диапазон. Скорость ограничивается по модулю значением 0.3 от диапазона координаты. Позиция агента обновляется добавлением вектора скорости к текущим координатам.

Коэффициент поглощения "gammaAbsorption" вычисляется по упрощённой формуле: 0.1 плюс 0.4, умноженное на разность единицы и "lambda". Таким образом, агенты, находящиеся близко к лучшему решению, имеют больший коэффициент и чаще выполняют локальный поиск, тогда как удалённые агенты чаще участвуют в глобальном исследовании.

Генерируется случайное число, и если оно превышает "gammaAbsorption", выполняется фаза притяжения к более громким сверчкам. Для каждого другого агента "j" с лучшим значением целевой функции вычисляется нормализованное расстояние "r_ij". По формулам акустики рассчитываются мощность звука "Ps", уровень звукового давления "Lp", атмосферное поглощение "A_atm" и реальный уровень давления "R_Lp". Коэффициент притяжения "K_0" определяется через сигмоидную функцию от R_Lp, а итоговый коэффициент K_i учитывает экспоненциальное затухание с расстоянием. Позиция агента смещается в направлении агента "j" пропорционально K_i с добавлением случайного шума, масштабированного коэффициентом "alpha". Притяжение выполняется последовательно ко всем более громким агентам без прерывания цикла.

Если случайное число не превышает "gammaAbsorption", выполняется случайное блуждание вблизи лучшего решения. Новая позиция вычисляется как координаты лучшего решения "cB" плюс случайное отклонение, масштабированное произведением "alpha", коэффициента 0.2 и диапазона координаты. Скорость агента обнуляется. В завершение цикла по агентам координаты каждого агента приводятся к допустимому диапазону и сетке дискретизации функцией "SeInDiSp".

//————————————————————————————————————————————————————————————————————
void C_AO_CA_Cricket::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]);
        vel [i].v [c] = 0.0;
      }
    }
    revision = true;
    return;
  }

  //------------------------------------------------------------------
  currentEpoch++;

  alpha = alpha0 *pow (0.95, currentEpoch);
  if (alpha < 0.01) alpha = 0.01;

  //==================================================================
  for (int i = 0; i < popSize; i++)
  {
    //================================================================
    // N_i ∈ [0, 120]
    //================================================================
    double Ni = u.RNDfromCI (0.0, 120.0);

    //================================================================
    // eq. 3: T_C = 10 + (N - 40) / 7
    //================================================================
    double T_C = 10.0 + (Ni - 40.0) / 7.0;

    //================================================================
    // eq. 4: V = 20.1 * sqrt(273 + C)
    //================================================================
    double Vi = 20.1 * MathSqrt (273.0 + T_C);

    //================================================================
    // λ — НОРМАЛИЗОВАННОЕ расстояние до лучшего [0, 1]
    //================================================================
    double lambda_raw = 0.0;
    for (int c = 0; c < coords; c++)
    {
      double diff = a [i].c [c] - cB [c];
      lambda_raw += diff * diff;
    }
    lambda_raw = MathSqrt (lambda_raw);

    // Нормализация к [0, 1]
    double lambda = lambda_raw / maxDiagonal;
    if (lambda < 0.001) lambda = 0.001;
    if (lambda > 1.0) lambda = 1.0;

    //================================================================
    // eq. 5: f = V / λ
    // Нормализуем Vi относительно V_ref, получаем f ∈ [0, ~2]
    //================================================================
    double Vi_norm = Vi / V_ref;  // ≈ [0.98, 1.02]
    double f_max = Vi_norm / lambda;  // Теперь разумные значения

    // Ограничиваем f_max для стабильности
    if (f_max > 10.0) f_max = 10.0;
    if (f_max < 0.01) f_max = 0.01;

    //================================================================
    // eq. 11: f_i = f_min + (f_max - f_min) * β
    //================================================================
    double beta  = u.RNDprobab ();
    double f_min = 0.0;
    double fi    = f_min + (f_max - f_min) * beta;

    //================================================================
    // eq. 12: v_i = v_i + (x* - x_i) * f_i + V_i (нормализованное)
    //================================================================
    for (int c = 0; c < coords; c++)
    {
      double rangeC = rangeMax [c] - rangeMin [c];

      // Нормализованное направление
      double diff_to_best = (cB [c] - a [i].c [c]) / rangeC;

      // V_i как нормализованный импульс
      double V_impulse = (Vi_norm - 1.0) * 0.1 * u.RNDfromCI (-1.0, 1.0);

      // eq. 12: v = v + direction * f + V
      vel [i].v [c] = vel [i].v [c] + diff_to_best * fi * rangeC * 0.1 + V_impulse * rangeC;

      // Ограничение скорости
      double maxVel = rangeC * 0.3;
      vel [i].v [c] = MathMax (-maxVel, MathMin (maxVel, vel [i].v [c]));
    }

    //================================================================
    // eq. 13: x_i = x_i + v_i
    //================================================================
    for (int c = 0; c < coords; c++)
    {
      a [i].c [c] = a [i].c [c] + vel [i].v [c];
    }

    //================================================================
    // γ — нормализованный коэффициент поглощения
    // Используем упрощённую формулу для получения γ ∈ [0.1, 0.5]
    //================================================================
    // Чем ближе к лучшему (малое lambda) → больше γ → больше local search
    // Чем дальше (большое lambda) → меньше γ → больше global search
    double gammaAbsorption = 0.1 + 0.4 * (1.0 - lambda);

    //================================================================
    // if rand[0,1] > γ
    //================================================================
    double rnd = u.RNDprobab ();

    if (rnd > gammaAbsorption)
    {
      //--------------------------------------------------------------
      // FIREFLY ФАЗА: притяжение к более громким
      //--------------------------------------------------------------
      for (int j = 0; j < popSize; j++)
      {
        if (j != i && a [j].f > a [i].f)
        {
          //----------------------------------------------------------
          // r_ij — НОРМАЛИЗОВАННОЕ расстояние [0, 1]
          //----------------------------------------------------------
          double r_ij_raw = 0.0;
          for (int c = 0; c < coords; c++)
          {
            double diff = a [i].c [c] - a [j].c [c];
            r_ij_raw += diff * diff;
          }
          r_ij_raw = MathSqrt (r_ij_raw);

          double r_ij = r_ij_raw / maxDiagonal;
          if (r_ij < 0.001) r_ij = 0.001;

          //----------------------------------------------------------
          // eq. 7: Ps = I * 4πr² (нормализованное)
          //----------------------------------------------------------
          double I_j = 1.0;  // Нормализованная интенсивность
          double Ps  = I_j * 4.0 * pi * r_ij * r_ij;

          //----------------------------------------------------------
          // eq. 8: Lp = Lw + 10*log[Q / (4πr²)]
          //----------------------------------------------------------
          double Lw = 10.0 * MathLog10 (Ps + 1e-10);
          double Lp = Lw + 10.0 * MathLog10 (Q / (4.0 * pi * r_ij * r_ij + 1e-10));

          //----------------------------------------------------------
          // eq. 9: A_atm = 7.4 * (f²r / Ø) * 10⁻⁸
          // Для нормализованных значений масштабируем
          //----------------------------------------------------------
          double A_atm = 7.4 * (fi * fi * r_ij / humidity) * 0.01;

          //----------------------------------------------------------
          // eq. 10: R_Lp = Lp - A_atm
          //----------------------------------------------------------
          double R_Lp = Lp - A_atm;

          //----------------------------------------------------------
          // eq. 15, 16: K = K_0 * exp(-γ * r²)
          //----------------------------------------------------------
          double K_0 = 1.0 / (1.0 + MathExp (-R_Lp / 5.0));
          double K_i = K_0 * MathExp (-gammaFirefly * r_ij * r_ij);

          //----------------------------------------------------------
          // eq. 17: x_i = x_i + K * direction + α * ε
          //----------------------------------------------------------
          for (int c = 0; c < coords; c++)
          {
            double rangeC = rangeMax [c] - rangeMin [c];

            double direction  = a [j].c [c] - a [i].c [c];
            double attraction = K_i * direction;

            double epsilon = u.RNDfromCI (-0.5, 0.5);
            double noise   = alpha * rangeC * epsilon;

            a [i].c [c] = a [i].c [c] + attraction + noise;
          }
          // Нет break — притяжение ко всем более громким
        }
      }
    }
    else
    {
      //--------------------------------------------------------------
      // eq. 14: random walk
      // x_i = x_best + ε * scale
      //
      // Масштаб зависит от alpha (уменьшается со временем)
      //--------------------------------------------------------------
      for (int c = 0; c < coords; c++)
      {
        double rangeC = rangeMax [c] - rangeMin [c];
        double eps    = u.RNDfromCI (-1.0, 1.0);

        // Адаптивный масштаб: больше в начале, меньше в конце
        double scale = alpha * 0.2;  // 0.1 в начале, уменьшается

        a [i].c [c] = cB [c] + eps * scale * rangeC;

        vel [i].v [c] = 0.0;
      }
    }

    //================================================================
    // Ограничение координат и приведение к шагу
    //================================================================
    for (int c = 0; c < coords; c++)
    {
      a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//————————————————————————————————————————————————————————————————————

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

Метод начинается с инициализации переменных для поиска лучшего агента: "bestIdx" устанавливается в 0, "bestFit" получает значение целевой функции первого агента. Далее выполняется проход по всем агентам начиная со второго. Если значение целевой функции текущего агента превышает "bestFit", обновляются обе переменные: "bestFit" получает новое лучшее значение, "bestIdx" — индекс агента.

После определения лучшего агента в текущей популяции выполняется сравнение с глобальным лучшим решением "fB". Если найденное значение "bestFit" превосходит "fB", глобальное лучшее обновляется. Таким образом, метод "Revision" обеспечивает сохранение лучшего найденного решения на протяжении всего процесса оптимизации.

//————————————————————————————————————————————————————————————————————
void C_AO_CA_Cricket::Revision ()
{
  int    bestIdx = 0;
  double bestFit = a [0].f;

  for (int i = 1; i < popSize; i++)
  {
    if (a [i].f > bestFit)
    {
      bestFit = a [i].f;
      bestIdx = i;
    }
  }

  if (bestFit > fB)
  {
    fB = bestFit;
    ArrayCopy (cB, a [bestIdx].c, 0, 0, coords);
  }
}
//————————————————————————————————————————————————————————————————————


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

По результатам тестирования на стандартном наборе тестовых функций алгоритм продемонстрировал относительно скромную производительность, набрав около 34% от максимально возможного результата в рейтинговой таблице алгоритмов оптимизации. Данный показатель позиционирует алгоритм сверчков в нижней части списка рассмотренных метаэвристик, что указывает на необходимость дополнительной работы по его настройке и модификации.

CA_Cricket|Cricket Algorithm|50.0|1.0|1.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.5836480537501225
25 Hilly's; Func runs: 10000; result: 0.4394651273931123
500 Hilly's; Func runs: 10000; result: 0.3106533980628491
=============================
5 Forest's; Func runs: 10000; result: 0.5352980150573591
25 Forest's; Func runs: 10000; result: 0.3114351845482898
500 Forest's; Func runs: 10000; result: 0.18345680555353047
=============================
5 Megacity's; Func runs: 10000; result: 0.40307692307692317
25 Megacity's; Func runs: 10000; result: 0.19846153846153847
500 Megacity's; Func runs: 10000; result: 0.11247692307692414
=============================
All score: 3.07797 (34.20%)

Визуализация работы алгоритма на наших тестовых функциях и пример работы на стандартных тестовых функциях. 

Hilly

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

Forest

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

Megacity

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

Ackley

CA_Cricket на тестовой функции Rastrigin

Paraboloid

CA_Cricket на тестовой функции Paraboloid

По результатам тестирования, алгоритм CA-Cricket, представлен в рейтинговой таблице лучших популяционных методов оптимизации только ознакомительно.

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)
1DOAdingomdingo_optimization_algorithm_M0,479680,453670,463691,397040,941450,879090,914542,735080,786150,860610,848052,494816,62773,63
2ANSacross neighbourhood search0,949480,847760,438572,235811,000000,923340,399882,323230,709230,634770,230911,574916,13468,15
3CLAcode lock algorithm (joo)0,953450,871070,375902,200420,989420,917090,316422,222940,796920,693850,193031,683806,10767,86
4AMOmanimal migration ptimization M0,903580,843170,462842,209590,990010,924360,465982,380340,567690,591320,237731,396755,98766,52
5(P+O)ES(P+O) evolution strategies0,922560,881010,400212,203790,977500,874900,319452,171850,673850,629850,186341,490035,86665,17
6CTAcomet tail algorithm (joo)0,953460,863190,277702,094350,997940,857400,339492,194840,887690,564310,105121,557125,84664,96
7TETAtime evolution travel algorithm (joo)0,913620,823490,319902,057010,970960,895320,293242,159520,734620,685690,160211,580525,79764,41
8SDSmstochastic diffusion search M0,930660,854450,394762,179880,999830,892440,196192,088460,723330,611000,106701,441035,70963,44
9BOAmbilliards optimization algorithm M0,957570,825990,252352,035901,000000,900360,305022,205380,735380,525230,095631,356255,59862,19
10AAmarchery algorithm M0,917440,708760,421602,047800,925270,758020,353282,036570,673850,552000,237381,463235,54861,64
11ESGevolution of social groups (joo)0,999060,796540,350562,146161,000000,828630,131021,959650,823330,553000,047251,423585,52961,44
12SIAsimulated isotropic annealing (joo)0,957840,842640,414652,215130,982390,795860,205071,983320,686670,493000,090531,270205,46960,76
13EOmextremal_optimization_M0,761660,772420,317471,851550,999990,767510,235272,002770,747690,539690,142491,429875,28458,71
14BBObiogeography based optimization0,949120,694560,350311,993990,938200,673650,256821,868670,746150,482770,173691,402615,26558,50
15ACSartificial cooperative search0,755470,747440,304071,806981,000000,888610,224132,112740,690770,481850,133221,305835,22658,06
16DAdialectical algorithm0,861830,700330,337241,899400,981630,727720,287181,996530,703080,452920,163671,319675,21657,95
17BHAmblack hole algorithm M0,752360,766750,345831,864930,935930,801520,271772,009230,650770,516460,154721,321955,19657,73
18ASOanarchy society optimization0,848720,746460,314651,909830,961480,791500,238031,991010,570770,540620,166141,277525,17857,54
19RFOroyal flush optimization (joo)0,833610,737420,346291,917330,894240,738240,240981,873460,631540,502920,164211,298675,08956,55
20AOSmatomic orbital search M0,802320,704490,310211,817020,856600,694510,219961,771070,746150,528620,143581,418355,00655,63
21TSEAturtle shell evolution algorithm (joo)0,967980,644800,296721,909490,994490,619810,227081,841390,690770,426460,135981,253225,00455,60
22BSAbacktracking_search_algorithm0,973090,545340,290981,809410,999990,585430,217471,802890,847690,369530,129781,347004,95955,10
23DEdifferential evolution0,950440,616740,303081,870260,953170,788960,166521,908650,786670,360330,029531,176534,95555,06
24SRAsuccessful restaurateur algorithm (joo)0,968830,634550,292171,895550,946370,555060,191241,692670,749230,440310,125261,314804,90354,48
25BObonobo_optimizer0,775650,638050,329081,742780,880880,763440,255731,900050,610770,498460,142461,251694,89554,38
26CROchemical reaction optimisation0,946290,661120,298531,905930,879060,584220,211461,674730,758460,426460,126861,311784,89254,36
27BIOblood inheritance optimization (joo)0,815680,653360,308771,777810,899370,653190,217601,770160,678460,476310,139021,293784,84253,80
28DOAdream_optimization_algorithm0,855560,700850,372801,929210,734210,489050,241471,464730,772310,473540,185611,431464,82553,62
29BSAbird swarm algorithm0,893060,649000,262501,804550,924200,711210,249391,884790,693850,326150,100121,120124,80953,44
30DEAdolphin_echolocation_algorithm0,759950,675720,341711,777380,895820,642230,239411,777460,615380,440310,151151,206844,76252,91
31HSharmony search0,865090,687820,325271,878180,999990,680020,095901,775920,620000,422670,054581,097254,75152,79
32SSGsaplings sowing and growing0,778390,649250,395431,823080,859730,624670,174291,658690,646670,441330,105981,193984,67651,95
33BCOmbacterial chemotaxis optimization M0,759530,622680,314831,697040,893780,613390,225421,732590,653850,420920,144351,219124,64951,65
34ABOafrican buffalo optimization0,833370,622470,299641,755480,921700,586180,197231,705110,610000,431540,132251,173784,63451,49
35(PO)ES(PO) evolution strategies0,790250,626470,429351,846060,876160,609430,195911,681510,590000,379330,113221,082554,61051,22
36FBAfractal-based Algorithm0,790000,651340,289651,730990,871580,568230,188771,628580,610770,460620,123981,195374,55550,61
37TSmtabu search M0,877950,614310,291041,783300,928850,518440,190541,637830,610770,382150,121571,114494,53650,40
38BSObrain storm optimization0,937360,576160,296881,810410,931310,558660,235371,725340,552310,290770,119140,962224,49849,98
39WOAmwale optimization algorithm M0,845210,562980,262631,670810,931000,522780,163651,617430,663080,411380,113571,188034,47649,74
40AEFAartificial electric field algorithm0,877000,617530,252351,746880,927290,726980,180641,834900,666150,116310,095080,877544,45949,55
41AEOartificial ecosystem-based optimization algorithm0,913800,467130,264701,645630,902230,437050,214001,553270,661540,308000,285631,255174,45449,49
42CAmcamel algorithm M0,786840,560420,351331,698590,827720,560410,243361,631490,648460,330920,134181,113564,44449,37
43ACOmant colony optimization M0,881900,661270,303771,846930,858730,586800,150511,596040,596670,373330,024720,994724,43849,31
44CMAEScovariance_matrix_adaptation_evolution_strategy0,762580,720890,000001,483470,820560,796160,000001,616720,758460,490770,000001,249234,34948,33
45DA_duelistduelist_algorithm0,927820,537780,277921,743520,869570,475360,181931,526860,621530,335690,117151,074374,34548,28
CA_Cricketcricket_algorithm 0,583640,439460,310651,333750,535290,311430,183461,030180,403070,198460,112470,714003,07834,20
RWrandom walk0,487540,321590,257811,066940,375540,219440,158770,753750,279690,149170,098470,527342,34826,09


Выводы

Наблюдение за динамикой работы алгоритма позволяет отметить его своеобразный характер исследования пространства поиска. Сочетание bat-подобного механизма обновления скорости с firefly-подобным притяжением создаёт интересную картину движения популяции, где агенты одновременно стремятся к глобальному лучшему решению и притягиваются к локально лучшим соседям. Физические формулы распространения звука добавляют дополнительный уровень сложности взаимодействиям, хотя их влияние на итоговую производительность требует более детального исследования.

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

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

tab

Рисунок 2. Цветовая градация алгоритмов по соответствующим тестам

chart

Рисунок 3. Гистограмма результатов тестирования алгоритмов (по шкале от 0 до 100, чем больше, тем лучше, где 100 — максимально возможный теоретический результат, в архиве скрипт для расчета рейтинговой таблицы)

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

Плюсы:

  1. Лучше себя показывает на функциях средней и большой размерностей.

Минусы:

  1. Недостаточно хорошо справляется с функциями малой размерности.

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



Программы, используемые в статье

#ИмяТипОписание
1#C_AO.mqh
Включаемый файл
Родительский класс популяционных алгоритмов оптимизации
2#C_AO_enum.mqh
Включаемый файл
Перечисление популяционных алгоритмов оптимизации
3TestFunctions.mqh
Включаемый файл
Библиотека тестовых функций
4
TestStandFunctions.mqh
Включаемый файл
Библиотека функций тестового стенда
5
Utilities.mqh
Включаемый файл
Библиотека вспомогательных функций
6
CalculationTestResults.mqh
Включаемый файл
Скрипт для расчета результатов в сравнительную таблицу
7
Testing AOs.mq5
СкриптЕдиный испытательный стенд для всех популяционных алгоритмов оптимизации
8
Simple use of population optimization algorithms.mq5
Скрипт
Простой пример использования популяционных алгоритмов оптимизации без визуализации
9
Test_AO_CA_Cricket.mq5
СкриптИспытательный стенд для CA_Cricket
Прикрепленные файлы |
CA_Cricket.zip (403.12 KB)
Нейросети в трейдинге: Асинхронная обработка событий в потоковых моделях (Основные компоненты) Нейросети в трейдинге: Асинхронная обработка событий в потоковых моделях (Основные компоненты)
В статье рассматривается архитектура фреймворка EVA-Flow, ориентированного на обработку пространственно-временных данных и прогнозирование динамики потоков. Основное внимание уделено SMR-модулю, обеспечивающему устойчивое формирование скрытых состояний, и механизму адаптивной инициализации начального состояния через обучаемые кандидаты.
Нейросети в трейдинге: Асинхронная обработка событий в потоковых моделях (EVA-Flow) Нейросети в трейдинге: Асинхронная обработка событий в потоковых моделях (EVA-Flow)
В статье знакомимся с фреймворком EVA-Flow для низколатентной и высокочастотной оценки оптического потока на основе событийных данных. Модель сочетает адаптивное представление потока через Unified Voxel Grid с пространственно-временной рекуррентной архитектурой SMR, обеспечивая стабильное и точное прогнозирование движения в режиме реального времени.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Забытая классика объёма: индикатор "Finite Volume Elements" для современных рынков Забытая классика объёма: индикатор "Finite Volume Elements" для современных рынков
В статье рассмотрим индикатор Finite Volume Elements (FVE), позволяющий выявлять истинные потоки капитала на рынке. Реализуем FVE для MetaTrader 5 и рассмотрим рекомендации по его использованию в торговле.