English Русский Português
preview
Algoritmo de Aprendizaje Competitivo — Competitive Learning Algorithm (CLA)

Algoritmo de Aprendizaje Competitivo — Competitive Learning Algorithm (CLA)

MetaTrader 5Trading |
21 0
Andrey Dik
Andrey Dik

Contenido

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


Introducción

En las últimas décadas, se han propuesto muchos algoritmos bioinspirados, desde colonias de hormigas y enjambres de partículas hasta lobos grises y ballenas. Sin embargo, la sociedad humana, con sus complejas interacciones sociales, también puede servir como una rica fuente de ideas para crear métodos de optimización eficaces. Esta idea es la base del Algoritmo de Aprendizaje Competitivo (CLA).

El CLA utiliza una metáfora del proceso educativo, donde la población de soluciones está representada por estudiantes organizados en clases. El algoritmo modela de forma elegante tres tipos de aprendizaje: el aprendizaje del mejor alumno de la clase (el profesor), el aprendizaje a partir de la experiencia personal y el aprendizaje mediante la interacción entre clases. Este enfoque ofrece un equilibrio entre la exploración del espacio de búsqueda y el aprovechamiento de las buenas soluciones encontradas, lo cual resulta fundamental para una optimización eficaz.

En este artículo, analizaremos con detalle los principios del CLA, su base matemática y sus características de implementación, y compararemos su eficacia con otras metaheurísticas populares en nuestras funciones de prueba estándar.


Implementación del algoritmo

El CLA se basa en una metáfora del proceso educativo escolar. En esta metáfora, los estudiantes representan posibles soluciones al problema de optimización, las clases son grupos de estudiantes, los profesores son los mejores estudiantes de cada clase, el conocimiento corresponde a las coordenadas en el espacio de búsqueda y la evaluación se define por el valor de la función de aptitud.

El algoritmo comienza con una inicialización, que podemos comparar con el inicio del año escolar. Luego se crea una población de, por ejemplo, 198 estudiantes, que se dividen en 9 clases de 22 estudiantes cada una. A cada estudiante se le asigna aleatoriamente un "conocimiento" inicial: las coordenadas en el espacio de búsqueda.

El proceso de aprendizaje es iterativo y, con cada iteración, los estudiantes aprenden de tres maneras diferentes. El primer método es el aprendizaje dirigido por el profesor, donde cada estudiante aprende del mejor de su clase, y cuanto peor sea el rendimiento de la clase, más activo será el proceso de aprendizaje, pero con el tiempo la intensidad del aprendizaje disminuye para todos. El segundo método es el aprendizaje personal, que comienza solo después de la cuarta iteración. En este modo, el estudiante recuerda sus mejores resultados de las últimas cuatro "lecciones" e intenta volver a alcanzar su mejor marca personal. El tercer método consiste en aprender de otras clases, lo que también comienza después de la cuarta iteración. Existe un 50% de probabilidad de que un estudiante pueda aprender de un "profesor promedio" en todas las clases, lo cual ayuda a evitar quedarse estancado en óptimos locales.

Tras cada ciclo de entrenamiento, se evalúa el progreso. Después se identifica al mejor estudiante de cada clase, que se convierte en el profesor; se calcula la calificación general de la clase considerando el rendimiento de todos los estudiantes; y se actualiza la mejor solución encontrada a nivel global.

El algoritmo usa cinco parámetros clave:

  • popSize — define el número total de estudiantes,
  • numClasses — especifica el número de clases,
  • beta — regula la influencia de todos los estudiantes de una clase en su calificación general,
  • gamma — umbral que determina el aprendizaje a partir de otras clases,
  • deltaIter — especifica después de qué iteración comienza el aprendizaje extendido utilizando la experiencia personal y las interacciones entre clases.

El algoritmo implementa varios mecanismos inteligentes. Los factores de aprendizaje adaptativo ofrecen un aprendizaje más intensivo para las clases con menor rendimiento y una desaceleración gradual del aprendizaje con el tiempo, tal como ocurre en el proceso educativo real. El equilibrio entre exploración y explotación se logra mediante la exploración activa en las etapas iniciales, seguida de un enfoque en las mejores soluciones encontradas. El mecanismo de memoria permite que el algoritmo recuerde la historia de cada estudiante y, si es necesario, vuelva a soluciones buenas encontradas anteriormente.

Matemáticamente, la actualización del conocimiento de un estudiante puede representarse como la suma de varios componentes: la lección del profesor de la clase, la experiencia personal de la historia y el conocimiento recibido del profesor promedio de todas las clases. Esta fórmula ofrece un equilibrio entre seguir al líder, utilizar la experiencia personal y explorar nuevas áreas.

