Русский Português
preview
Algoritmo de búsqueda orbital atómica - Atomic Orbital Search (AOS)

Algoritmo de búsqueda orbital atómica - Atomic Orbital Search (AOS)

MetaTrader 5Ejemplos | 29 mayo 2025, 13:02
53 0
Andrey Dik
Andrey Dik

Contenido

  1. Introducción
  2. Implementación del algoritmo
  3. Resultados de las pruebas


Introducción

Los planteamientos modernos para resolver problemas complejos de optimización se inspiran cada vez más en los principios de la física, sobre todo en la mecánica cuántica. En este artículo, nos familiarizaremos con el algoritmo AOS (Atomic Orbital Search), basado en conceptos de modelos orbitales atómicos. El algoritmo fue propuesto por Mahdi Azizi en 2021, y supone un nuevo método metaheurístico. El modelo describe el comportamiento de los electrones no como trayectorias estrictamente definidas, sino como funciones de onda que crean nubes de probabilidad alrededor del núcleo atómico, tomando los avances científicos del eminente físico Erwin Schroeder. 

El orbital atómico, resultado de la descripción cuántica, es la región donde se maximiza la probabilidad de encontrar un electrón. En este modelo, los electrones se desplazan en capas imaginarias definidas por radios y números cuánticos que reflejan los niveles de energía. Las capas con valores más altos de n se corresponden con radios más grandes y, por tanto, con niveles de energía más altos. Este comportamiento de los electrones, sujeto a excitaciones por la interacción con otras partículas y la exposición a fotones, crea un entorno dinámico y variable en el que los electrones pueden emitir o absorber energía al moverse entre distintos orbitales.

El algoritmo AOS usa estos principios físicos para modelar el proceso de búsqueda de soluciones en problemas de optimización. El AOS tiene en cuenta las distribuciones de probabilidad y la dinámica de las interacciones, lo cual permite realizar una exploración eficaz del espacio de soluciones. En concreto, el algoritmo considera la actualización de las posiciones de las soluciones candidatas (electrones) según sus energías, lo que a su vez afecta a la probabilidad de encontrarse en determinadas capas. Esto permite al AOS no solo encontrar soluciones óptimas, sino también adaptarse a los cambios del entorno.

En este artículo, hablaremos con detalle del modelo matemático AOS, incluyendo los pasos para actualizar las posiciones de las soluciones candidatas y los mecanismos que rigen la absorción y liberación de energía. Así pues, el AOS no solo supone un enfoque interesante de la optimización, sino que también abre nuevos horizontes para la aplicación de los principios cuánticos a los problemas computacionales.


Implementación del algoritmo

El algoritmo AOS se basa en los principios del modelo orbital atómico, que tiene en cuenta la emisión y absorción de energía por los átomos, así como la configuración de la densidad de electrones. Al principio del algoritmo, se ofrecen varias soluciones candidatas, denotadas como X, que se tratan como electrones alrededor del núcleo del átomo. Estos candidatos forman una nube de electrones, mientras que el espacio de búsqueda se representa como un volumen esférico dividido en capas concéntricas. Las soluciones candidatas pueden escribirse de forma general como sigue:

X = [x1,  x2 ..., xj ..., xm], donde xi es el i-ésimo candidato a la decisión, y m es el número total de candidatos.

Las posiciones iniciales de las soluciones candidatas se inicializan aleatoriamente. Cada electrón posee un nivel de energía definido por una función objetivo que debe minimizarse. Así, los electrones con niveles de energía bajos se corresponden con los candidatos con mejores valores de la función objetivo, mientras que los electrones con niveles de energía altos se corresponden con los candidatos con peores valores. El vector de valores de la función objetivo se escribe como:

E = [E1, E2, ..., Ei, ..., Em], donde Ei es el nivel de energía del i-ésimo candidato.

Las capas imaginarias alrededor del núcleo se modelan usando un número entero aleatorio n, que puede ser desde 1 hasta el número de capas L. La capa con el radio más pequeño L0 representa el núcleo, mientras que las capas Li restantes representan la ubicación de los electrones (en el AOS la capa "núcleo" también puede contener electrones). La distribución de las soluciones candidatas entre capas se realiza mediante una función de densidad de probabilidad (PDF) que determina la probabilidad de encontrar el valor de una variable dentro de un rango determinado. El algoritmo usa una distribución lognormal para simular el comportamiento ondulatorio real de los electrones. Las soluciones candidatas se distribuyen en diferentes capas, donde el vector Xk que contiene los candidatos en n capas se escribe como:

Xk = [Xk1, Xk2, ..., Xki, ..., Xkp], donde k es el número de capa, y p es el número de candidatos en la capa.

Según el modelo orbital atómico, se supone que los electrones se encuentran en el estado fundamental del nivel de energía. El estado de enlace y la energía de enlace de cada capa se calculan como vemos abajo:

BS_k = (1/p) * Σ(Xki),

BE_k = (1/p) * Σ(Eki).

El nivel de energía total de un átomo se define así:

BS = (1/m) * Σ(Xi),

BE = (1/m) * Σ(Ei).

Los electrones pueden cambiar su ubicación y desplazarse entre capas bajo la influencia de los fotones y otras interacciones. La posición de las soluciones candidatas en el algoritmo AOS se actualiza según la probabilidad de interacción representada por un número ϕ generado aleatoriamente, que se distribuye en el intervalo [0,1]. Si ϕ ≥ PR (parámetro de velocidad del fotón), entonces es posible la emisión o absorción de energía.

Si Eki ≥ BEk, entonces tiene lugar la emisión de energía: Xki[t+1] = Xkit + αi × (βi × LE − γi × BS) / k.

Si Eki < BEk, entonces se da la absorción de energía: Xki[t+1] = Xkit + αi × (βi × LEk − γi × BSk).

Si ϕ < PR, entonces se consideran los desplazamientos hacia campos magnéticos o las interacciones con otras partículas: Xki[t+1] = Xkit + ri, donde ri supone un incremento aleatorio en el rango de min a max del correspondiente parámetro optimizado del problema.

Por decirlo de forma sencilla, en el AOS, la población de soluciones candidatas puede representarse figurativamente como una molécula en la que los átomos se corresponden con coordenadas en el espacio de búsqueda, mientras que los electrones de estos átomos se corresponden con soluciones específicas. Así, si la población consta de 50 soluciones candidatas, cada átomo tendrá 50 electrones distribuidos en capas, según una distribución lognormal.

En la descripción del algoritmo, el autor no especifica cómo se determina el diámetro de la capa exterior del átomo, lo cual implica que el núcleo del átomo estará situado en el centro con respecto a las capas. Y esto significa que el átomo, junto con las capas, se moverá dentro de los límites dados del problema. Para ofrecer más flexibilidad al algoritmo, nos basaremos en la condición de que el diámetro de la capa exterior se corresponderá con el rango [min; max] para la coordenada correspondiente en el espacio de búsqueda, mientras que el centro del núcleo del átomo se situará en el punto de la mejor solución global en la coordenada dada. De manera visual, el modelo de un átomo en el AOS puede visualizarse en la figura 1.

