English Русский Deutsch 日本語 Português
preview
Algoritmos de optimización de la población: Algoritmo Mind Evolutionary Computation (Computación Evolutiva Mental, (MEC)

Algoritmos de optimización de la población: Algoritmo Mind Evolutionary Computation (Computación Evolutiva Mental, (MEC)

MetaTrader 5Ejemplos | 26 febrero 2024, 06:25
229 0
Andrey Dik
Andrey Dik

Contenido:

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


1. Introducción

La computación evolutiva es un subapartado de la inteligencia computacional, el aprendizaje automático y la inteligencia artificial. Tienen amplias aplicaciones en problemas de optimización, diseño de robots, creación de árboles de decisión, configuración de algoritmos de análisis de datos, entrenamiento de redes neuronales y ajuste de hiperparámetros. En lugar de usar métodos numéricos clásicos, la computación evolutiva se inspira en la evolución biológica para desarrollar buenas soluciones. Resultan especialmente útiles cuando no se conoce la derivada de la función de aptitud, o cuando la función de aptitud tiene muchos extremos locales que pueden complicar los métodos secuenciales.

Los algoritmos basados en poblaciones utilizados en computación evolutiva poseen varias ventajas sobre los algoritmos clásicos a la hora de resolver problemas complejos de alta dimensionalidad. Pueden encontrar de forma más eficiente soluciones subóptimas que se encuentren suficientemente cerca de la óptima, lo cual suele ser aceptable en problemas de optimización relevantes en la práctica.

Un enfoque interesante en computación evolutiva es el algoritmo Mind Evolutionary Computation (MEC) propuesto en 1998 por Chengai y otros. En contraste con la esperada simulación del cerebro humano, el algoritmo MEC modela algunos aspectos del comportamiento humano en sociedad. En este algoritmo, cada individuo es tratado como un agente inteligente que opera en un grupo de personas. A la hora de tomar decisiones, un individuo se siente influido tanto por los miembros de su propio grupo como por los de otros. Para alcanzar una posición elevada en la sociedad, un individuo deberá aprender de las personas con más éxito de su grupo. Al mismo tiempo, para que su grupo tenga más éxito en comparación con otros, todos los individuos deberán guiarse por el mismo principio en la competición intergrupal. Un aspecto importante del algoritmo MEC es el intercambio de información entre individuos dentro de un grupo y entre ellos. Esto refleja la necesidad de un intercambio continuo y libre de información para el desarrollo satisfactorio de una sociedad de individuos inteligentes.

El concepto presentado se implementará mediante algoritmos MEC que utilizan operaciones de contención y disimilación locales responsables de la búsqueda local y global, respectivamente. Los tableros de mensajes son usados por el algoritmo para almacenar información sobre la historia evolutiva de la población y el proceso de optimización se gestiona basándose en esta información.


2. Descripción del algoritmo

El algoritmo MEC puede interpretarse como un algoritmo multipoblación compuesto por grupos líderes y rezagados. Se supone que el número de agentes de cada grupo será el mismo. Cada grupo tiene su propio tablón de anuncios local, y además hay un tablón de anuncios global compartido para toda la multipoblación.

La versión original del algoritmo MEC, conocida como Simple MEC (SMEC), usa operaciones de inicialización de grupo, contención y disimilación locales.

La operación de inicialización crea los grupos y los coloca en la zona de búsqueda. Para cada grupo, se generará un vector aleatorio que se identificará con un individuo del grupo. A continuación, se determinarán las coordenadas iniciales de los agentes del grupo restantes colocándolos aleatoriamente alrededor del individuo del grupo mediante una ley de distribución normal.

La operación de competición local ejecuta una búsqueda local del máximo de la función de aptitud de cada grupo. Para cada grupo, la información sobre el agente ganador actual se leerá en su tablón de anuncios. A continuación, se determinarán las nuevas coordenadas de los restantes agentes del grupo, colocándolos aleatoriamente alrededor del ganador mediante una ley de distribución normal. Después se calcularán las nuevas cuentas de los agentes del grupo y se determinará el nuevo ganador del grupo con la máxima cuenta corriente. El nuevo ganador se publicará en el tablón de anuncios del grupo.

La operación de disimilación controlará la búsqueda global. En primer lugar, las cuentas de todos los grupos se leerán en el tablón de anuncios global. A continuación, estas cuentas se compararán entre sí. Si la puntuación del grupo líder es inferior a la de uno de los grupos rezagados, este último pasará a ocupar el lugar del líder, mientras que el grupo líder se convertirá en el grupo rezagado. Si la puntuación de un grupo es inferior a la de todos los grupos rezagados, el grupo se eliminará de la población. En lugar de los grupos eliminados, los nuevos grupos se inicializarán usando la operación de inicialización.

Así, el algoritmo MEC es un algoritmo multipoblación que incluye operaciones de inicialización, contención y disimilación locales.

Lo anterior ha sido una descripción general del algoritmo MEC simple de los creadores del algoritmo; dicha descripción, en mi opinión, dificulta la comprensión de los principios detrás de la estrategia de búsqueda en el espacio multidimensional y esto plantea muchas preguntas como "¿qué es un tablero de mensajes y en qué se diferencia de las características de los individuos específicos en el grupo?" y otras preguntas, así que vamos a entrar en estas sutilezas con más detalle.

Ya hemos dicho que el algoritmo modela la sociedad humana y la interacción entre sus miembros. La forma más sencilla y directa de pensar en el concepto de "idea" puede ser una idea científica, una idea artística, una idea literaria o cualquier otra idea. En la sociedad siempre existen ideas dominantes e ideas alternativas. No dividiremos las ideas en "líderes y rezagadas", como sugieren los autores en relación con los grupos: esto, como veremos más adelante, dará alguna ventaja al algoritmo sobre su versión de referencia. Como toda idea incluye al menos una tesis (una tesis es un parámetro optimizable de una función de aptitud), una idea puede ramificarse en otras, igual que en la ciencia existen diferentes teorías y corrientes científicas. La figura 1 muestra de forma esquemática las ideas etiquetadas como i1, i2, etc. Cada idea puede ramificarse dentro de los límites definidos por el poder del pensamiento (un parámetro externo del algoritmo); cuanto más lejos esté la ramificación de la idea, menos probable será (la probabilidad y los límites de las ramificaciones de las ideas se muestran como círculos concéntricos en expansión). Si se demuestra que una idea está más consolidada (el valor de la función de aptitud es mejor) que su idea padre, esta rama sustituirá a la idea padre (la nueva idea como resultado de la bifurcación de ideas se muestra como i5 en la figura). En la figura podemos ver que no existen restricciones al cruce de fronteras de ideas, lo cual significa que es posible la aparición de ramas de ideas con las mismas tesis.

ideas

Figura 1. Ideas i1, i2, i3, i4, límites de estas, cruces de los límites y aparición de una nueva idea i5 como resultado de la ramificación de la idea i1.

La bifurcación de ideas ejecuta una contención local dentro de cada idea y proporciona una búsqueda en la vecindad de un extremo local. El conjunto de ramas de todas las ideas representa una multipoblación, mientras que una idea individual y sus ramas representan una población aparte. Cada idea solo encierra su tesis y su valor práctico, mientras que el programa de usuario recurre a las ramas de ideas, no a las ideas en sí.

Para garantizar la búsqueda global, deberemos posibilitar la aparición de nuevas ideas más allá de las actuales en la población, de lo contrario las ideas se "cocerán" en sí mismas (atascadas en extremos locales) y no se dará la aparición del mejor valor de la función de aptitud. Precisamente para este fin se ha diseñado el proceso de disimilación (destrucción). Utilizaremos un patrón de intercambio de ideas entre el grupo de ideas dominante (verde) y el grupo alternativo (azul) ligeramente distinto al del algoritmo original. Tras clasificar las ideas de cada grupo por separado, eliminaremos la peor del grupo dominante y colocaremos en su lugar la mejor del grupo alternativo, garantizando así el intercambio de ideas. En el espacio desocupado del grupo alternativo colocaremos una nueva idea que se ensamblará a partir de las tesis de las ideas seleccionadas al azar del grupo dominante (excluida la última). A esta acción se le puede añadir un componente aleatorio para aportar variabilidad, que dejaremos para una posible experimentación posterior a los investigadores de algoritmos de optimización. Tomar tesis de las ideas del grupo dominante aumentará la capacidad combinatoria del algoritmo. La figura 2 muestra el esquema de sustitución de una idea por otra del grupo alternativo y la creación de una nueva.

ideas 2

Figura 2. Plan para sustituir una idea por otra de un grupo alternativo y crear una nueva.

Escribiremos el pseudocódigo MEC para simplificar la escritura posterior del código del algoritmo:

1.1 Si se trata de la primera ejecución del algoritmo
1.1.1 Crearemos dos grupos de ideas al azar según el campo de ideas (dominante y alternativo)

1.2 Si se trata de la segunda ejecución del algoritmo o posteriores
1.2.1 Para la idea dominante, crearemos ramas según la ley de Levy*; una de las ramas será el resultado de una combinación de las tesis de las ideas dominantes.
1.2.2 Para una idea alternativa, todas las ramas se crearán según la ley de Levy*.

2 Calcularemos el valor de las ramas de ideas

3.1 Si hay una idea rama mejor, sustituiremos la idea correspondiente
3.2 Clasificaremos por separado los grupos dominante y alternativo
3.3 Sustituiremos la peor idea del grupo dominante por la mejor idea del grupo alternativo
3.4 En lugar de una idea vacía en un grupo alternativo, crearemos una nueva idea basada en elementos del grupo dominante** (sustituiremos todas menos la última)


* - en lugar de una distribución normal, como en el caso del autor
** - en lugar de crear tesis al azar como ha hecho el autor

Podemos observar en el pseudocódigo que el algoritmo original ha sufrido modificaciones.

En primer lugar, en lugar de la ley de distribución normal propuesta por los autores del algoritmo, usaremos la ley del vuelo de Levy, que mejora la capacidad de exploración del algoritmo y matiza sus capacidades. Deberemos prestar atención al hecho de que la ley del vuelo de Levy está lejos de mejorar el rendimiento de todos los algoritmos de optimización si se intenta utilizar en lugar de la distribución normal o uniforme. Esto se debe principalmente a las particularidades de la estrategia de búsqueda del algoritmo. Por ejemplo, en el artículo anterior, en el que analizamos el algoritmo de salto de rana aleatorio, intentamos utilizar la ley del vuelo de Levy en ranas saltarinas en lugar de la distribución normal, lo cual no produjo ninguna mejora notable en el rendimiento de la capacidad de búsqueda.

En segundo lugar, el algoritmo original no ofrece absolutamente ningún mecanismo combinatorio en la estrategia de búsqueda; tratemos de entender por qué esto resulta esencial. Por poner un ejemplo, vamos a imaginar varias cestas que contienen bolas de aluminio (ligeras) y una bola de oro (pesada). Tenemos una tarea: llenar una cesta vacía con pelotas de modo que todas sean doradas, y se nos permite o bien cambiar suavemente la composición química de cada nueva pelota en la cesta y no saber si esto aumentará la masa, o simplemente coger al azar una pelota que esté en una de las cestas, y saber que una de ellas será necesariamente dorada, pudiendo además pesar solo la cesta en su conjunto pero no las pelotas por separado. Una vez tengamos la cesta llena, deberemos pesarla, y el reto consistirá en maximizar el peso de la cesta. Este problema demuestra que usando una simple combinación podemos conseguir una cesta llena de bolas doradas en muchos menos pasos.

Veamos ahora la descripción del código del algoritmo.

La unidad lógica elemental de un algoritmo será una idea, y también representará una rama de ideas. La estructura S_Idea, que es un objeto que contiene información sobre las coordenadas y la idoneidad de una idea, será excelente para describir una idea. La estructura tiene un método Init para inicializar la adaptación con un valor DBL_MAX negativo.

//——————————————————————————————————————————————————————————————————————————————
struct S_Idea
{
  void Init (int size)
  {
    ArrayResize (c, size);
    f = -DBL_MAX;
  }
  double c []; //coordinates
  double f;    //fitness
};
//——————————————————————————————————————————————————————————————————————————————

En la clase C_AO_MEC, describiremos el algoritmo MEC; contiene una serie de variables y métodos para trabajar con esas variables.

Variables de clase:
- cB: array que contiene las mejores coordenadas
- fB: valor de la función de aptitud para las mejores coordenadas
- idBr: array que contiene las ramas ideológicas

- rangeMax: array que contiene los valores máximos a buscar
- rangeMin: array que contiene los valores mínimos a buscar
- rangeStep: array que contiene los pasos a buscar

- leadIdeolGroup: array que contiene el grupo ideológico principal
- alteIdeolGroup: array que contiene el grupo ideológico alternativo
- tempIdeolGroup: array que contiene el grupo ideológico temporal

- coordinatesNumber: número de coordenadas
- populationSize: tamaño de la población
- ideasNumber: número de ideas
- thoughtPower: poder del pensamiento
- ideasBr: número de ramas ideológicas
- leadIdGroupSize: tamaño del grupo ideológico líder
- alteIdGroupSize: tamaño del grupo ideológico alternativo

- vect: vector para usar los incrementos de coordenadas
- ind: array de índices
- val: array de valores
- revision: bandera de revisión

Métodos de clase:
- Init: inicialización de la clase con transmisión de parámetros
- Moving: ejecución de un movimiento
- Revision: revisión

- Sorting: clasificación de grupos ideológicos
- SeInDiSp: cálculo del intervalo de búsqueda
- RNDfromCI: generación de un número aleatorio partiendo de un intervalo dado

//——————————————————————————————————————————————————————————————————————————————
class C_AO_MEC
{
  //----------------------------------------------------------------------------
  public: double cB   []; //best coordinates
  public: double fB;      //FF of the best coordinates
  public: S_Idea idBr []; //ideological branches


  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search


  public: void Init (const int    coordinatesNumberP,   //coordinates number
                     const int    populationSizeP,      //population size
                     const int    ideasNumberP,         //ideas number
                     const double thoughtPowerP);       //thought power

  public: void Moving   ();
  public: void Revision ();

  //----------------------------------------------------------------------------
  private: S_Idea leadIdeolGroup []; //leading ideological group
  private: S_Idea alteIdeolGroup []; //alternative ideological group
  private: S_Idea tempIdeolGroup []; //temporal ideological group

  private: int    coordinatesNumber; //coordinates number
  private: int    populationSize;    //population size
  private: int    ideasNumber;       //ideas number
  private: double thoughtPower;      //thought power
  private: int    ideasBr;           //number of ideological branches
  private: int    leadIdGroupSize;   //leading ideological group size
  private: int    alteIdGroupSize;   //alternative ideological group size

  private: double vect    [];        //vector
  private: int    ind     [];
  private: double val     [];
  private: bool   revision;

  private: void   Sorting   (S_Idea &ideas []);
  private: double SeInDiSp  (double In, double InMin, double InMax, double Step);
  private: double RNDfromCI (double min, double max);
};
//——————————————————————————————————————————————————————————————————————————————

El método de inicialización Init realiza las siguientes acciones:

- Al principio del código, se establecerá el valor inicial del generador de números aleatorios y la variable fB se establecerá en el valor mínimo de tipo double.
- A continuación, las variables coordinatesNumber, populationSize, ideasNumber y thoughtPower se establecerán como iguales a los valores transmitidos a la función Init.
- A continuación se calcularán los valores de las variables ideasBr, leadIdGroupSize y alteIdGroupSize a partir de los valores de populationSize e ideasNumber.
- Después los arrays rangeMax, rangeMin, rangeStep, vect, ind, val, tempIdeolGroup y cB se redimensionarán con la función ArrayResize.
- Luego se crearán objetos de la clase Ideology en los arrays leadIdeolGroup y alteIdeolGroup usando ciclos for y la función Init.
- A continuación, se crearán objetos de la clase Ideology en el array idBr mediante un ciclo for y la función Init.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MEC::Init (const int    coordinatesNumberP,   //coordinates number
                     const int    populationSizeP,      //population size
                     const int    ideasNumberP,         //ideas number
                     const double thoughtPowerP)        //thought power
{
  MathSrand ((int)GetMicrosecondCount ()); // reset of the generator
  fB       = -DBL_MAX;
  revision = false;

  coordinatesNumber = coordinatesNumberP;
  populationSize    = populationSizeP;
  ideasNumber       = ideasNumberP;
  thoughtPower      = thoughtPowerP;

  ideasBr         = populationSize / ideasNumber;
  leadIdGroupSize = ideasNumber / 2;
  alteIdGroupSize = ideasNumber - leadIdGroupSize;

  ArrayResize (rangeMax,       coordinatesNumber);
  ArrayResize (rangeMin,       coordinatesNumber);
  ArrayResize (rangeStep,      coordinatesNumber);
  ArrayResize (vect,           coordinatesNumber);
  ArrayResize (ind,            alteIdGroupSize, alteIdGroupSize);
  ArrayResize (val,            alteIdGroupSize, alteIdGroupSize);
  ArrayResize (tempIdeolGroup, alteIdGroupSize, alteIdGroupSize);
  ArrayResize (cB,             coordinatesNumber);

  ArrayResize (leadIdeolGroup, leadIdGroupSize);
  for (int i = 0; i < leadIdGroupSize; i++) leadIdeolGroup [i].Init (coordinatesNumber);

  ArrayResize (alteIdeolGroup, alteIdGroupSize);
  for (int i = 0; i < alteIdGroupSize; i++) alteIdeolGroup [i].Init (coordinatesNumber);

  ArrayResize (idBr, populationSize);
  for (int i = 0; i < populationSize; i++) idBr [i].Init (coordinatesNumber);
}
//——————————————————————————————————————————————————————————————————————————————

El método Moving de creación de ramas de ideas cumple la lógica básica de la estrategia de búsqueda de MEC. Parte del código se ejecutará solo en la primera iteración del algoritmo mientras que el resto del código se ejecutará en cada iteración.

La primera iteración consistirá en inicializar un vector que se rellenará con valores calculados a partir de rango y fuerza del pensamiento (thoughtPower), que suponen incrementos en la ramificación, y creará las ideas en dos grupos, dominante y alternativo. Para ello, dispersaremos las ideas de ambos grupos (y estas son equivalentes) con igual probabilidad por todo el campo de búsqueda.

//============================================================================
if (!revision)
{
  fB = -DBL_MAX;
  int cnt = 0;

  for (int c = 0; c < coordinatesNumber; c++) vect [c] = (rangeMax [c] - rangeMin [c]) * thoughtPower;

  //--------------------------------------------------------------------------
  for (int i = 0; i < leadIdGroupSize; i++)
  {
    for (int c = 0; c < coordinatesNumber; c++)    
    {
      coord = RNDfromCI (rangeMin [c], rangeMax [c]);
      leadIdeolGroup [i].c [c] = SeInDiSp (coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
    leadIdeolGroup [i].f = -DBL_MAX;
  }

  //--------------------------------------------------------------------------
  for (int i = 0; i < alteIdGroupSize; i++)
  {
    for (int c = 0; c < coordinatesNumber; c++)
    {
      coord = RNDfromCI (rangeMin [c], rangeMax [c]);
      alteIdeolGroup [i].c [c] = SeInDiSp (coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
    alteIdeolGroup [i].f = -DBL_MAX;
  }

  revision = true;
}

Luego, en la primera iteración y en las siguientes, generaremos ramas de ideas, por el bien de las propias ideas que ya hemos creado. Nos interesarán específicamente las ramificaciones ideológicas que podamos evaluar según la función de aptitud.

La operación principal para crear una rama será fijar el movimiento hacia estas ideas según la ley del vuelo de Levy con normalización según el coeficiente de poder de pensamiento; lo haremos para todas las ideas del grupo alternativo y para todas menos la última para el grupo dominante según la fórmula:

coord = leadIdeolGroup [i].c [c] + r1 * vect [c] * pow (r2, -2.0);

para la última idea del grupo dominante, seleccionaremos al azar una idea de ese grupo y tomaremos la tesis del índice correspondiente:

r1 = RNDfromCI (0.0, leadIdGroupSize - 1);
idBr [cnt].c [c] = leadIdeolGroup [(int)r1].c [c];

y aquí está el código completo para crear ramificaciones de ideas para ambos grupos:

//----------------------------------------------------------------------------
for (int i = 0; i < leadIdGroupSize; i++)
{
  for (int b = 0; b < ideasBr; b++)
  {
    if (b < ideasBr -1)
    {
      for (int c = 0; c < coordinatesNumber; c++)
      {
        r1 = RNDfromCI (0.0, 1.0);
        r1 = r1 > 0.5 ? 1.0 : -1.0;
        r2 = RNDfromCI (1.0, 20.0);

        coord = leadIdeolGroup [i].c [c] + r1 * vect [c] * pow (r2, -2.0);
        idBr [cnt].c [c] = SeInDiSp (coord, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
    else
    {
      for (int c = 0; c < coordinatesNumber; c++)
      {
        r1 = RNDfromCI (0.0, leadIdGroupSize - 1);
        idBr [cnt].c [c] = leadIdeolGroup [(int)r1].c [c];
      }
    }

    cnt++;
  }
}

//----------------------------------------------------------------------------
for (int i = 0; i < alteIdGroupSize; i++)
{
  for (int b = 0; b < ideasBr; b++)
  {
    for (int c = 0; c < coordinatesNumber; c++)
    {
      r1 = RNDfromCI (0.0, 1.0);
      r1 = r1 > 0.5 ? 1.0 : -1.0;
      r2 = RNDfromCI (1.0, 20.0);

      coord = alteIdeolGroup [i].c [c] + r1 * vect [c] * pow (r2, -2.0);
      idBr [cnt].c [c] = SeInDiSp (coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }

    cnt++;
  }
}

El método revision está diseñado para revisar las ideas según los resultados de la evaluación de sus ramas de ideas, así como para actualizar las métricas de la solución global. En el código se ejecutarán los siguientes pasos:

1. Inicialización de las variables cnt y pos.

2. Sustitución de las mejores ideas: El ciclo para cada líder del grupo de líderes (leadIdeolGroup) buscará la rama de la mejor idea del global (idBr). Para cada rama se realizará una comprobación, si su valor de la función de aptitud (f) es mayor que el valor del líder actual, la posición (pos) se establecerá como igual al índice actual (cnt). Si se encuentra una idea mejor, el valor funcional y las coordenadas del líder se actualizarán con los valores de esa idea. Si el valor funcional de la nueva idea también es mayor que el mejor valor funcional actual (fB), entonces también se actualizarán fB y las coordenadas de la mejor idea (cB).

3. Se realizará del mismo modo para el alteIdeolGroup.

4. Clasificación de grupos de ideas: Los grupos de líderes y las ideas alternativas se clasificarán en orden descendente según el valor de la función de aptitud.

5. Sustitución de la peor idea: La peor idea del leadIdeolGroup se sustituirá por la mejor idea del alteIdeolGroup.

6. Creación de una nueva idea: para cada coordenada (c) del grupo de soluciones alternativas (alteIdeolGroup), se creará una nueva idea basada en los elementos del grupo dominante (leadIdeolGroup). La coordenada se elegirá al azar entre el grupo dominante de líderes.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MEC::Revision ()
{
  int cnt = 0;
  int pos = -1;

  //----------------------------------------------------------------------------
  //4. If there is a better ideological branch, replace the corresponding idea
  for (int i = 0; i < leadIdGroupSize; i++)
  {
    pos = -1;
    for (int b = 0; b < ideasBr; b++)
    {
      if (idBr [cnt].f > leadIdeolGroup [i].f) pos = cnt;

      cnt++;
    }

    if (pos != -1)
    {
      leadIdeolGroup [i].f = idBr [pos].f;
      ArrayCopy (leadIdeolGroup [i].c, idBr [pos].c, 0, 0, WHOLE_ARRAY);

      if (idBr [pos].f > fB)
      {
        fB = idBr [pos].f;
        ArrayCopy (cB, idBr [pos].c, 0, 0, WHOLE_ARRAY);
      }
    }
  }

  //----------------------------------------------------------------------------
  for (int i = 0; i < alteIdGroupSize; i++)
  {
    pos = -1;
    for (int b = 0; b < ideasBr; b++)
    {
      if (idBr [cnt].f > alteIdeolGroup [i].f) pos = cnt;

      cnt++;
    }

    if (pos != -1)
    {
      alteIdeolGroup [i].f = idBr [pos].f;
      ArrayCopy (alteIdeolGroup [i].c, idBr [pos].c, 0, 0, WHOLE_ARRAY);

      if (idBr [pos].f > fB)
      {
        fB = idBr [pos].f;
        ArrayCopy (cB, idBr [pos].c, 0, 0, WHOLE_ARRAY);
      }
    }
  }

  //----------------------------------------------------------------------------
  //5. Sort two groups of ideas.
  Sorting (leadIdeolGroup);
  Sorting (alteIdeolGroup);

  //----------------------------------------------------------------------------
  //6. Replace the worst idea of the first group with the best idea from the second group
  leadIdeolGroup [leadIdGroupSize - 1] = alteIdeolGroup [0];

  //----------------------------------------------------------------------------
  //7. Instead of an empty idea, create a new idea based on elements of the dominant group 
  double rnd   = 0.0;
  double coord = 0.0;
  for (int c = 0; c < coordinatesNumber; c++)
  {
    rnd = RNDfromCI (0.0, leadIdGroupSize - 2);
    alteIdeolGroup [0].c [c] = leadIdeolGroup [(int)rnd].c [c];
  }
}
//——————————————————————————————————————————————————————————————————————————————


3. Resultados de las pruebas

Impresión del rendimiento del algoritmo de evolución mental en el banco de pruebas:

C_AO_MEC:50;10;0.3
=============================
5 Rastrigin's; Func runs 10000 result: 78.73205273291103
Score: 0.97553
25 Rastrigin's; Func runs 10000 result: 58.554840607439516
Score: 0.72553
500 Rastrigin's; Func runs 10000 result: 42.32395504312925
Score: 0.52442
=============================
5 Forest's; Func runs 10000 result: 1.2024830541165685
Score: 0.68018
25 Forest's; Func runs 10000 result: 0.4588423143844061
Score: 0.25954
500 Forest's; Func runs 10000 result: 0.08756810826330522
Score: 0.04953
=============================
5 Megacity's; Func runs 10000 result: 5.279999999999999
Score: 0.44000
25 Megacity's; Func runs 10000 result: 2.048
Score: 0.17067
500 Megacity's; Func runs 10000 result: 0.4364
Score: 0.03637
=============================
All score: 3.86178
Observando la animación del algoritmo MEC, podemos ver la formación de clústeres de concentración de agentes en los extremos locales. La calidad de la convergencia da esperanzas de ocupar puestos notables en la tabla de clasificación.

rastrigin

  MEC en la función de prueba Rastrigin.

forest

  MEC en la función de prueba Forest.

megacity

  MEC en la función de prueba Megacity.


Analizando la tabla de clasificación de los resultados de las pruebas de los algoritmos de optimización, observamos que el algoritmo MEC alcanza un rendimiento muy elevado y ocupa el honroso quinto puesto. El MEC muestra excelentes resultados en las funciones Rastrigin, Forest y Megacity, a pesar de la superficie totalmente diferente de estas funciones de prueba. Los resultados resultan especialmente impresionantes en la función Megacity con 10 parámetros. No obstante, cabe señalar que el MEC muestra un rendimiento aún mayor en las características con menos parámetros optimizables en comparación con los otros participantes del análisis, y esto supone más un inconveniente que una ventaja. 

#

AO

Description

Rastrigin

Rastrigin final

Forest

Forest final

Megacity (discrete)

Megacity final

Final result

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

SSG

saplings sowing and growing

1.00000

1.00000

0.55665

2.55665

0.72740

0.94522

1.00000

2.67262

0.76364

0.85977

1.00000

2.62340

100.000

2

HS

harmony search

0.99676

0.95282

0.48178

2.43136

1.00000

0.98931

0.44806

2.43736

1.00000

1.00000

0.41537

2.41537

92.329

3

ACOm

ant colony optimization M

0.34611

0.17985

0.17044

0.69640

0.86888

1.00000

0.77362

2.64249

1.00000

0.88930

0.05606

1.94536

65.347

4

IWO

invasive weed optimization

0.95828

0.67083

0.29807

1.92719

0.70773

0.46349

0.31773

1.48896

0.80000

0.42067

0.33289

1.55356

61.104

5

MEC

mind evolutionary computation

0.99270

0.51040

0.22800

1.73110

0.60762

0.40658

0.25459

1.26880

0.93335

0.41328

0.26170

1.60833

56.227

6

COAm

cuckoo optimization algorithm M

0.92400

0.46794

0.26004

1.65199

0.58378

0.34034

0.16526

1.08939

0.72727

0.33025

0.17083

1.22835

47.612

7

FAm

firefly algorithm M

0.59825

0.33980

0.17135

1.10941

0.51073

0.42299

0.49790

1.43161

0.34545

0.28044

0.35258

0.97847

41.537

8

ABC

artificial bee colony

0.78170

0.32715

0.20822

1.31707

0.53837

0.21455

0.13344

0.88636

0.56364

0.26569

0.13926

0.96858

36.849

9

GSA

gravitational search algorithm

0.70167

0.45217

0.00000

1.15384

0.31660

0.36416

0.33204

1.01280

0.59395

0.35054

0.00000

0.94448

36.028

10

BA

bat algorithm

0.40526

0.63761

0.84451

1.88738

0.20841

0.17477

0.25989

0.64308

0.29698

0.09963

0.17371

0.57032

35.888

11

BFO

bacterial foraging optimization

0.67203

0.30963

0.11813

1.09979

0.39702

0.26623

0.20652

0.86976

0.52122

0.33211

0.18932

1.04264

34.693

12

EM

electroMagnetism-like algorithm

0.12235

0.46278

1.00000

1.58513

0.00000

0.03498

0.34880

0.38377

0.00000

0.00000

0.10924

0.10924

22.091

13

SFL

shuffled frog-leaping

0.40072

0.23739

0.26548

0.90360

0.20153

0.04147

0.02652

0.26952

0.27273

0.05535

0.06639

0.39446

15.203

14

MA

monkey algorithm

0.33192

0.33451

0.14644

0.81287

0.10012

0.07891

0.08932

0.26836

0.21818

0.04243

0.10720

0.36781

13.603

15

FSS

fish school search

0.46812

0.25337

0.11302

0.83451

0.12840

0.05013

0.06516

0.24369

0.16971

0.04796

0.08283

0.30050

12.655

16

PSO

particle swarm optimisation

0.20449

0.08200

0.07160

0.35809

0.18895

0.10486

0.21738

0.51119

0.23636

0.05903

0.01957

0.31496

10.031

17

RND

random

0.16826

0.09743

0.08019

0.34589

0.13496

0.04810

0.04715

0.23021

0.16971

0.03875

0.04922

0.25767

5.302

18

GWO

grey wolf optimizer

0.00000

0.00000

0.02256

0.02256

0.06570

0.00000

0.00000

0.06570

0.32727

0.07378

0.02557

0.42663

1.000


Conclusiones

El Algoritmo de Evolución Mental (MEC) es un método de optimización eficaz y potente basado en los principios de la evolución biológica. Presenta una serie de ventajas significativas que lo hacen atractivo a la hora de resolver problemas de optimización complejos.

El algoritmo de evolución mental puede aplicarse a una amplia gama de problemas, tales como la optimización funcional, la búsqueda de valores óptimos de los parámetros y los problemas de aprendizaje automático, entre otros. No requiere conocer la forma analítica de la función objetivo y puede gestionar espacios de solución continuos, discretos o combinatorios.

El MEC es fácilmente paralelizable, lo cual permite utilizar múltiples recursos informáticos para acelerar el proceso de optimización. Esto resultará especialmente útil al tratar con tareas que requieren un gran número de cálculos o iteraciones.

El MEC tiene cierta tendencia a atascarse en extremos locales, pero este inconveniente aparece principalmente en funciones discretas y funciones con pliegues, y si se considera esta característica a la hora de diseñar una función de aptitud, dicho inconveniente del algoritmo podrá considerarse mínimamente significativo.

El MEC funciona relativamente bien en problemas en los que el espacio de soluciones resulta muy dimensional. El algoritmo no está suficientemente estudiado y aún tiene potencial de mejora.

En general, el algoritmo MEC es una potente herramienta de optimización, flexible, versátil y con buenos extremos locales. Estas ventajas lo convierten en una opción atractiva para resolver problemas de optimización complejos en diversos ámbitos; la sencillez de la lógica del algoritmo puede resultar especialmente útil para su uso en soluciones de software personalizadas no estándar.

Para visualizar mejor las ventajas y desventajas de cada algoritmo en comparación con los demás, la tabla anterior puede representarse utilizando la escala de colores de la figura 3.

rating table

Figura 3. Gradación por colores de los algoritmos según sus respectivas pruebas.

Histograma de los resultados de los algoritmos de prueba en la figura 3 (en una escala de 0 a 100, cuanto más mejor, en el archivo hay un script para calcular la tabla de clasificación según la metodología de este artículo):

chart

Figura 4. Histograma con los resultados finales de los algoritmos de prueba.

Ventajas y desventajas del algoritmo MEC:

Ventajas:
1. Número mínimo de parámetros externos.
2. Alta eficiencia en una gran variedad de tareas.
3. Bajo gasto de recursos informáticos.
4. Facilidad de aplicación del algoritmo.

Desventajas:
1. El algoritmo se atasca en funciones con "superficies" horizontales planas.

En cada artículo adjuntamos un archivo que contiene versiones reales actualizadas de los códigos de los algoritmos descritos en los artículos anteriores. No obstante, cabe señalar que no nos hacemos responsable de la exactitud absoluta en la descripción de los algoritmos canónicos. Con frecuencia también hemos añadido ideas propias y mejoras basadas en experiencias y opiniones personales. Las conclusiones y juicios presentados en los artículos se basan en los resultados de los experimentos realizados.

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

Archivos adjuntos |
Integración de modelos ML con el simulador de estrategias (Conclusión): Implementación de un modelo de regresión para la predicción de precios Integración de modelos ML con el simulador de estrategias (Conclusión): Implementación de un modelo de regresión para la predicción de precios
Este artículo describe la implementación de un modelo de regresión de árboles de decisión para predecir precios de activos financieros. Se realizaron etapas de preparación de datos, entrenamiento y evaluación del modelo, con ajustes y optimizaciones. Sin embargo, es importante destacar que el modelo es solo un estudio y no debe ser usado en operaciones reales.
Desarrollando un cliente MQTT para MetaTrader 5: metodología de TDD (Parte 3) Desarrollando un cliente MQTT para MetaTrader 5: metodología de TDD (Parte 3)
El presente artículo supone la tercera parte de la serie que describe las etapas de desarrollo de un cliente MQL5 nativo para el protocolo MQTT. En esta ocasión, hablaremos con detalle sobre la aplicación de un desarrollo basado en pruebas para implementar el intercambio de paquetes CONNECT/CONNACK. Al final de este paso, nuestro cliente DEBERÁ poder comportarse adecuadamente al lidiar con cualquier posible resultado del servidor al intentar conectarse.
Teoría de categorías en MQL5 (Parte 22): Una mirada distinta a las medias móviles Teoría de categorías en MQL5 (Parte 22): Una mirada distinta a las medias móviles
En el presente artículo intentaremos simplificar los conceptos tratados en esta serie centrándonos en solo un indicador, el más común y probablemente el más fácil de entender: la media móvil. También veremos el significado y las posibles aplicaciones de las transformaciones naturales verticales.
Teoría de categorías en MQL5 (Parte 21): Transformaciones naturales con ayuda de LDA Teoría de categorías en MQL5 (Parte 21): Transformaciones naturales con ayuda de LDA
Este artículo, el número 21 de nuestra serie, continuaremos analizando las transformaciones naturales y cómo se pueden implementar mediante el análisis discriminante lineal. Como en el artículo anterior, la implementación se presentará en formato de clase de señal.