En definitiva, la eficacia del algoritmo está determinada por varios factores. La diversidad se logra usando múltiples clases que exploran diferentes direcciones en el espacio de búsqueda. La competencia entre los estudiantes por un puesto de profesor estimula la mejora de las soluciones. La cooperación mediante el intercambio de conocimientos entre clases busca prevenir la convergencia prematura. La adaptabilidad ofrece ayuda adicional para las clases débiles, mientras que el mecanismo de memoria almacena información sobre las buenas soluciones.

CLA_L

Figura 1. Esquema del funcionamiento del algoritmo

La ilustración del funcionamiento del algoritmo describe tres pasos principales: la inicialización, la fase de entrenamiento y la evaluación con actualización. Ahora vamos a escribir el pseudocódigo para el algoritmo CLA_L.

LO QUE NECESITAMOS CON ANTELACIÓN:
- 198 estudiantes (nuestras soluciones)
- 9 clases (grupos para estudiantes)
- Parámetro β = 0,9 (¿cuán importantes son todos los estudiantes en la clase?)
- Parámetro γ = 0,5 (probabilidad de aprender de otras clases)
- Después de la cuarta iteración, incluimos los tipos de entrenamiento adicionales.
- La función para evaluar la calidad de la solución

COMENCEMOS:

1. CREANDO UNA ESCUELA:
   - Distribuimos 198 estudiantes en 9 clases (22 en cada una).
   - A cada estudiante le asignamos una posición inicial aleatoria en el espacio.
   - En cada clase elegimos al mejor estudiante; este se convierte en profesor.
   - Creamos un registro para anotar la historia de cada estudiante.

2. PROCESO DE APRENDIZAJE (proceso iterativo):
   
   Paso 1: Determinamos la intensidad del entrenamiento
   - Para cada clase calculamos con qué intensidad necesitan trabajar los estudiantes
   - Las clases débiles (es decir, con mala clasificación) estudian con más intensidad.
   - Con el tiempo, todos estudian con menos intensidad (como en la vida real).
   
   Segundo paso: Encontramos el "profesor promedio"
   - Tomamos las posiciones de todos los profesores
   - Calculamos su valor promedio
   - Este será el estándar de conocimiento para toda la escuela.
   
   Paso 3: Cada estudiante aprende:
   
   Por cada estudiante hacemos lo siguiente:
   
   a) SIEMPRE aprendemos de nuestro profesor:
      - Vemos dónde está nuestro profesor.
      - Nos acercamos a él.
      - La velocidad del movimiento depende del factor de entrenamiento de la clase.
   
   b) Después de la cuarta iteración, recordamos nuestra experiencia:
      - Analizamos el diario: ¿en qué posición obtuve mi mejor resultado durante las últimas 4 lecciones?
      - Con una cierta fuerza aleatoria volvemos a esa posición.
      - Esto nos ayudará a no olvidar las buenas soluciones.
   
   c) Después de la cuarta iteración, aprendemos de otras clases:
      - Lanzamos una moneda (con un 50% de probabilidad)
      - Si sale cruz, miramos al "profesor promedio".
      - Nos movemos ligeramente en su dirección
      - Esto nos ayuda a intercambiar experiencias entre clases.
   
   Paso 4: Evaluamos a todos los estudiantes.
   - Cada estudiante recibe una calificación de aptitud (fitness).
   - Cuanto mejor sea la posición, mayor será la puntuación.
   
   Paso 5: Actualizamos la jerarquía escolar
   
   Para cada clase:
   - Encontramos un nuevo estudiante destacado: se convierte en profesor.
   - Calculamos el nivel general de la clase:
     * Tomamos en cuenta la evaluación del profesor.
     * Sumamos la puntuación media de todos los estudiantes (multiplicada por β)
   - Determinamos la puntuación total de la clase:
     * Las mejores clases obtienen una clasificación baja (1, 2, 3...).
     * Las peores clases obtienen la puntuación total alta
   
   Paso 6: Recordamos la mejor solución
   - Si algún profesor es mejor que nuestro récord
   - Lo guardaremos como un nuevo récord.
   
   Paso 7: Guardamos la historia.
   - Mantenemos las posiciones actuales de todos los estudiantes.
   - Esto será necesario para el aprendizaje personal.

3. FINALIZAMOS:
   - Retornamos la mejor solución encontrada.
   - Y su valoración.