AOS

Figura 1. Modelo de un átomo en el algoritmo AOS, donde los puntos denotan electrones, mientras que la línea discontinua indica la distribución lognormal de electrones

Pseudocódigo del algoritmo de búsqueda orbital atómica (AOS):

1. Inicialización

1.1 Posiciones iniciales (Xi)

Se crea una población de m soluciones candidatas
A cada candidato se le asigna una posición aleatoria en el espacio de búsqueda

1.2 Cálculo de la aptitud inicial (Ei)

Para cada candidato se calcula el valor de la función objetivo
Este valor representa la energía de la partícula
Cuanto menor sea la energía, mejor resultará la solución

1.3 Determinación de los parámetros de los átomos

BS (Binding State) estado de enlace de un átomo; representa la posición media actual de todas las partículas
BE (Binding Energy) energía de enlace; representa la energía media de todas las partículas
LE (Lowest Energy) partícula de menor energía (mejor solución)

2. Creación de una estructura de capas

2.1 Generación de un número aleatorio de capas [1; n] para cada átomo

Determinación del número de orbitales imaginarios
Cada orbital representa un nivel de búsqueda con una intensidad distinta

2.2 Distribución de partículas

Las partículas se distribuyen en capas según la función de densidad de probabilidad (PDF)
Las capas internas suelen contener las mejores soluciones
Las capas exteriores se usan para explorar el espacio

2.3 Proceso de búsqueda para cada capa (k)

3.1 Parámetros de las capas

Estado de enlace BSk para una capa específica
BEk energía de enlace de la capa
LEk partícula con la energía más baja de la capa

3.2 Actualización de las posiciones de las partículas

Para cada partícula i en la capa k:

3.3 Generación de parámetros de control:

   φ: determina el tipo de movimiento
   α: factor de escalado
   β: coeficiente de atracción hacia la mejor solución
   γ: coeficiente de repulsión respecto al estado medio
   PR: probabilidad de desplazamiento del fotón

3.4 Selección del tipo de movimiento:

   si φ ≥ PR:
       si Eki ≥ BEk:
           // Investigación global
           Xi[t+1] = Xit + αi × (βi × LE - γi × BS) / k
       de lo contrario:
           // Investigación local.
           Xi[t+1] = Xit + αi × (βi × LEk - γi × BSk)
   de lo contrario:
       // Paseo aleatorio
       Xki[t+1] = Xkit + ri

4. Cálculo de la aptitud (Ei)  

5. Actualización de los parámetros globales

6. Repetimos desde 1.3 hasta que se cumpla el criterio de parada

Para calcular la probabilidad de la distribución de electrones alrededor del núcleo (la mejor solución), podemos usar la generación de números para diferentes distribuciones. El autor prefiere la distribución lognormal, que requiere su implementación en código. Ahora escribiremos el código del generador. Para el algoritmo, necesitaremos crear no solo una distribución lognormal, sino una distribución asimétricamente desplazada con respecto al centro (kernel), como se muestra en la figura 1. Implementaremos la función "LognormalDistribution" en la colección de bibliotecas de funciones para algoritmos de optimización, que genera un número aleatorio distribuido según la ley lognormal en los límites dados con un desplazamiento.

La función aceptará los siguientes parámetros:

1. center- valor central de la distribución.
2. min_value - valor mínimo que se puede generar.
3. max_value - valor máximo que se puede generar.
4. peakDisplCoeff - coeficiente de desplazamiento máximo relativo al centro de distribución (por defecto es igual a 0,2).

Descripción funcional:

1. Comprobación de límites:
    Si "min_value" es mayor o igual a "max_value", la función retornará "max_value".
    Si "max_value" es menor o igual a "min_value", la función retornará "min_value".

2. Se genera un número "random" en el rango de 0 a 1.

3. Corrección del centro:
    Si "center" es menor que "min_value", se fijará en "min_value" y "random" se fijará en 1.
    Si "center" es mayor que "max_value", se fijará en "max_value" y "random" se fijará en 0.

4. Se calculan los valores "peak_left" y "peak_right", que determinarán la posición de los picos de distribución.

5. Generación de valor:
    Si "random" es inferior a 0,5, se realizará el cálculo para la parte izquierda de la distribución:
        Se calculan los parámetros "mu_left" y "sigma_left".
        Se generan números aleatorios "u1" y "u2" para el método Box-Muller.
        Se aplica el método de Box-Muller para obtener un valor "z" con distribución normal.
        Se calcula el resultado de la parte izquierda.
    Si "random" es mayor o igual que 0,5, se realizará el mismo proceso para el lado derecho de la distribución, utilizando los parámetros "mu_right" y "sigma_right".

6. Si el valor "result" se sale de los límites "min_value" y "max_value", se llamará a la función "RNDfromCI" para "lanzar" el valor al rango aceptable, evitando así la acumulación de probabilidades en los límites de los números aleatorios generados.

//------------------------------------------------------------------------------
//The lognormal distribution of the species:  min|------P---C---P------|max
double C_AO_Utilities :: LognormalDistribution (double center, double min_value, double max_value, double peakDisplCoeff = 0.2)
{
  // Проверка правой границы
  if (min_value >= max_value)
  {
    return max_value;
  }

  // Проверка левой границы
  if (max_value <= min_value)
  {
    return min_value;
  }

  // Генерация случайного числа от 0 до 1
  double random = MathRand () / 32767.0;

  // Коррекция центра, если он выходит за границы
  if (center < min_value)
  {
    center = min_value;
    random = 1;
  }

  if (center > max_value)
  {
    center = max_value;
    random = 0;
  }

  // Расчет положения пиков
  double peak_left  = center - (center - min_value) * peakDisplCoeff;
  double peak_right = center + (max_value - center) * peakDisplCoeff;

  double result = 0.0;

  if (random < 0.5) // Левая часть распределения
  {
    // Расчет параметров для левой части
    double diff_center_peak = MathMax (center - peak_left, DBL_EPSILON);
    double diff_center_min  = MathMax (center - min_value, DBL_EPSILON);

    double mu_left = MathLog (diff_center_peak);
    double sigma_left = MathSqrt (2.0 * MathLog (MathMax (diff_center_min / diff_center_peak, DBL_EPSILON)) / 9.0);

    // Генерация случайных чисел для метода Бокса-Мюллера
    double u1 = MathRand () / 32767.0;
    double u2 = MathRand () / 32767.0;

    // Защита от нулевых значений
    u1 = MathMax (u1, DBL_EPSILON);

    // Применение метода Бокса-Мюллера
    double z = MathSqrt (-2.0 * MathLog (u1)) * MathCos (2.0 * M_PI * u2);

    // Расчет результата для левой части
    result = center - MathExp (mu_left + sigma_left * z);
  }
  else // Правая часть распределения
  {
    // Расчет параметров для правой части
    double diff_peak_center = MathMax (peak_right - center, DBL_EPSILON);
    double diff_max_center  = MathMax (max_value - center,  DBL_EPSILON);

    double mu_right    = MathLog  (diff_peak_center);
    double sigma_right = MathSqrt (2.0 * MathLog (MathMax (diff_max_center / diff_peak_center, DBL_EPSILON)) / 9.0);

    // Генерация случайных чисел для метода Бокса-Мюллера
    double u1 = MathRand () / 32767.0;
    double u2 = MathRand () / 32767.0;

    // Защита от нулевых значений
    u1 = MathMax (u1, DBL_EPSILON);

    // Применение метода Бокса-Мюллера
    double z = MathSqrt (-2.0 * MathLog (u1)) * MathCos (2.0 * M_PI * u2);

    // Расчет результата для правой части
    result = center + MathExp (mu_right + sigma_right * z);
  }

  // Проверка и коррекция результата, если он выходит за границы
  if (result < min_value || result > max_value) return RNDfromCI (min_value, max_value);

  return result;
}

Vamos a escribir un script para comprobar visualmente la distribución resultante. Esto es lo que hará el script de prueba (no daremos el resto del código, la clase de trabajo con el lienzo para el banco de pruebas se puede encontrar en el archivo del artículo):

1. Se crea un objeto "Canvas" para dibujar gráficos.
2. Se inicializan los parámetros del lienzo: anchura "W", altura "H" y separaciones "O".
3. Se crean los arrays "CountL" y "CountR" para calcular los valores a la izquierda y a la derecha del parámetro de entrada "Inp_P", inicializados con ceros.
4. Se crea un elemento gráfico (lienzo) con las dimensiones y el color de fondo especificados.

La distribución lognormal describe las variables aleatorias cuyo logaritmo tiene una distribución normal. En el código, se usa para generar los valores visualizados en el gráfico.

5. El ciclo "for" genera "N" valores utilizando la función "U.LognormalDistribution()". Cada valor se compara con "Inp_P": si es menor, se incrementará el contador "CountL[i]", si es mayor, se incrementará "CountR[i]".
6. Se inicializan los arrays "CountL" y "CountR" con ceros antes de la generación.
7. Los valores mínimo y máximo de los arrays se calculan para determinar el rango de los gráficos.
8. Se calculan las coordenadas para dibujar los gráficos, incluido el centro del lienzo y los pasos para las partes izquierda y derecha.
9. Se dibujan puntos en el lienzo que representan el número de valores en los rangos, con el color definido por la frecuencia del ocurrencia.
10. El lienzo se actualiza para mostrar los cambios.