Ahora comenzaremos a escribir el código del algoritmo. La clase "C_AO_CLA_l" hereda de la clase "C_AO" (clase padre) e implementa un algoritmo basado en el concepto de aprendizaje competitivo. La clase contiene una serie de parámetros configurables por el usuario:

  • popSize — tamaño de la población (número de "agentes" o "estudiantes");
  • numClasses — número de clases en las que se dividen los agentes;
  • beta — parámetro que probablemente influye en la velocidad de aprendizaje o adaptación;
  • gamma — otro parámetro que probablemente esté relacionado con el aprendizaje;
  • deltaIter — frecuencia de ejecución de ciertos pasos del algoritmo (en iteraciones).

El constructor inicializa los parámetros principales, establece el nombre y la descripción del algoritmo, especifica los valores predeterminados para las variables y dimensiona el array "params", que está destinado a almacenar información sobre los parámetros del algoritmo.

Métodos:

  • SetParams () — actualiza los valores de las variables internas de la clase (parámetros del algoritmo) utilizando los valores del array "params". Esto permite cambiar parámetros configurados externamente.
  • Init () — inicializa el algoritmo. Acepta parámetros para definir los límites y el paso para cambiar los parámetros.
  • Moving () — método principal para "mover" los agentes (realizando iteraciones y pasos del algoritmo).
  • Revision () — el método está asociado con la corrección o mejora de las soluciones.
  • Injection () — método para insertar nuevos conocimientos o datos en un agente.
Campos de clase:
  • numClasses, beta, gamma, deltaIter — parámetros del algoritmo.
  • currentIter, studentsPerClass, totalIters — variables internas para controlar el desarrollo del algoritmo.
  • teachers[] — array de estructuras "S_AO_Agent" que representan a los "profesores" en cada clase (puntos de referencia).
  • classRanks[] — clasificaciones de clase que reflejan su rendimiento.
  • classTotalCosts[] — costos totales o "costo" de cada clase.
  • CL[] — array temporal para calcular el conocimiento promedio de los profesores.
  • UpdateTeachersAndCosts() — método interno para actualizar la información sobre los profesores y sus costos.
  • UpdateClassRanks() — método interno para actualizar las clasificaciones de las clases.
  • UpdateStudentsKnowledge() — método interno para actualizar los parámetros de conocimiento o "estudiantes".
//————————————————————————————————————————————————————————————————————
class C_AO_CLA_l : public C_AO
{
  public: //----------------------------------------------------------
  ~C_AO_CLA_l () { }
  C_AO_CLA_l ()
  {
    ao_name = "CLA_L";
    ao_desc = "Competitive Learning Algorithm";
    ao_link = "https://www.mql5.com/en/articles/18857";

    popSize        = 198;
    numClasses     = 3;
    beta           = 0.3;
    gamma          = 0.8;
    deltaIter      = 2;

    ArrayResize (params, 5);

    params [0].name = "popSize";     params [0].val = popSize;
    params [1].name = "numClasses";  params [1].val = numClasses;
    params [2].name = "beta";        params [2].val = beta;
    params [3].name = "gamma";       params [3].val = gamma;
    params [4].name = "deltaIter";   params [4].val = deltaIter;
  }

  void SetParams ()
  {
    popSize    = (int)params [0].val;
    numClasses = (int)params [1].val;
    beta       = params      [2].val;
    gamma      = params      [3].val;
    deltaIter  = (int)params [4].val;
  }

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

  void Moving   ();
  void Revision ();
  void Injection (const int popPos, const int coordPos, const double value) { }

  //------------------------------------------------------------------
  int    numClasses;
  double beta;
  double gamma;
  int    deltaIter;

  private: //---------------------------------------------------------
  int    currentIter;
  int    studentsPerClass;
  int    totalIters;

  // Structures for classes
  S_AO_Agent teachers        [];
  double     classRanks      [];
  double     classTotalCosts [];

  // Temporary array
  double     CL [];             // Average knowledge of teachers

  // Auxiliary methods
  void   UpdateTeachersAndCosts  ();
  void   UpdateClassRanks        ();
  void   UpdateStudentsKnowledge ();
};
//————————————————————————————————————————————————————————————————————

El método "Init()" de la clase "C_AO_CLA_l" inicializa el algoritmo antes de que comience a funcionar. La lógica del trabajo se divide en varias etapas. Standard Initialization: se llama al método "StandardInit()" y se realiza la inicialización estándar para el algoritmo de optimización. Se le pasan los parámetros "rangeMinP", "rangeMaxP" y el paso "rangeStepP". Si la inicialización estándar falla, el método Init() devuelve "false".

Initialization of Algorithm Parameters: restablece el contador de iteraciones actual a "0", establece el número total de iteraciones que el algoritmo debe realizar utilizando el valor pasado en el argumento "epochsP", calcula el número de "estudiantes" (agentes) en cada clase dividiendo el tamaño de la población por el número de clases. A continuación, el método comprueba que haya al menos un estudiante en cada clase. Luego el ciclo "for" inicializa a cada agente de la población. Para cada agente en el array "a", se llama al método "Init()". El método consiste en inicializar el número de coordenadas para cada agente.