// Функция, вызываемая при старте
void OnStart ()
{
    CCanvas Canvas; // Объект для работы с графикой (канвас)

    // Параметры канваса
    int W = 750; // Ширина канваса
    int H = 400; // Высота канваса
    int O = 10;  // Отступы от границ канваса

    // Массивы для хранения подсчета значений
    int CountL []; // Подсчет значений слева от входного параметра
    int CountR []; // Подсчет значений справа от входного параметра

    // Инициализация массивов
    ArrayResize (CountL, Size_P);  // Изменяем размер массива CountL
    ArrayInitialize (CountL, 0);   // Инициализируем массив CountL нулями

    ArrayResize (CountR, Size_P);  // Изменяем размер массива CountR
    ArrayInitialize (CountR, 0);   // Инициализируем массив CountR нулями

    // Создание канваса
    string canvasName = "Test_Probability_Distribution_Canvas"; // Имя канваса
    if (!Canvas.CreateBitmapLabel(canvasName, 5, 30, W, H, COLOR_FORMAT_ARGB_RAW))
    {
        Print ("Error creating Canvas: ", GetLastError()); // Вывод ошибки, если создание не удалось
        return;
    }

    // Настройка свойств канваса
    ObjectSetInteger (0, canvasName, OBJPROP_HIDDEN, false);    // Сделать канвас видимым
    ObjectSetInteger (0, canvasName, OBJPROP_SELECTABLE, true); // Сделать канвас выбираемым

    // Очистка канваса и рисование границы
    Canvas.Erase (COLOR2RGB(clrWhite));                         // Заполнение белым цветом
    Canvas.Rectangle (1, 1, W - 1, H - 1, COLOR2RGB(clrBlack)); // Рисование черной рамки

    int    ind = 0;   // Индекс для подсчета
    double X   = 0.0; // Переменная для хранения значений

    // Основной цикл для генерации значений
    for (int i = 0; i < CNT_P; i++)
    {
        // Генерация логнормального распределения
        X = U.LognormalDistribution (Inp_P, Min_P, Max_P, PeakDisplCoeff_P);

        // Определение, в какую сторону от входного параметра попадает значение
        if (X < Inp_P)
        {
            // Считаем индекс для левой части
            ind = (int) U.Scale(X, Min_P, Inp_P, 0, Size_P, true);
            if (ind >= Size_P) ind = Size_P - 1; // Ограничиваем индекс
            if (ind < 0) ind = 0;                // Ограничиваем индекс
            CountL [ind] += 1;                   // Увеличиваем счетчик для левой части
        }
        else
        {
            // Считаем индекс для правой части
            ind = (int) U.Scale (X, Inp_P, Max_P, 0, Size_P, false);
            if (ind >= Size_P) ind = Size_P - 1; // Ограничиваем индекс
            if (ind < 0) ind = 0;                // Ограничиваем индекс
            CountR [ind] += 1;                   // Увеличиваем счетчик для правой части
        }
    }

    // Определение минимальных и максимальных значений для графика
    int minCNT = CNT_P; // Начальное значение для минимального счетчика
    int maxCNT = 0;     // Начальное значение для максимального счетчика

    // Поиск минимальных и максимальных значений в счетчиках
    for (int i = 0; i < Size_P; i++)
    {
        if (CountL [i] > maxCNT) maxCNT = CountL [i]; // Обновление максимального значения для левой части
        if (CountR [i] > maxCNT) maxCNT = CountR [i]; // Обновление максимального значения для правой части

        if (CountL [i] < minCNT) minCNT = CountL [i]; // Обновление минимального значения для левой части
        if (CountR [i] < minCNT) minCNT = CountR [i]; // Обновление минимального значения для правой части
    }

    // Переменные для рисования графиков
    int   x      = 0.0; // Координата X для рисования
    int   y      = 0.0; // Координата Y для рисования
    color clrF;         // Цвет для рисования
    int   centre = 0;   // Центр канваса
    int   stepL  = 0;   // Шаг для левой части
    int   stH_L  = 0;   // Высота для левой части
    int   stepR  = 0;   // Шаг для правой части
    int   stH_R  = 0;   // Высота для правой части

    // Определение центра канваса
    centre = (int) U.Scale(Inp_P, Min_P, Max_P, O, W - O - 1, false);

    // Вычисление шагов и высот для левой части
    stepL = (centre - O) / Size_P;
    stH_L = stepL / 2;
    if (stH_L == 0) stH_L = 1; // Убедимся, что высота не 0

    // Вычисление шагов и высот для правой части
    stepR = (W - O - centre) / Size_P;
    stH_R = stepR / 2;
    if (stH_R == 0) stH_R = 1; // Убедимся, что высота не 0

    // Рисование графиков для левой и правой частей
    for (int i = 0; i < Size_P; i++)
    {
        // Рисование для левой части
        x = (int) U.Scale (i, 0, Size_P - 1, O, centre - stH_L, true); // Вычисление координаты X
        y = (int) U.Scale (CountL [i], 0, maxCNT, O, H - O - 1, true); // Вычисление координаты Y

        clrF = DoubleToColor(CountL [i], minCNT, maxCNT, 0, 255); // Определение цвета по значению

        // Рисование точек для левой части
        Canvas.Circle (x, y, 2, COLOR2RGB (clrF)); // Рисуем маленький круг
        Canvas.Circle (x, y, 3, COLOR2RGB (clrF)); // Рисуем круг большего размера

        // Рисование для правой части
        x = (int) U.Scale (i, 0, Size_P - 1, centre + stH_R, W - O - 1, false); // Вычисление координаты X
        y = (int) U.Scale (CountR[i], 0, maxCNT, O, H - O - 1, true);           // Вычисление координаты Y

        clrF = DoubleToColor (CountR [i], minCNT, maxCNT, 0, 255); // Определение цвета по значению

        // Рисование точек для правой части
        Canvas.Circle (x, y, 2, COLOR2RGB (clrF)); // Рисуем маленький круг
        Canvas.Circle (x, y, 3, COLOR2RGB (clrF)); // Рисуем круг большего размера
    }

    Canvas.Update (); // Обновление канваса для отображения изменений}

Ejecutamos el script y obtenemos una imagen en el gráfico como en la figura 2.

LogNormDistr

Figura 2. Visualización de la construcción de una distribución lognormal asimétrica usando la biblioteca estándar Canvas

Tras detallar la teoría de todos los pasos del algoritmo, pasaremos directamente a la implementación del código, al tiempo que en el AOS (como método de minimización para el problema), corregiremos su lógica para que funcione para la maximización. Ahora escribiremos una estructura "S_Layer", que modelará una capa de un átomo y contendrá información sobre el número de partículas de esa capa. Incluirá tanto las características numéricas como un método de inicialización. Campos de la estructura:

  • pc - contador de partículas en una capa determinada del átomo, que permitirá llevar la cuenta de cuántas partículas (electrones) hay en una capa concreta. 
  • BSk - estado de enlace en la capa; refleja el nivel de interacción entre las partículas de la capa. 
  • BEk - energía de enlace en la capa; muestra la fuerza con la que las partículas de la capa están unidas entre sí.
  • LEk - energía mínima en una capa; se utiliza para determinar el nivel de energía más bajo que pueden alcanzar las partículas en esa capa concreta. 

El método "Init" está diseñado para inicializar los campos de la estructura con valores por defecto y permite restablecer fácilmente el estado de la capa varias veces si es necesario.

//——————————————————————————————————————————————————————————————————————————————
struct S_Layer
{
    int    pc;  // счетчик частиц
    double BSk; // состояние связи
    double BEk; // энергия связи
    double LEk; // минимальная энергия

    void Init ()
    {
      pc  = 0;
      BSk = 0.0;
      BEk = 0.0;
      LEk = 0.0;
    }
};
//——————————————————————————————————————————————————————————————————————————————

A continuación, analizaremos la estructura "S_Atom" y su método "Init". "S_Atom" es una estructura que supone un átomo compuesto de múltiples capas. Cada capa se modela utilizando el array "layers []" de la estructura "S_Layer", descrita anteriormente. Campos de la estructura:

  • Init - método para inicializar un array de capas de átomos e inicializar cada capa en ese array.
  • layersNumb - este parámetro entero indica el número de capas que se crearán para este átomo.

//——————————————————————————————————————————————————————————————————————————————
struct S_Atom
{
    S_Layer layers [];  // массив слоев атома

    void Init (int layersNumb)
    {
      ArrayResize (layers, layersNumb);
      for (int i = 0; i < layersNumb; i++) layers [i].Init ();
    }
};
//——————————————————————————————————————————————————————————————————————————————

A continuación, vendrá la siguiente estructura "S_Electron" y su método "Init". La estructura representa un electrón miembro de la población de la solución que contiene información sobre su posición en la capa correspondiente del átomo. Los campos "layerID []" suponen un array de números enteros que almacena los identificadores de las capas a las que pertenece el electrón. Cada identificador se corresponderá con una capa específica del átomo, lo cual nos permitirá saber en qué nivel se encuentra un electrón.

//——————————————————————————————————————————————————————————————————————————————
struct S_Electron
{
    int layerID [];  // массив идентификаторов слоев для электрона

    void Init (int coords)
    {
      ArrayResize (layerID, coords);
    }
};
//——————————————————————————————————————————————————————————————————————————————

La clase de algoritmo AOS "C_AO_AOS" hereda de la clase básica "C_AO" e implica funcionalidad común relacionada con las órbitas atómicas.

Parámetros de la clase:

  • popSize - tamaño de la población en el algoritmo.
  • maxLayers - número máximo de capas que se pueden utilizar en el modelo atómico.
  • photonEmissions - número de emisiones de fotones que se utilizarán en el proceso de optimización.
  • PR - coeficiente de transición fotónica, determina la probabilidad de transición entre estados.
  • peakPosition - posición del pico en la distribución lognormal.

Métodos de clase:

1. SetParams () - establece los parámetros del algoritmo leyendo los valores del array "params".
2. Init () - inicializa el algoritmo con los parámetros de búsqueda especificados: rangos mínimo y máximo, paso de búsqueda y número de épocas.
3. Moving () - método para mover partículas en el espacio de búsqueda.
4. Revision () - método se encarga de revisar las mejores soluciones encontradas durante el proceso de optimización.

Campos privados de la clase:

  • atomStage - la etapa actual del átomo define en qué etapa se encuentran los procesos del átomo.
  • currentLayers [] - el array almacena información sobre el número actual de capas para cada átomo (en cada época el número de capas en cada átomo será un número aleatorio en el rango [1; maxLayers].
  • S_Atom atoms [] - array de átomos cuyo tamaño corresponde al número de coordenadas utilizadas en el algoritmo.
  • S_Electron electrons [] - array de electrones correspondiente al tamaño de la población.
  • BS [] - el array almacena los estados de enlace entre electrones a través de la población.

Métodos privados de clase:

1. GetOrbitBandID () - obtiene el ID de banda orbital para parámetros establecidos como el número de capas y rangos.
2. DistributeParticles() - método para distribuir partículas en el espacio de búsqueda.
3. LayersGenerationInAtoms () - genera el número de capas en los átomos.
4. UpdateElectronsIDs () - actualiza los identificadores de capa de los electrones.
5. CalcLayerParams () - calcula los parámetros de la capa e incluye la definición de niveles de energía y enlaces.
6. ActualizarElectrones () - actualiza la posición de los electrones.

//——————————————————————————————————————————————————————————————————————————————
// Класс реализующий алгоритм атомарной оптимизации (Atomic Orbital Search)
class C_AO_AOS : public C_AO
{
  public: //--------------------------------------------------------------------
  ~C_AO_AOS () { }
  C_AO_AOS ()
  {
    ao_name = "AOS";
    ao_desc = "Atomic Orbital Search";
    ao_link = "https://www.mql5.com/es/articles/16276";

    popSize         = 50;      // размер популяции

    maxLayers       = 5;       // максимальное количество слоев
    photonEmissions = 1;       // количество излучений фотонов
    PR              = 0.1;     // коэффициент перехода фотонов
    peakPosition    = 0.05;    // позиция пика в логнормальном распределении

    ArrayResize (params, 5);

    params [0].name = "popSize";         params [0].val = popSize;
    params [1].name = "maxLayers";       params [1].val = maxLayers;
    params [2].name = "photonEmissions"; params [2].val = photonEmissions;
    params [3].name = "photonRate";      params [3].val = PR;
    params [4].name = "peakPsition";     params [4].val = peakPosition;
  }

  // Установка параметров алгоритма
  void SetParams ()
  {
    popSize         = (int)params [0].val;
    maxLayers       = (int)params [1].val;
    photonEmissions = (int)params [2].val;
    PR              = params      [3].val;
    peakPosition    = params      [4].val;
  }

  // Инициализация алгоритма с заданными параметрами поиска
  bool Init (const double &rangeMinP  [], // минимальный диапазон поиска
             const double &rangeMaxP  [], // максимальный диапазон поиска
             const double &rangeStepP [], // шаг поиска
             const int     epochsP = 0);  // количество эпох

  void Moving   (); // Метод перемещения частиц
  void Revision (); // Метод пересмотра лучших решений

  //----------------------------------------------------------------------------
  int    maxLayers;       // максимальное количество слоев
  int    photonEmissions; // количество излучений фотонов
  double PR;              // коэффициент перехода фотонов
  double peakPosition;    // позиция пика в логнормальном распределении

  private: //-------------------------------------------------------------------
  int        atomStage;        // текущая стадия атома
  int        currentLayers []; // текущее количество слоев для соответствующего атома (координаты)
  S_Atom     atoms         []; // атомы, размер соответствует количеству координат
  S_Electron electrons     []; // электроны, соответствует размеру популяции
  double     BS            []; // состояния связей

  // Получение орбитальной полосы для заданных параметров
  int  GetOrbitBandID          (int layersNumb, double min, double max, double center, double p);

  // Распределение частиц в пространстве поиска
  void DistributeParticles     ();

  // Генерация слоев в атомах
  void LayersGenerationInAtoms ();

  // Обновление идентификаторов электронов
  void UpdateElectronsIDs      ();

  // Расчет параметров слоев
  void CalcLayerParams         ();

  // Обновление положения электронов
  void UpdateElectrons         ();
};
//——————————————————————————————————————————————————————————————————————————————

Veamos qué ocurre en el método "Init" de la clase de algoritmo AOS.

1. Inicialización estándar: el método comienza con una llamada a "StandardInit" y ejecuta los pasos comunes de inicialización como el establecimiento de rangos para las coordenadas. 

2. Inicialización de variables:

  • atomStage - se establece en "0", lo cual significa que el algoritmo comienza desde la etapa inicial.
  • ArrayResize (currentLayers, coords) - redimensiona el array "currentLayers" según el número de coordenadas "coords".
  • ArrayResize (atoms, coords) - redimensiona el array "atoms", creando un objeto distinto para cada átomo (coordenadas). Para cada átomo, se llama al método "Init (maxLayers)" para inicializarlo con el número máximo de capas.
  • ArrayResize (electrons, popSize) - redimensiona el array "electrons" según el tamaño de la población "popSize". Para cada electrón, se crea un array "layerID" que corresponde al número de coordenadas.
  • ArrayResize (BS, coords) - redimensiona el array "BS", que almacena los estados de cada coordenada.

4. Si todas las operaciones de inicialización se han efectuado correctamente, el método retornará "true".

//——————————————————————————————————————————————————————————————————————————————
// Инициализация алгоритма
bool C_AO_AOS::Init (const double &rangeMinP [],
                     const double &rangeMaxP [],
                     const double &rangeStepP [],
                     const int epochsP = 0)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //----------------------------------------------------------------------------
  atomStage = 0;

  ArrayResize (currentLayers, coords);

  ArrayResize (atoms, coords);
  for (int i = 0; i < coords; i++) atoms [i].Init (maxLayers);

  ArrayResize (electrons,   popSize);
  for (int i = 0; i < popSize; i++) ArrayResize (electrons [i].layerID, coords);

  ArrayResize (BS, coords);

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

Método para mover las partículas. Vamos a describir el métodoMoving:

1. Posicionamiento aleatorio inicial:

  • Si la variable "revision" es "false", significará que el algoritmo aún no ha comenzado su trabajo. En este caso, se producirá un posicionamiento aleatorio de las partículas.
  •  A continuación, el ciclo "for" anidado recorrerá todos los electrones (tamaño de la población) y para cada coordenada generará un valor aleatorio utilizando el método "u.RNDfromCI", que tomará un valor del rango dado por "rangeMin" y "rangeMax". A continuación, este valor se ajustará mediante el método "u.SeInDiSp", que fijará el valor según el paso especificado.

2. Ejecución de la etapa adecuada en la evolución de los átomos:

  • Si "revision" es "true", significará que el algoritmo ya se ha inicializado y se pueden ejecutar los pasos básicos. Dependiendo de la etapa actual de "atomStage", se llamarán diferentes métodos:
  • Si "atomStage" es "0", se llamará "DistributeParticles ()", que se encargará de distribuir las partículas en el espacio según una distribución lognormal asimétrica.
  • En caso contrario, se llamarán los métodos que generan capas en los átomos, se actualizarán los identificadores de electrones, se calcularán los parámetros de las capas y se actualizarán las posiciones de los electrones.

3. Una vez realizadas todas las operaciones necesarias, "atomStage" se incrementará en "1". Si "atomStage" supera el valor de "photonEmissions", se restablecerá a "0", permitiendo que los pasos del algoritmo sean cíclicos.

//——————————————————————————————————————————————————————————————————————————————
// Метод перемещения частиц
void C_AO_AOS::Moving ()
{
  // Начальное случайное позиционирование
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
        a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }

    revision = true;
    return;
  }

  //----------------------------------------------------------------------------
  // Выполнение соответствующего этапа алгоритма
  if (atomStage == 0)
  {
    DistributeParticles ();
  }
  else
  {
    LayersGenerationInAtoms ();
    UpdateElectronsIDs      ();
    CalcLayerParams         ();
    UpdateElectrons         ();
  }

  // Переход к следующей стадии
  atomStage++;
  if (atomStage > photonEmissions) atomStage = 0;
}
//——————————————————————————————————————————————————————————————————————————————

Vamos a desglosar los métodos específicos. El método "GetOrbitBandID" de la clase "C_AO_AOS" está diseñado para determinar la banda orbital para una partícula basándose en su posición relativa a un centro dado. Toma el número de capas, los valores mínimo y máximo, el centro y la posición de la partícula "p".

1. Calcula la anchura de las bandas a la izquierda y la derecha del centro.
2. Si la posición de la partícula "p" es inferior al centro, buscará en cuál de las bandas de la izquierda se encuentra.
3. Si es más grande, buscará en las bandas correctas.
4. Si es igual al centro, devolverá el número 0 (centro).

Así, la función devuelve el índice de la banda orbital correspondiente para una posición dada.

//——————————————————————————————————————————————————————————————————————————————
// Определение орбитальной полосы для частицы
int C_AO_AOS::GetOrbitBandID (int layersNumb, double min, double max, double center, double p)
{
  // Расчет ширины полос слева и справа от центра
  double leftWidth  = (center - min) / layersNumb;
  double rightWidth = (max - center) / layersNumb;

  // Определение номера полосы
  if (p < center)
  {
    // Объект находится слева от центра
    for (int i = 1; i <= layersNumb; i++)
    {
      if (p >= center - i * leftWidth) return i - 1;
    }
    return layersNumb - 1; // Если объект находится в крайней левой полосе
  }
  else
    if (p > center)
    {
      // Объект находится справа от центра
      for (int i = 1; i <= layersNumb; i++)
      {
        if (p <= center + i * rightWidth) return i - 1;
      }
      return layersNumb - 1; // Если объект находится в крайней правой полосе
    }
    else
    {
      // Объект находится в центре
      return 0;
    }
}
//——————————————————————————————————————————————————————————————————————————————