El ciclo "for" inicializa un "profesor" para cada clase, establece la clasificación de cada clase en "1.0" y establece el "costo" inicial de cada clase en un valor máximo negativo para garantizar que se encuentre una mejor solución más adelante. Si todos los pasos de inicialización se realizan correctamente, el método devuelve "true".

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

  //------------------------------------------------------------------
  currentIter = 0;
  totalIters = epochsP;
  studentsPerClass = popSize / numClasses;

  if (studentsPerClass < 1)
  {
    Print ("Error: Too few students per class");
    return false;
  }

  // Adjust the population size
  //spopSize = studentsPerClass * numClasses;
  ArrayResize (a, popSize);
  for (int i = 0; i < popSize; i++) a [i].Init (coords);

  // Initialize class structures
  ArrayResize (teachers, numClasses);
  ArrayResize (classRanks, numClasses);
  ArrayResize (classTotalCosts, numClasses);

  for (int i = 0; i < numClasses; i++)
  {
    teachers        [i].Init (coords);
    classRanks      [i] = 1.0;
    classTotalCosts [i] = -DBL_MAX;
  }

  // Temporary array
  ArrayResize (CL, coords);

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

El método "Moving()" de la clase "C_AO_CLA_l" implementa una iteración del algoritmo de optimización principal, comprueba si es la primera iteración y, si lo es (es decir, "revision" es false), el método inicializa las posiciones de todos los agentes de la población con valores aleatorios en el rango dado. Itera sobre todos los agentes de la población y, para cada agente, itera sobre todas sus coordenadas.

Para cada coordenada, el método genera un valor aleatorio "val" en el rango de "rangeMin[c]" a "rangeMax[c]" usando el método "u.RNDfromCI()", que proporciona una función para generar números aleatorios. Este asigna el valor "val" a la coordenada "a[i].c[c]" del agente "i", habiéndola "recortado" previamente para que se encuentre dentro del rango aceptable y corresponda al paso dado "rangeStep[c]". Luego se utiliza el método "u.SeInDiSp()", que realiza la comprobación y el ajuste de valores.

Tras inicializar la población, se establece una bandera para señalar que la inicialización se ha realizado correctamente. Si no se trata de la primera iteración, aumenta el contador de iteraciones actual. Llama al método "UpdateStudentsKnowledge()", que implementa el mecanismo principal para el aprendizaje o la adaptación de los agentes según los principios de aprendizaje competitivo usados en el algoritmo "CLA_L". La lógica de este método determina cómo interactúan los agentes, intercambian información y mejoran sus posiciones en el espacio de búsqueda de soluciones.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::Moving ()
{
  // Initial population setup
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        double val = u.RNDfromCI (rangeMin [c], rangeMax [c]);
        a [i].c [c] = u.SeInDiSp (val, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
    revision = true;
    return;
  }

  currentIter++;

  // Update students' knowledge
  UpdateStudentsKnowledge ();
}
//————————————————————————————————————————————————————————————————————

El método "UpdateStudentsKnowledge()" se encarga de actualizar la posición de cada estudiante (agente) durante el proceso de optimización. Luego se calcula el progreso actual de la optimización. Y se calculan dos factores clave de aprendizaje:

  • TF  (Teaching Factor) — muestra cuánto aprende un estudiante de un profesor.
  • CF  (Confirmatory Factor) — muestra hasta qué punto un estudiante tiene en cuenta el conocimiento promedio de los profesores. Estos factores dependen del progreso de la optimización y de la puntuación total de la clase del estudiante.

A continuación, se calcula el valor medio de las coordenadas de todos los profesores “activos” (profesores cuyos resultados son válidos). Este conocimiento promedio se almacena en un array temporal. Para cada estudiante (agente), se determina la clase a la que pertenece, y para cada coordenada del estudiante, se calcula una nueva posición del estudiante sumando la coordenada actual con las "fuentes de conocimiento". El estudiante aprende de su profesor ajustando su posición en una cantidad proporcional a la diferencia entre la coordenada del profesor y la suya propia, multiplicada por TF. Si han transcurrido suficientes iteraciones (currentIter > deltaIter) y el estudiante tiene una "mejor solución", entonces aprende de su experiencia previa exitosa ajustando su posición hacia la mejor coordenada, multiplicada por un factor aleatorio.