El método "DistributeParticles" de la clase "C_AO_AOS" se encarga de distribuir las partículas en el espacio de búsqueda. El método distribuye las partículas en el espacio de búsqueda usando una distribución lognormal.

Para cada partícula (en un ciclo por "popSize") y para cada coordenada (en un ciclo por "coords"):

  • Genera la posición de la partícula mediante una distribución lognormal usando los parámetros dados ("cB", "rangeMin", "rangeMax", "peakPosition").
  • Aplica la función "SeInDiSp" para ajustar el valor de la posición de la partícula dentro del rango especificado, teniendo en cuenta el paso.
//——————————————————————————————————————————————————————————————————————————————
// Распределение частиц в пространстве поиска
void C_AO_AOS::DistributeParticles ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Используем логнормальное распределение для позиционирования частиц
      a [i].c [c] = u.LognormalDistribution (cB [c], rangeMin [c], rangeMax [c], peakPosition);
      a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

El método "UpdateElectronsIDs" de la clase "C_AO_AOS", que actualiza los identificadores de capa para los electrones dependiendo de sus coordenadas y parámetros dados.

//——————————————————————————————————————————————————————————————————————————————
// Обновление идентификаторов слоев для каждого электрона
void C_AO_AOS::UpdateElectronsIDs ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      electrons [i].layerID [c] = GetOrbitBandID (currentLayers [c], rangeMin [c], rangeMax [c], cB [c], a [i].c [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

El método "CalcLayerParams" de la clase "C_AO_AOS" se utiliza para calcular los parámetros de cada capa de átomos del sistema. Aquí tenemos los principales componentes del método:

1. Inicialización de la variable: "energy" es una variable para almacenar la energía máxima que se actualizará durante el procesamiento de los electrones.

2. El ciclo recorre todos los átomos (coordenadas) del sistema. El índice "c" indica el átomo actual.

3. Para cada átomo, se llama al método "Init", que inicializa los parámetros para el número máximo de capas especificado por la variable "maxLayers".

4. Ciclo de capas: ciclo interno que recorre todas las capas asociadas al átomo actual, "currentLayers [c]" indica el número de capas del átomo "c".

5. Procesamiento de electrones: otro ciclo interno recorre todos los electrones "e" de la población, donde se comprueba si el electrón actual pertenece a la capa "L" para el átomo "c".

6. Actualización de los parámetros de la capa:

  • Si un electrón pertenece a una capa, aumentará el número de partículas en la capa.
  • Los valores de energía "BEk" y de estado "BSk" se actualizan para la capa según las propiedades del electrón.
  • Si la energía del electrón "a[e].f" es mayor que la energía máxima actual "energy" de la capa, se actualizarán los valores de la energía máxima "energy" y del estado "LEk".

7. Cálculo de los valores medios de la capa: si el contador de partículas "pc" no es igual a cero, se calcularán los valores medios de energía y estado.

8. Cálculo del estado de enlace total: de forma similar, el estado de enlace se calcula para cada átomo "BS", pero para la población de electrones en conjunto.

//——————————————————————————————————————————————————————————————————————————————
// Расчет параметров для каждого слоя
void C_AO_AOS::CalcLayerParams ()
{
  double energy;

  // Обработка каждой координаты (атома)
  for (int c = 0; c < coords; c++)
  {
    atoms [c].Init (maxLayers);

    // Обработка каждого слоя
    for (int L = 0; L < currentLayers [c]; L++)
    {
      energy = -DBL_MAX;

      // Обработка каждого электрона
      for (int e = 0; e < popSize; e++)
      {
        if (electrons [e].layerID [c] == L)
        {
          atoms [c].layers [L].pc++;
          atoms [c].layers [L].BEk = a [e].f;
          atoms [c].layers [L].BSk = a [e].c [c];

          if (a [e].f > energy)
          {
            energy = a [e].f;
            atoms [c].layers [L].LEk = a [e].c [c];
          }
        }
      }

      // Расчет средних значений для слоя
      if (atoms [c].layers [L].pc != 0)
      {
        atoms [c].layers [L].BEk /= atoms [c].layers [L].pc;
        atoms [c].layers [L].BSk /= atoms [c].layers [L].pc;
      }
    }
  }

  // Расчет общего состояния связей
  ArrayInitialize (BS, 0);

  for (int c = 0; c < coords; c++)
  {
    for (int e = 0; e < popSize; e++)
    {
      BS [c] += a [e].c [c];
    }

    BS [c] /= popSize;
  }
}
//——————————————————————————————————————————————————————————————————————————————

El método "UpdateElectrons" de la clase "C_AO_AOS" se ocupa de actualizar la posición de los electrones en el sistema.

1. Inicialización de los parámetros: se definen los coeficientes de velocidad, los pesos de la mejor solución, los pesos medios de los estados y la probabilidad de transición.

2. Para cada partícula y cada coordenada:

  • Se genera una probabilidad aleatoria "φ".
  • Si "φ" es inferior al valor umbral "PR", se producirá una dispersión aleatoria y se seleccionará aleatoriamente una nueva posición dentro del intervalo especificado.
  • De lo contrario:
  • Se obtendrá el identificador de capa "lID" de la partícula actual.
  • Se generarán valores aleatorios para los coeficientes.
    • Si la energía actual de una partícula es inferior a la energía media de la capa, se producirá un movimiento hacia el óptimo global.
    • Si no, se producirá un movimiento hacia el óptimo local de la capa.
  • Al final, la nueva posición se limitará dentro del rango especificado teniendo en cuenta el paso.

//——————————————————————————————————————————————————————————————————————————————
// Обновление положения электронов
void C_AO_AOS::UpdateElectrons ()
{
  double α;      // коэффициент скорости
  double β;      // коэффициент веса лучшего решения
  double γ;      // коэффициент веса среднего состояния
  double φ;      // вероятность перехода
  double newPos; // новая позиция
  double LE;     // лучшая энергия
  double BSk;    // состояние связи
  int    lID;    // идентификатор слоя

  // Обработка каждой частицы
  for (int p = 0; p < popSize; p++)
  {
    for (int c = 0; c < coords; c++)
    {
      φ = u.RNDprobab ();

      if (φ < PR)
      {
        // Случайное рассеивание
        newPos = u.RNDfromCI (rangeMin [c], rangeMax [c]);
      }
      else
      {
        lID = electrons [p].layerID [c];

        α = u.RNDfromCI (-1.0, 1.0);
        β = u.RNDprobab ();
        γ = u.RNDprobab ();

        // Если текущая энергия частицы меньше средней энергии слоя
        if (a [p].f < atoms [c].layers [lID].BEk)
        {
          // Движение в сторону глобального оптимума----------------------------
          LE = cB [c];

          newPos = a [p].c [c]+ α * (β * LE - γ * BS [c]) / currentLayers [c];
        }
        else
        {
          // Движение в сторону локального оптимума слоя
          LE  = atoms [c].layers [lID].LEk;
          BSk = atoms [c].layers [lID].BSk;

          newPos = a [p].c [c] + α * (β * LE - γ * BSk);
        }
      }

      // Ограничение новой позиции в пределах диапазона поиска с учетом шага
      a [p].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

El método "Revision" de la clase "C_AO_AOS" está diseñado para revisar y actualizar las mejores soluciones (o estados óptimos) durante la iteración. Pasos del método:

1. Inicialización de la variable "bestIndex", que se usará para almacenar el índice de la mejor solución.

2. Búsqueda de la mejor solución. Condición para comprobar si el valor de la función (o puntuación) de la solución actual "a[i].f" es mayor que el valor actual de la mejor solución global "fB". Si esta condición es verdadera, el valor de la mejor solución global se actualizará hasta el valor actual y el índice de la solución actual se almacenará como la mejor solución.

3. Si se encuentra la mejor solución, las coordenadas de la mejor solución "a[bestIndex].c" se copiarán en el array "cB".

//——————————————————————————————————————————————————————————————————————————————
// Метод пересмотра лучших решений
void C_AO_AOS::Revision ()
{
  int bestIndex = -1;

  // Поиск лучшего решения в текущей итерации
  for (int i = 0; i < popSize; i++)
  {
    // Обновление глобального лучшего решения
    if (a [i].f > fB)
    {
      fB = a [i].f;
      bestIndex = i;
    }
  }

  // Обновление лучших координат если найдено лучшее решение
  if (bestIndex != -1) ArrayCopy (cB, a [bestIndex].c, 0, 0, WHOLE_ARRAY);
}
//——————————————————————————————————————————————————————————————————————————————


Resultados de las pruebas

Vamos a ejecutar el banco de pruebas y obtener estos resultados del AOS:

AOS|Atomic Orbital Search|50.0|5.0|1.0|0.1|0.05|
=============================
5 Hilly's; Func runs: 10000; result: 0.6521321213930082
25 Hilly's; Func runs: 10000; result: 0.39883708808831186
500 Hilly's; Func runs: 10000; result: 0.2602779698842558
=============================
5 Forest's; Func runs: 10000; result: 0.5165008091396371
25 Forest's; Func runs: 10000; result: 0.30233740723010416
500 Forest's; Func runs: 10000; result: 0.1926906342754638
=============================
5 Megacity's; Func runs: 10000; result: 0.39384615384615385
25 Megacity's; Func runs: 10000; result: 0.1892307692307692
500 Megacity's; Func runs: 10000; result: 0.09903076923077013
=============================
All score: 3.00488 (33.39%)

En la visualización del funcionamiento del algoritmo AOS, observamos un comportamiento interesante: regiones características de "aglomeración" en los orbitales atómicos, pero la precisión de convergencia no es muy alta.

Hilly

AOS en la función de prueba Hilly

Forest

AOS en la función de prueba Forest

Megacity

AOS en la función de prueba Megacity

Según los resultados de la prueba, el algoritmo del AOS se ha situado en el puesto 39 de la tabla de clasificación.

AO Description Hilly Hilly final Forest Forest final Megacity (discrete) Megacity final Final result % de 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 (joo) 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 AMOm animal migration optimization M 0,90358 0,84317 0,46284 2,20959 0,99001 0,92436 0,46598 2,38034 0,56769 0,59132 0,23773 1,39675 5,987 66,52
4 (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
5 CTA comet tail algorithm (joo) 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
6 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
7 AAm archery algorithm M 0,91744 0,70876 0,42160 2,04780 0,92527 0,75802 0,35328 2,03657 0,67385 0,55200 0,23738 1,46323 5,548 61,64
8 ESG evolution of social groups (joo) 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
9 SIA simulated isotropic annealing (joo) 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
10 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
11 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
12 TSEA turtle shell evolution algorithm (joo) 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
13 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
14 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
15 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
16 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
17 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
18 BCOm bacterial chemotaxis optimization M 0,75953 0,62268 0,31483 1,69704 0,89378 0,61339 0,22542 1,73259 0,65385 0,42092 0,14435 1,21912 4,649 51,65
19 ABO african buffalo optimization 0,83337 0,62247 0,29964 1,75548 0,92170 0,58618 0,19723 1,70511 0,61000 0,43154 0,13225 1,17378 4,634 51,49
20 (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
21 TSm tabu search M 0,87795 0,61431 0,29104 1,78330 0,92885 0,51844 0,19054 1,63783 0,61077 0,38215 0,12157 1,11449 4,536 50,40
22 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
23 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
24 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
25 AEO artificial ecosystem-based optimization algorithm 0,91380 0,46713 0,26470 1,64563 0,90223 0,43705 0,21400 1,55327 0,66154 0,30800 0,28563 1,25517 4,454 49,49
26 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
27 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
28 ABH 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
29 ACMO atmospheric cloud model optimization 0,90321 0,48546 0,30403 1,69270 0,80268 0,37857 0,19178 1,37303 0,62308 0,24400 0,10795 0,97503 4,041 44,90
30 ASHA artificial showering algorithm 0,89686 0,40433 0,25617 1,55737 0,80360 0,35526 0,19160 1,35046 0,47692 0,18123 0,09774 0,75589 3,664 40,71
31 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
32 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
33 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
34 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
35 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
36 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
37 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
38 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
39 AOS atomic orbital search 0,65213 0,39884 0,26028 1,31125 0,51650 0,30234 0,19269 1,01153 0,39385 0,18923 0,09903 0,68211 3,005 33,39
40 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
41 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
42 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
43 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
44 AAA algae adaptive algorithm 0,50007 0,32040 0,25525 1,07572 0,37021 0,22284 0,16785 0,76089 0,27846 0,14800 0,09755 0,52402 2,361 26,23
45 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


Conclusiones

Hoy hemos analizado un interesante algoritmo de búsqueda de orbitales atómicos que utiliza enfoques novedosos para la búsqueda global y el refinamiento local de los resultados. Gracias a las capas orbitales dinámicas de los átomos, los electrones se mueven de forma equilibrada en busca de un estado atómico estable. El algoritmo muestra un rendimiento limitado en funciones suaves, pero ofrece buenos resultados cuando se aumenta la dimensionalidad del problema, incluso en la función discreta Megacity.

Este algoritmo me parece un buen ejemplo de idea prometedora, pero su eficacia se resiente debido a algunos matices pequeños pero significativos. En el próximo artículo, veremos mi modificación del AOS y analizaremos de qué es capaz realmente este maravilloso concepto de búsqueda orbital.

Tab

Figura 3. Gradación por colores de los algoritmos según sus respectivas pruebas. Los resultados superiores o iguales a 0.99 se resaltan en blanco.

chart

Figura 4. Histograma con los resultados de las pruebas de los algoritmos (en una escala de 0 a 100, cuanto mayor, mejor,

donde 100 es el máximo resultado teórico posible; el script para calcular la tabla de clasificación está en el archivo)


Ventajas e inconvenientes del algoritmo del AOS:

Ventajas:

  1. Una base prometedora para mejorar el algoritmo.
  2. Tiene un número reducido de parámetros externos.

Desventajas:

  1. La frecuente generación de números aleatorios lo hace lento.
  2. Aplicación bastante compleja.
  3. Baja precisión de convergencia.

Adjuntamos al artículo un archivo con las versiones actuales de los códigos de los algoritmos. El autor de este artículo no se responsabiliza de la exactitud absoluta de la descripción de los algoritmos canónicos, muchos de ellos han sido modificados para mejorar las capacidades de búsqueda. Las conclusiones y juicios presentados en los artículos se basan en los resultados de los experimentos realizados.


Programas usados en el artículo

# Nombre Tipo Descripción
1 #C_AO.mqh
Archivo de inclusión
Clase padre de algoritmos de optimización basados en la población
2 #C_AO_enum.mqh
Archivo de inclusión
Enumeración de los algoritmos de optimización basados en la población
3 TestFunctions.mqh
Archivo de inclusión
Biblioteca de funciones de prueba
4
TestStandFunctions.mqh
Archivo de inclusión
Biblioteca de funciones del banco de pruebas
5
Utilities.mqh
Archivo de inclusión
Biblioteca de funciones auxiliares
6
CalculationTestResults.mqh
Archivo de inclusión
Script para calcular los resultados en una tabla comparativa
7
Testing AOs.mq5
Script Banco de pruebas único para todos los algoritmos de optimización basados en la población
8
AO_AOS_AtomicOrbitalSearch.mqh
Archivo de inclusión Clase del algoritmo AOS
9
Test_AO_AOS.mq5
Script
Banco de pruebas para el AOS

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/16276

Archivos adjuntos |
AOS.ZIP (128.64 KB)
Simulador rápido de estrategias comerciales en Python usando Numba Simulador rápido de estrategias comerciales en Python usando Numba
Este artículo implementaremos un simulador rápido de estrategias para modelos de aprendizaje automático utilizando Numba. En cuanto a su velocidad, superará en un factor de 50 a un simulador de estrategias puramente basado en Python. El autor recomienda usar esta biblioteca para acelerar los cálculos matemáticos, y especialmente cuando se utilizan ciclos.
Reimaginando las estrategias clásicas en MQL5 (Parte IX): Análisis de múltiples marcos temporales (II) Reimaginando las estrategias clásicas en MQL5 (Parte IX): Análisis de múltiples marcos temporales (II)
En la discusión de hoy, examinamos la estrategia de análisis de múltiples marcos temporales para aprender en qué marco temporal nuestro modelo de IA funciona mejor. Nuestro análisis nos lleva a concluir que los marcos temporales mensuales y horarios producen modelos con tasas de error relativamente bajas en el par EURUSD. Utilizamos esto para nuestro beneficio y creamos un algoritmo comercial que hace predicciones de IA en el marco de tiempo mensual y ejecuta sus operaciones en el marco de tiempo horario.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Redes neuronales en el trading: Modelo hiperbólico de difusión latente (Final) Redes neuronales en el trading: Modelo hiperbólico de difusión latente (Final)
El uso de procesos de difusión anisotrópica para codificar los datos de origen en un espacio latente hiperbólico, como se propone en el framework HypDIff, ayuda a preservar las características topológicas de la situación actual del mercado y mejora la calidad de su análisis. En el artículo anterior, empezamos a aplicar los enfoques propuestos usando herramientas MQL5. Hoy continuaremos el trabajo iniciado, llevándolo a su conclusión lógica.
OSZAR »