Si han transcurrido suficientes iteraciones y el número de profesores es válido, el estudiante aprende del conocimiento promedio de todos los profesores, ajustando su posición en la dirección de la coordenada promedio multiplicada por "CF" con una cierta probabilidad (1-gamma). Luego se aplican límites (restricciones) a cada coordenada del estudiante para garantizar que el valor se encuentre dentro del rango aceptable. El valor se ajusta para que coincida con los valores aceptables dado el paso de discretización del espacio de búsqueda.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::UpdateStudentsKnowledge ()
{
  // Calculate learning factors for the current iteration
  double progress = (double)currentIter / (double)MathMax (totalIters, 100);

  // Calculate the average knowledge of all teachers (CL)
  ArrayInitialize (CL, 0.0);
  int validTeachers = 0;

  for (int k = 0; k < numClasses; k++)
  {
    // Make sure the teacher is initialized
    if (teachers [k].f > -DBL_MAX)
    {
      for (int c = 0; c < coords; c++)
      {
        CL [c] += teachers [k].c [c];
      }
      validTeachers++;
    }
  }

  if (validTeachers > 0)
  {
    for (int c = 0; c < coords; c++)
    {
      CL [c] /= validTeachers;
    }
  }

  // Update each student
  for (int i = 0; i < popSize; i++)
  {
    int classIdx = i / studentsPerClass;

    // Teaching Factor - decreases with progress
    double TF = MathExp (-0.6 * progress * classRanks [classIdx]);
    TF = MathMax (0.1, MathMin (1.0, TF));

    // Confirmatory Factor
    double CF = MathExp (-0.5 * progress * classRanks [classIdx]);
    CF = MathMax (0.1, MathMin (1.0, CF));

    // Update the student position
    for (int c = 0; c < coords; c++)
    {
      double newPos = a [i].c [c];

      // a) Teacher Learning - learn from the class teacher
      if (teachers [classIdx].f > -DBL_MAX)
      {
        newPos += TF * (teachers [classIdx].c [c] - a [i].c [c]);
      }

      // b) Personal Learning - learn from your best solution
      if (currentIter > deltaIter && a [i].fB > -DBL_MAX)
      {
        double PF = u.RNDprobab ();
        newPos += PF * (a [i].cB [c] - a [i].c [c]);
      }

      // c) Confirmatory Learning - learn from the average of all teachers
      if (currentIter > deltaIter && validTeachers > 0)
      {
        double rnd = u.RNDprobab ();
        if (rnd >= gamma) // Participate with probability (1-gamma)
        {
          newPos += CF * (CL [c] - a [i].c [c]);
        }
      }

      // Apply borders
      a [i].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//————————————————————————————————————————————————————————————————————

El método "Revision()" de la clase "C_AO_CLA_l" se usa para actualizar la información sobre las mejores soluciones de cada agente, así como para actualizar la mejor solución global y los parámetros correspondientes.

Para cada agente, se comprueba si su función objetivo actual (a[i].f) ha mejorado en comparación con su mejor valor recordado (a[i].fB). En ese caso, se guarda el mejor valor y se copian las coordenadas correspondientes. Tras comprobar todos los agentes, si alguno de ellos obtiene un valor de función mejor que el máximo global actual (fB), se actualizan los parámetros globales: fB es el mejor valor de función global, mientras que cB son las coordenadas de esta mejor solución.

A continuación, se llama al método "UpdateTeachersAndCosts()", que actualiza la información sobre los mejores profesores. Al final, se llama a "UpdateClassRanks()" para recalcular las clasificaciones de las clases, lo cual influye en la prioridad de elección de ciertas soluciones en iteraciones posteriores.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::Revision ()
{
  for (int i = 0; i < popSize; i++)
  {
    // Update personal best positions
    if (a [i].f > a [i].fB)
    {
      a [i].fB = a [i].f;
      ArrayCopy (a [i].cB, a [i].c);
    }
    // Update the global best one
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ArrayCopy (cB, a [i].c);
    }
  }

  // Update teachers 
  UpdateTeachersAndCosts ();

  // Update class ranks
  UpdateClassRanks ();
}
//————————————————————————————————————————————————————————————————————

El método "UpdateTeachersAndCosts()" se usa para actualizar la información sobre los profesores de cada clase y calcular el "costo" total de la clase. El método itera todas las clases definidas en el sistema. Para cada clase, se determinan los índices inicial y final de los estudiantes (agentes) incluidos en dicha clase.

Para encontrar al mejor estudiante de la clase, se inicializan variables para almacenar el mejor valor de la función, el índice del mejor estudiante, la suma de los valores de la función de todos los estudiantes de la clase y el número de estudiantes válidos. El ciclo se repite con todos los estudiantes de la clase actual. Para cada estudiante, se comprueba si su solución es válida y, si lo es, entonces: el valor de la función de este estudiante se suma a "sumFitness", se incrementa el contador de estudiantes válidos y, si el valor de la función del estudiante actual es mejor que el mejor valor actual "bestFitness", entonces se actualiza y se actualiza "bestIdx".

Después de encontrar al mejor estudiante de la clase, se comprueba que haya habido al menos un estudiante válido en la clase (validStudents > 0). Si se cumple la condición, las coordenadas del mejor estudiante se copian a las coordenadas del profesor de la clase correspondiente, mientras que el valor de la función del mejor estudiante se asigna al valor de la función del profesor.

Luego se calcula el valor promedio de la función de todos los estudiantes de la clase "avgFitness". El "costo" total de la clase se calcula como la suma del valor de la función del mejor estudiante y el producto del coeficiente "beta" por el valor medio de la función de todos los estudiantes. Es una combinación de la eficacia del profesor y el rendimiento medio de la clase.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA::UpdateTeachersAndCosts ()
{
  for (int k = 0; k < numClasses; k++)
  {
    int startIdx = k * studentsPerClass;
    int endIdx = startIdx + studentsPerClass;

    double bestFitness = -DBL_MAX;
    int bestIdx = startIdx;
    double sumFitness = 0.0;
    int validStudents = 0;

    // Find the best student (teacher) in the class
    for (int i = startIdx; i < endIdx; i++)
    {
      if (a[i].f > -DBL_MAX) // Validity check
      {
        sumFitness += a[i].f;
        validStudents++;
        
        if (a[i].f > bestFitness)
        {
          bestFitness = a[i].f;
          bestIdx = i;
        }
      }
    }

    // Update the teacher
    if (validStudents > 0)
    {
      ArrayCopy (teachers[k].c, a[bestIdx].c);
      teachers[k].f = bestFitness;
      
      // Calculate the class total cost
      double avgFitness = sumFitness / validStudents;
      classTotalCosts[k] = bestFitness + beta * avgFitness;
    }
  }
}
//————————————————————————————————————————————————————————————————————

El método "UpdateClassRanks()" se usa para determinar la clasificación de las clases en función de su "costo" general, que caracteriza la eficacia de la clase. El proceso del método comienza por encontrar el costo mínimo y máximo entre todas las clases válidas. Si todas las clases tienen el mismo valor, o no hay clases válidas, entonces se establece el mismo rango de 1 para todas.

Si existen diferencias de costo, estos valores se normalizan: cada costo se ajusta a un rango de 0 a 1. Después de esto, se realiza una inversión: las clases con un costo mayor reciben una clasificación inferior, cercana a 1, y las que tienen un costo menor reciben una clasificación máxima igual al número de clases.

A continuación, cada valor de clasificación se limita a un valor mínimo y máximo para evitar valores fuera de los límites establecidos. En definitiva, basándose en los resultados de este método, se asignan clasificaciones a las clases según su rendimiento.

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::UpdateClassRanks ()
{
  // Find the min and max costs among valid classes
  double minCost   = DBL_MAX;
  double maxCost   = -DBL_MAX;
  int validClasses = 0;

  for (int k = 0; k < numClasses; k++)
  {
    if (classTotalCosts [k] > -DBL_MAX)
    {
      if (classTotalCosts [k] < minCost) minCost = classTotalCosts [k];
      if (classTotalCosts [k] > maxCost) maxCost = classTotalCosts [k];
      validClasses++;
    }
  }

  if (validClasses == 0 || maxCost - minCost < 1e-10)
  {
    // All classes have the same score
    for (int k = 0; k < numClasses; k++) classRanks [k] = 1.0;
  }
  else
  {
    // Ranking: best classes (high cost) get low rank
    for (int k = 0; k < numClasses; k++)
    {
      if (classTotalCosts [k] > -DBL_MAX)
      {
        // Normalize from 0 to 1
        double normalized = (classTotalCosts [k] - minCost) / (maxCost - minCost);

        // Inversion: the best get a rank close to 1
        classRanks [k] = 1.0 + (1.0 - normalized) * (numClasses - 1.0);

        // Limitation
        classRanks [k] = MathMax (1.0, MathMin ((double)numClasses, classRanks [k]));
      }
      else
      {
        classRanks [k] = numClasses; // Worst rank for uninitialized
      }
    }
  }
}
//————————————————————————————————————————————————————————————————————


Resultados de las pruebas

Según los resultados de las pruebas, el algoritmo CLA_L ha obtenido resultados decentes.

CLA_L|Competitive Learning Algorithm|198.0|3.0|0.3|0.8|2.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.6482993681242128
25 Hilly's; Func runs: 10000; result: 0.5535249826770444
500 Hilly's; Func runs: 10000; result: 0.2584959913710746
=============================
5 Forest's; Func runs: 10000; result: 0.8027208362980616
25 Forest's; Func runs: 10000; result: 0.49540442971179494
500 Forest's; Func runs: 10000; result: 0.20048686632188017
=============================
5 Megacity's; Func runs: 10000; result: 0.6353846153846153
25 Megacity's; Func runs: 10000; result: 0.2716923076923076
500 Megacity's; Func runs: 10000; result: 0.10086153846153936
=============================
All score: 3.96687 (44.08%)

La visualización muestra que el algoritmo inicialmente tiene buenas capacidades de búsqueda, las cuales se deterioran al quedar atrapado en óptimos locales, lo que lleva a un estancamiento en la segunda mitad de la ejecución del algoritmo.

Hilly

CLA_L en la función de prueba Hilly

Forest

CLA_L en la función de prueba Forest

Megacity

CLA_L en la función de prueba Megacity

Basándonos en los resultados del algoritmo, le presentamos la tabla comparativa; CLA_L se muestra con fines informativos.

AO Description Hilly Hilly
Final
Forest Forest
Final
Megacity (discrete) Megacity
Final
Final
Result
% of
MAX
10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F)
1 ANS across neighbourhood search 0,94948 0,84776 0,43857 2,23581 1,00000 0,92334 0,39988 2,32323 0,70923 0,63477 0,23091 1,57491 6,134 68,15
2 CLA code lock algorithm (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 TETA time evolution travel algorithm (joo) 0,91362 0,82349 0,31990 2,05701 0,97096 0,89532 0,29324 2,15952 0,73462 0,68569 0,16021 1,58052 5,797 64,41
7 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
8 BOAm billiards optimization algorithm M 0,95757 0,82599 0,25235 2,03590 1,00000 0,90036 0,30502 2,20538 0,73538 0,52523 0,09563 1,35625 5,598 62,19
9 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
10 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
11 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
12 EOm extremal_optimization_M 0,76166 0,77242 0,31747 1,85155 0,99999 0,76751 0,23527 2,00277 0,74769 0,53969 0,14249 1,42987 5,284 58,71
13 BBO biogeography based optimization 0,94912 0,69456 0,35031 1,99399 0,93820 0,67365 0,25682 1,86867 0,74615 0,48277 0,17369 1,40261 5.265 58,50
14 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
15 DA dialectical algorithm 0,86183 0,70033 0,33724 1,89940 0,98163 0,72772 0,28718 1,99653 0,70308 0,45292 0,16367 1,31967 5,216 57,95
16 BHAm black hole algorithm M 0,75236 0,76675 0,34583 1,86493 0,93593 0,80152 0,27177 2,00923 0,65077 0,51646 0,15472 1,32195 5.196 57.73
17 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
18 RFO royal flush optimization (joo) 0,83361 0,73742 0,34629 1,91733 0,89424 0,73824 0,24098 1,87346 0,63154 0,50292 0,16421 1,29867 5,089 56,55
19 AOSm búsqueda de orbitales atómicos M 0,80232 0,70449 0,31021 1,81702 0,85660 0,69451 0,21996 1,77107 0,74615 0,52862 0,14358 1,41835 5,006 55,63
20 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
21 BSA backtracking_search_algorithm 0,97309 0,54534 0,29098 1,80941 0,99999 0,58543 0,21747 1,80289 0,84769 0,36953 0,12978 1,34700 4.959 55.10
22 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
23 SRA successful restaurateur algorithm (joo) 0,96883 0,63455 0,29217 1,89555 0,94637 0,55506 0,19124 1,69267 0,74923 0,44031 0,12526 1,31480 4,903 54,48
24 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
25 BIO blood inheritance optimization (joo) 0,81568 0,65336 0,30877 1,77781 0,89937 0,65319 0,21760 1,77016 0,67846 0,47631 0,13902 1,29378 4,842 53,80
26 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
27 DEA dolphin_echolocation_algorithm 0,75995 0,67572 0,34171 1,77738 0,89582 0,64223 0,23941 1,77746 0,61538 0,44031 0,15115 1,20684 4.762 52,91
28 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
29 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
30 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
31 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
32 (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
33 FBA fractal-based Algorithm 0,79000 0,65134 0,28965 1,73099 0,87158 0,56823 0,18877 1,62858 0,61077 0,46062 0,12398 1,19537 4.555 50,61
34 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
35 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
36 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
37 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
38 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
39 CAm camel algorithm M 0,78684 0,56042 0,35133 1,69859 0,82772 0,56041 0,24336 1,63149 0,64846 0,33092 0,13418 1,11356 4.444 49.37
40 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
41 CMAES covariance_matrix_adaptation_evolution_strategy 0,76258 0,72089 0,00000 1,48347 0,82056 0,79616 0,00000 1,61672 0,75846 0,49077 0,00000 1,24923 4.349 48.33
42 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
43 SOA simple optimization algorithm 0,91520 0,46976 0,27089 1,65585 0,89675 0,37401 0,16984 1,44060 0,69538 0,28031 0,10852 1,08422 4.181 46,45
44 ABHA artificial bee hive algorithm 0,84131 0,54227 0,26304 1,64663 0,87858 0,47779 0,17181 1,52818 0,50923 0,33877 0,10397 0,95197 4.127 45,85
45 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
CLA_L competitivelearningalgorithm 0,64829 0,55352 0,25849 1,46030 0,80272 0,49540 0,20048 1,49860 0,63538 0,27169 0,10086 1,00793 3,967 44,08
RW random walk 0,48754 0,32159 0,25781 1,06694 0,37554 0,21944 0,15877 0,75375 0,27969 0,14917 0,09847 0,52734 2.348 26,09


Conclusiones

El algoritmo de aprendizaje competitivo (CLA_L) demuestra un rendimiento promedio en la resolución de problemas de optimización estándar. El análisis del funcionamiento del algoritmo ha revelado una dinámica característica de dos fases: una fase de exploración activa en las iteraciones iniciales y una fase de estancamiento prematuro en la segunda mitad del proceso de optimización.

La división de la población en clases garantiza una buena cobertura del espacio de búsqueda en las primeras etapas. Cada clase explora su propia área, lo cual contribuye a una búsqueda global. El modelo educativo hace que el algoritmo sea claro y fácil de interpretar. Los conceptos de profesores, estudiantes y diferentes tipos de aprendizaje son fáciles de comprender. En teoría, los factores de aprendizaje que dependen de la puntuación total en la clase deberían ofrecer un equilibrio entre la exploración y la explotación. La combinación de tres tipos de aprendizaje (dirigido por el profesor, personal y confirmatorio) crea el potencial para evitar óptimos locales. A pesar de los mecanismos de diversificación, el algoritmo tiende a quedarse atascado en óptimos locales. 

El algoritmo CLA presenta un concepto interesante que consiste en aplicar una metáfora educativa a problemas de optimización. A pesar del enfoque innovador y el buen rendimiento inicial, el algoritmo necesita modificaciones significativas para poder competir con las metaheurísticas modernas. El principal reto sigue siendo garantizar un equilibrio entre la exploración y la explotación a lo largo de todo el proceso de optimización.

tab

Figura 2. Clasificación por colores de los algoritmos según las pruebas respectivas

chart

Figura 3. Histograma de los resultados de las pruebas de algoritmos (en una escala de 0 a 100, cuanto más mejor, donde 100 es el máximo resultado teórico posible, el script para calcular la tabla de puntuación está en el archivo)

Ventajas e inconvenientes del algoritmo CLA_L:

Ventajas:

  1. Es rápido.

Desventajas:

  1. Gran número de parámetros externos.
  2. Tendencia a quedarse atascado en las tareas.

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 base 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
Simple use of population optimization algorithms.mq5
Script
Ejemplo sencillo de utilización de algoritmos de optimización basados en la población sin visualización
9
Test_AO_CLA_L.mq5
Script Banco de pruebas para CLA_L

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

Archivos adjuntos |
CLA_l.ZIP (317.9 KB)
Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
De novato a experto: Revelando las sombras de las velas japonesas (mechas) De novato a experto: Revelando las sombras de las velas japonesas (mechas)
En este análisis, damos un paso adelante para descubrir la acción del precio subyacente que se esconde tras las mechas de las velas japonesas. Al integrar una función de visualización de mechas en el Market Periods Synchronizer, mejoramos la herramienta con mayor profundidad analítica e interactividad. Este sistema mejorado permite a los traders visualizar los rechazos de precios en marcos temporales superiores directamente en gráficos de marcos temporales inferiores, revelando estructuras detalladas que antes estaban ocultas.
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 multidimensional de extremo a extremo para la previsión de series temporales (Final) Redes neuronales en el trading: Modelo multidimensional de extremo a extremo para la previsión de series temporales (Final)
Les presentamos la parte final de la serie dedicada a GinAR, un framework de red neuronal para la predicción de series temporales. En este artículo, vamos a analizar los resultados de las pruebas realizadas al modelo con datos nuevos y a evaluar su robustez en condiciones reales de mercado.