Optimización por comunidad de científicos — Community of Scientist Optimization (CoSO): Práctica
Índice:
Implementación del algoritmo
Hoy continuaremos con la descripción de la implementación del algoritmo, que iniciamos en la primera parte del artículo, y presentaremos también los resultados de las pruebas experimentales realizadas con funciones de prueba especializadas.
La función «AssignFunds» describe el mecanismo de distribución de los «fondos» disponibles entre los investigadores en el algoritmo CoSO. Estos fondos representan oportunidades de aprendizaje, desplazamiento o participación en procesos posteriores, y su distribución influye en la dinámica de la evolución de las soluciones. La función recibe un único parámetro: «availableFunds», es decir, la cantidad total de fondos que hay que distribuir. Este proceso se divide en varias fases.
División de los fondos en dos partes. Se calcula «outsiderFunds», es decir, la parte de los fondos destinada a los investigadores «outsiders». La cantidad de estos fondos se determina como una fracción del total de «availableFunds», donde «omegaCurrent» (parámetro que controla la proporción de fondos destinados a los outsiders) actúa como coeficiente. Los fondos restantes, «existingFunds», se destinan a su distribución entre los investigadores activos.Distribución de fondos entre los investigadores existentes. Esta parte solo se ejecuta si existe un «informe global» (globalReport) y si su tamaño es mayor que cero; entonces se calcula «totalRank», la suma de todos los rangos en una progresión aritmética desde «1» hasta «reportSize». En esencia, se trata de la suma de los coeficientes de ponderación que se utilizarán para el reparto proporcional de los fondos. A continuación, los fondos («existingFunds») se distribuyen unidad por unidad: para cada unidad de fondos se genera un número aleatorio, que se multiplica por «totalRank», y ese valor se utilizará para seleccionar al investigador. Después se itera sobre «globalReport».
Para cada entrada de «globalReport» se calcula la suma acumulada «cumSum», a la que se suma un «peso» igual a (reportSize - i). Esto significa que a los investigadores con posiciones más altas en el informe se les asigna un mayor peso y, por lo tanto, tienen más posibilidades de obtener fondos. Si el número aleatorio cae en el intervalo asociado al investigador actual (es decir, rnd <= cumSum), los fondos de dicho investigador aumentan en una unidad. A continuación, se interrumpe el ciclo de distribución del fondo actual y se pasa a la distribución del siguiente fondo.
Creación de outsiders. Para finalizar, se llama a la función «CreateOutsiders», a la que se le pasa «outsiderFunds». Esta función utiliza los fondos reservados para outsiders para crear nuevos investigadores o, en otras palabras, para iniciar nuevas vías de investigación.De este modo, «AssignFunds» implementa una estrategia de gestión de fondos que premia a los investigadores que han mostrado buenos resultados (a través de «existingFunds» y la distribución por rango) y, al mismo tiempo, fomenta la aparición de nuevas ideas o agentes (a través de «outsiderFunds»).
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::AssignFunds (int availableFunds) { // Fondos para los outsiders int outsiderFunds = (int)(availableFunds * omegaCurrent); int existingFunds = availableFunds - outsiderFunds; int reportSize = ArraySize (globalReport); // Asignación de fondos a los investigadores existentes if (reportSize > 0) { int totalRank = reportSize * (reportSize + 1) / 2; for (int f = 0; f < existingFunds; f++) { double rnd = u.RNDprobab () * totalRank; double cumSum = 0; for (int i = 0; i < reportSize; i++) { cumSum += reportSize - i; if (rnd <= cumSum) { researchers [globalReport [i].index].m++; break; } } } } // Creación de outsiders CreateOutsiders (outsiderFunds); } //————————————————————————————————————————————————————————————————————
La función «CreateOutsiders» describe el proceso de creación de nuevos «investigadores» en el marco del modelo CoSO, utilizando los fondos asignados específicamente a los «outsiders». Estos nuevos investigadores representan una diversidad potencial o nuevas ideas introducidas en el sistema. La función admite un único parámetro: «outsiderFunds», que es la cantidad de fondos destinados a la creación de «outsiders». Si «outsiderFunds» es menor o igual a cero, la función interrumpe inmediatamente su ejecución, ya que no hay fondos para crear «outsiders».
Determinación del número de nuevos investigadores. A continuación, se establece «maxNew»: el número máximo de nuevos outsiders que se pueden crear en este momento. Este valor depende del tamaño actual de la población. Si la población es grande (más de 100 elementos), «maxNew» es igual a 2 (para ralentizar el crecimiento). De lo contrario, «maxNew» es igual a 5. Se trata de un mecanismo de control del crecimiento de la población. Se determina el número real de nuevos investigadores que se crearán. Luego se selecciona aleatoriamente dentro de un rango que va desde uno hasta el valor mínimo entre «outsiderFunds» y «maxNew». Esto garantiza que el número de nuevos investigadores no supere los fondos disponibles ni el límite establecido; a continuación, se calcula la cantidad de fondos que recibirá cada nuevo investigador (simple división del total de «outsiderFunds» entre «newResearchers»).
Ciclo de creación de nuevos investigadores. La función ejecuta el ciclo «newResearchers» veces: primero se busca un espacio «libre» en el array existente de investigadores (researchers). Si se encuentra un espacio libre (idx != -1), se utiliza. Si no hay espacio libre, pero el tamaño actual de la población es inferior al tamaño máximo permitido (maxPopSize), se añade un nuevo espacio al final del array (idx = actualPopSize).
Ampliación del array (si es necesario). Si no hay espacio libre y «actualPopSize» ya es igual o superior a «maxPopSize», se comprueba si es posible aumentar el tamaño del array de investigadores. Si «actualPopSize» ya alcanza «maxPopSize», se calcula un nuevo tamaño máximo (newMaxSize) como «maxPopSize + 50», pero sin superar los 500. Este es otro mecanismo que limita el crecimiento de la población. Si se alcanza el límite absoluto de 500, se omite la iteración actual (no se crean nuevos outsiders). De lo contrario, «maxPopSize» se actualiza a «newMaxSize». Tras las comprobaciones, «idx» se establece en «actualPopSize» para utilizar el primer espacio nuevo. Si, por cualquier motivo, «idx» sigue siendo «-1» después de todos los intentos de buscar o crear un espacio, se omite la creación del investigador actual.
Inicialización de un nuevo investigador. Si el espacio «idx» se encuentra o se crea correctamente, «researchers [idx]. alive» se establece en «true», haciendo que el investigador sea marcado como activo; la cantidad de fondos, o «motivación», se establece en «fundsPerNew», y la «fuerza», o el valor inicial de otro parámetro, se inicializa con un número aleatorio.
Inicialización de las coordenadas (posición en el espacio de soluciones). Para cada coordenada «c» («coords»: número de dimensiones), la posición se inicializa con un número aleatorio dentro del intervalo especificado. A continuación, «researchers [idx]. x [c]» se ajusta considerando el paso de discretización mediante la función «SeInDiSp», y la «mejor» posición, que inicialmente es igual a la actual, también se establece en «researchers [idx]. x [c]». La velocidad o el vector de variación se inicializa con un número aleatorio extraído de una distribución normal con los parámetros especificados.
Inicialización de las probabilidades de las revistas científicas (de publicación). Para cada revista científica «j» («journalsNum»: número de revistas científicas), la probabilidad de publicación en la revista «j» se inicializa con un número aleatorio. A continuación, se llama a «NormalizeProbabilities» para «researchers [idx]. rho», con el fin de garantizar que la suma de todos los «rho» de ese investigador sea igual a uno.
Actualización del tamaño de la población. Si se ha añadido un nuevo investigador al final del array, «actualPopSize» se actualiza a «idx + 1».
De este modo, «CreateOutsiders» añade dinámicamente nuevos investigadores a la población, garantizando su inicialización aleatoria en el espacio de soluciones y distribuyendo entre ellos los fondos asignados. Los mecanismos de limitación «maxNew» y «maxPopSize» sirven para controlar el tamaño de la población, evitando que crezca indefinidamente.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::CreateOutsiders (int outsiderFunds) { if (outsiderFunds <= 0) return; // Limitamos el número de nuevos outsiders, sobre todo si la población ya es numerosa int maxNew = (actualPopSize > 100) ? 2 : 5; int newResearchers = (int)(u.RNDfromCI (1, MathMin (outsiderFunds, maxNew))); int fundsPerNew = outsiderFunds / newResearchers; for (int i = 0; i < newResearchers; i++) { // Buscamos un espacio libre int idx = -1; for (int j = 0; j < actualPopSize; j++) { if (!researchers [j].alive) { idx = j; break; } } if (idx == -1 && actualPopSize < maxPopSize) { idx = actualPopSize; } if (idx == -1) // No hay espacio, ampliamos el array { if (actualPopSize >= maxPopSize) { // Limitamos el crecimiento de la población int newMaxSize = MathMin (maxPopSize + 50, 500); if (newMaxSize == maxPopSize) continue; // Se ha alcanzado el límite, omitimos la creación maxPopSize = newMaxSize; ArrayResize (researchers, maxPopSize); for (int j = actualPopSize; j < maxPopSize; j++) { researchers [j].Init (coords, journalsNum); researchers [j].alive = false; } idx = actualPopSize; } } if (idx == -1) continue; // No se ha podido crear researchers [idx].alive = true; researchers [idx].m = fundsPerNew; researchers [idx].s = u.RNDprobab (); // Inicialización aleatoria for (int c = 0; c < coords; c++) { researchers [idx].x [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); researchers [idx].x [c] = u.SeInDiSp (researchers [idx].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); researchers [idx].b [c] = researchers [idx].x [c]; researchers [idx].v [c] = u.GaussDistribution (0.0, -0.01, 0.01, 1); } // Inicialización de las probabilidades de las revistas científicas for (int j = 0; j < journalsNum; j++) { researchers [idx].rho [j] = u.RNDprobab (); } NormalizeProbabilities (researchers [idx].rho); if (idx >= actualPopSize) actualPopSize = idx + 1; } } //————————————————————————————————————————————————————————————————————
La función «HireResearchers» describe el proceso de «contratación» de nuevos investigadores por parte de un investigador ya existente que cuenta con una cantidad suficiente de subvenciones. Se trata de un mecanismo para crear nuevos elementos (soluciones) teniendo en cuenta las características de los ya existentes, lo que constituye una forma de reproducción o diversificación. La función admite un único parámetro: el índice del «supervisor», es decir, el investigador que se encargará de contratar a los nuevos. Si el investigador con ese índice dispone de una unidad de fondos o menos, la función interrumpe inmediatamente su ejecución. Esto significa que, para la contratación, es necesario disponer de fondos suficientes.
División de los fondos del supervisor. Se calcula la parte de los fondos que el supervisor conserva para sí. Se trata de los fondos totales del supervisor, multiplicados por «researchers[idx].s». Se calculan los fondos disponibles para la contratación. Son los fondos restantes. Se actualizan los fondos del supervisor. Si «hireFunds» es menor o igual que 0, la contratación no es posible y la función interrumpe su ejecución.
Determinación del número de investigadores que se van a contratar. Se establece el número máximo de nuevos investigadores que se pueden contratar. Si la población actual es grande (más de 100), «maxNew» es igual a 1. De lo contrario, «maxNew» es igual a 3. Se trata de un mecanismo de control del crecimiento de la población. Primero se determina el número real de nuevos investigadores que se crearán. Luego se selecciona aleatoriamente en el rango de 1 hasta el valor mínimo entre «hireFunds» y «maxNew». Después se calcula la cantidad de fondos que recibirá cada nuevo investigador contratado (división simple de «hireFunds» entre «newCount»).
Ciclo de creación de nuevos investigadores (contratación). La función ejecuta este proceso «newCount» veces: primero se busca un «espacio libre» en el array existente de investigadores. Se considera espacio libre el índice cuyo indicador de actividad está establecido en «false» y, si se encuentra un espacio libre, este se utiliza. Si no hay espacio libre, pero el tamaño actual de la población es inferior al tamaño máximo permitido, se añade un nuevo espacio al final del array.
Comprobación de la posibilidad de contratación (al alcanzar los límites). Si no hay espacio libre y, además, «actualPopSize» ya es igual o superior a «maxPopSize», o si «actualPopSize» ya es igual o superior al límite absoluto de 500, se omite la creación del investigador actual (el ciclo pasa a la siguiente iteración o finaliza). Si «newIdx» sigue siendo -1, significa que no es posible encontrar ni crear un espacio para un nuevo investigador, por lo que se omite la iteración actual del ciclo.
Inicialización de un nuevo investigador. Si se encuentra un espacio correctamente, «researchers [newIdx]. alive» se establece en «true», lo que hace que el nuevo investigador se marque como activo, y los fondos del nuevo investigador se establecen en «fundsPerNew». El parámetro de «tendencia» del nuevo investigador se inicializa con un número aleatorio extraído de una distribución gaussiana. El valor medio de esta distribución se toma de «researchers [idx]. s» (parámetro del supervisor) y significa que el nuevo investigador será similar a su «supervisor». El valor de «s» queda limitado al intervalo de «0» a «1».
Herencia de características del supervisor. La mejor posición encontrada o el «conocimiento» de un nuevo investigador se copia directamente de la mejor posición del supervisor y permite a los nuevos investigadores heredar esa «experiencia».
Inicialización de la posición (coordenadas). Para cada coordenada «c» (coords — número de dimensiones), la posición del nuevo investigador se inicializa como la posición del supervisor, más una perturbación aleatoria extraída de una distribución gaussiana. Esto significa que los nuevos investigadores aparecen «cerca» de su supervisor, pero no exactamente en el mismo lugar. La posición se restringe a los límites establecidos. A continuación, «researchers [newIdx]. x [c]» se ajusta teniendo en cuenta el paso de discretización mediante la función «SeInDiSp», y la velocidad o el vector de variación también se inicializa de forma aleatoria a partir de una distribución normal.
Inicialización de las probabilidades de las revistas científicas (publicación). Para cada revista científica «j» (journalsNum: número de revistas científicas), la probabilidad de publicación en la revista científica «j» se inicializa con un número aleatorio extraído de una distribución gaussiana. El valor medio de esta distribución se obtiene a partir de la probabilidad del supervisor. Esto permite a los nuevos investigadores heredar las preferencias del supervisor en cuanto a las revistas científicas, aunque con cierta variación aleatoria. Los valores negativos de «rho» se recortan a 0. A continuación, se llama a «NormalizeProbabilities» para «researchers [newIdx]. rho», con el fin de garantizar que la suma de todos los «rho» de ese investigador sea igual a uno.
Actualización del tamaño de la población. Si se ha añadido un nuevo investigador al final del array («newIdx» es igual o mayor que «actualPopSize»), entonces «actualPopSize» se actualiza a «newIdx + 1».
De este modo, «HireResearchers» permite a los investigadores de éxito «reproducirse», creando nuevas instancias que heredan parte de sus características, pero con cierta variación aleatoria. Esto favorece la exploración de las zonas adyacentes en el espacio de búsqueda y la difusión de estrategias exitosas, al tiempo que se controla el tamaño total de la población.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::HireResearchers (int idx) { if (researchers [idx].m <= 1) return; int keepFunds = (int)(researchers [idx].m * researchers [idx].s); int hireFunds = researchers [idx].m - keepFunds; researchers [idx].m = keepFunds; if (hireFunds <= 0) return; // Limitamos el número de investigadores contratados, sobre todo cuando la población es numerosa int maxNew = (actualPopSize > 100) ? 1 : 3; int newCount = (int)(u.RNDfromCI (1, MathMin (hireFunds, maxNew))); int fundsPerNew = hireFunds / newCount; for (int i = 0; i < newCount; i++) { // Buscamos un espacio libre int newIdx = -1; for (int j = 0; j < actualPopSize; j++) { if (!researchers [j].alive) { newIdx = j; break; } } if (newIdx == -1 && actualPopSize < maxPopSize) { newIdx = actualPopSize; } if (newIdx == -1) // No hay espacio disponible { if (actualPopSize >= maxPopSize || actualPopSize >= 500) continue; // Se omite la creación al alcanzar el límite } if (newIdx == -1) continue; // No se pudo encontrar un espacio libre researchers [newIdx].alive = true; researchers [newIdx].m = fundsPerNew; researchers [newIdx].s = u.GaussDistribution (researchers [idx].s, 0, 1, 1); if (researchers [newIdx].s < 0) researchers [newIdx].s = 0; if (researchers [newIdx].s > 1) researchers [newIdx].s = 1; // Herencia a partir del supervisor ArrayCopy (researchers [newIdx].b, researchers [idx].b, 0, 0, WHOLE_ARRAY); // Posición cerca del supervisor for (int c = 0; c < coords; c++) { researchers [newIdx].x [c] = researchers [idx].x [c] + u.GaussDistribution (0.0, -0.01, 0.01, 1); // Control de límites if (researchers [newIdx].x [c] < rangeMin [c]) researchers [newIdx].x [c] = rangeMin [c]; if (researchers [newIdx].x [c] > rangeMax [c]) researchers [newIdx].x [c] = rangeMax [c]; researchers [newIdx].x [c] = u.SeInDiSp (researchers [newIdx].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); researchers [newIdx].v [c] = u.GaussDistribution (0.0, -0.01, 0.01, 1); } // Probabilidades perturbadas de las revistas científicas for (int j = 0; j < journalsNum; j++) { researchers [newIdx].rho [j] = u.GaussDistribution (researchers [idx].rho [j], 0, 1, 1); if (researchers [newIdx].rho [j] < 0) researchers [newIdx].rho [j] = 0; } NormalizeProbabilities (researchers [newIdx].rho); if (newIdx >= actualPopSize) actualPopSize = newIdx + 1; } } //————————————————————————————————————————————————————————————————————
La función «ComputeStdDev» sirve para calcular la desviación estándar de los valores de la función objetivo para todos los investigadores activos de la población. Es una medida de la dispersión de los datos en torno al valor medio y, en el contexto de la optimización, puede indicar la diversidad de soluciones en la población actual.
Cálculo de la media (Mean):- Se inicializan las variables «mean» (para acumular la suma de los valores de «f») y «count» (para contar el número de investigadores activos).
- La función itera por todos los investigadores del array «researchers», desde «0» hasta «actualPopSize - 1».
- Dentro del ciclo se comprueba si el investigador «researchers [i]» está «activo», ya que solo los investigadores activos deben tenerse en cuenta en los cálculos.
- Si el investigador está activo, su valor «f» se suma a «mean» y «count» aumenta en «1».
- Una vez finalizado el primer ciclo, si «count» sigue siendo igual a «0» (no se ha encontrado ningún investigador activo), la función devuelve «0».
- Por último, «mean» se divide entre «count» para obtener la media aritmética de «f» para todos los investigadores activos.
- Se inicializa la variable «variance» con el valor «0».
- La función vuelve a recorrer todos los investigadores del array «researchers».
- Se vuelve a comprobar la condición de investigador activo.
- Para cada investigador activo se calcula el cuadrado de la diferencia entre su valor «f» y el valor «mean» ya calculado. Esta diferencia al cuadrado se suma a «variance».
- Una vez finalizado el segundo ciclo, «variance» se divide entre «count». Esto da como resultado la varianza de los valores de «f» para los investigadores activos.
//———————————————————————————————————————————————————————————————————— double C_AO_CoSO::ComputeStdDev () { if (actualPopSize == 0) return 0; double mean = 0; int count = 0; for (int i = 0; i < actualPopSize; i++) { if (researchers [i].alive) { mean += researchers [i].f; count++; } } if (count == 0) return 0; mean /= count; double variance = 0; for (int i = 0; i < actualPopSize; i++) { if (researchers [i].alive) { variance += MathPow (researchers [i].f - mean, 2); } } variance /= count; return MathSqrt (variance); } //————————————————————————————————————————————————————————————————————
La función «UpdateOmega» ajusta dinámicamente el parámetro «omegaCurrent», que representa la proporción de outsiders o la probabilidad de seleccionar a un outsider en el comportamiento del algoritmo. El objetivo de esta función es gestionar de forma adaptativa la estrategia de exploración/explotación según el estado actual de la población de investigadores, es decir, de su dispersión en el espacio de búsqueda.
En primer lugar, la función llama a «ComputeStdDev()» para determinar «currentSigma», es decir, la desviación estándar actual de los valores de la función objetivo para los investigadores activos. Un valor alto de «currentSigma» indica una gran diversidad de soluciones, mientras que un valor bajo indica su convergencia.
Caso 1: Convergencia de la población (currentSigma < sigma0). Si la desviación estándar actual es inferior a un umbral «sigma0» predeterminado, esto indica que los investigadores comienzan a converger o a agruparse en torno a determinadas soluciones. En este caso, el algoritmo pasa a la fase de explotación (refinamiento) de las soluciones encontradas. Para evitar una convergencia prematura hacia un óptimo local y fomentar una mayor exploración, así como la búsqueda de mejores soluciones, se aumenta la proporción de outsiders (omegaCurrent). El incremento se calcula como (omegaMax - omegaMin) / 2.0 * epsilonPlus. Aquí, «omegaMax» y «omegaMin» definen los límites superior e inferior de «omegaCurrent», mientras que «epsilonPlus» es un coeficiente positivo que controla la velocidad de aumento. El objetivo es dar mayor peso a aquellos elementos que puedan «desviarse» de la tendencia general o que representen enfoques completamente nuevos.
Caso 2: Divergencia o falta de convergencia de la población (currentSigma >= sigma0). Si la desviación estándar es mayor o igual que el umbral «sigma0», esto significa que la población sigue estando muy dispersa o se encuentra en las primeras fases de exploración. En este caso la proporción de outsiders (omegaCurrent) disminuye. La reducción se calcula como (omegaMax - omegaMin) / 2.0 * epsilonMinus, donde «epsilonMinus» es un coeficiente negativo que controla la velocidad de reducción. Esto se hace para que el algoritmo no dedique demasiados recursos a la exploración aleatoria cuando la población ya es lo suficientemente diversa, y pueda empezar a centrarse en áreas más prometedoras.
Limitación del rango (omegaCurrent). Tras modificar «omegaCurrent», la función garantiza que su valor se mantenga dentro del rango establecido; si «omegaCurrent» desciende por debajo de «omegaMin», se fija en «omegaMin», y si supera «omegaMax», se fija en «omegaMax», lo que evita que el parámetro se salga de unos límites operativos razonables.
En general, la función «UpdateOmega» aplica una estrategia adaptativa. Cuando la población de investigadores muestra signos de convergencia rápida (baja desviación estándar), el algoritmo aumenta la probabilidad de seleccionar «outsiders» (o elementos que puedan alterar la estructura actual), con el fin de evitar los óptimos locales y estimular una nueva búsqueda o la exploración de un espacio más amplio. A la inversa, cuando la población sigue estando ampliamente distribuida, el algoritmo reduce el énfasis en los outsiders para centrarse en una exploración o explotación más sistemática de las áreas prometedoras ya identificadas.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::UpdateOmega () { double currentSigma = ComputeStdDev (); if (currentSigma < sigma0) { // Aumentamos la proporción de outsiders cuando hay convergencia omegaCurrent += (omegaMax - omegaMin) / 2.0 * epsilonPlus; } else { // Reducimos la proporción de outsiders omegaCurrent -= (omegaMax - omegaMin) / 2.0 * epsilonMinus; } // Limitamos el rango if (omegaCurrent < omegaMin) omegaCurrent = omegaMin; if (omegaCurrent > omegaMax) omegaCurrent = omegaMax; } //————————————————————————————————————————————————————————————————————
La función «NormalizeProbabilities» está diseñada para transformar el array de valores numéricos «probs» de tal forma que representen una distribución de probabilidades correcta. Es decir, tras ejecutar la función, la suma de todos los elementos del array «probs» será igual a uno. Se inicializa la variable «sum» con el valor 0; se utilizará para acumular la suma de todos los elementos del array «probs». Se inicia un ciclo que recorre todos los elementos de este array. Dentro del ciclo, cada valor de «probs [i]» se suma a la variable «sum».
Si el valor calculado de «sum» es positivo, se inicia un segundo ciclo que también recorre todos los elementos del array «probs». Dentro de este ciclo, cada elemento del array se divide entre «sum». Como resultado de esta división, cada valor de «probs [i]» pasa a ser la fracción correspondiente del total, y la suma de todos los elementos del array es igual a «1». Se trata de un procedimiento estándar de normalización.
Si «sum» es igual a «0» o es negativa —aunque esto no suele esperarse en el caso de las probabilidades, la función también contempla este caso—, significa que no hay base sobre la que normalizar los valores iniciales. Por ejemplo, todas las probabilidades iniciales eran cero. En este caso, la función pasa a una «distribución uniforme». El valor «val» se calcula como (1.0 / size). Esto significa que cada elemento del array tendrá la misma probabilidad, de modo que su suma sea «1». Se inicia el tercer ciclo, que recorre todos los elementos del array «probs». Dentro de este ciclo, a cada elemento se le asigna el valor calculado «val». De este modo, cada elemento del array pasa a ser igual a (1 / size), y su suma será «1».
Esta función es un método de utilidad general que garantiza que un conjunto de pesos o probabilidades «en bruto» pueda utilizarse como una distribución de probabilidades válida (donde «válida» significa que la suma de todas las probabilidades es igual a 1). Esto es importante en muchos algoritmos, como los métodos de selección basados en probabilidades, la selección por ruleta o el método de Monte Carlo, en los que una normalización adecuada evita errores y garantiza un comportamiento estadístico correcto.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::NormalizeProbabilities (double &probs []) { double sum = 0; int size = ArraySize (probs); for (int i = 0; i < size; i++) { sum += probs [i]; } if (sum > 0) { for (int i = 0; i < size; i++) { probs [i] /= sum; } } else { // Distribución uniforme double val = 1.0 / size; for (int i = 0; i < size; i++) { probs [i] = val; } } } //————————————————————————————————————————————————————————————————————
La función «CompactPopulation» se encarga de gestionar el tamaño y la composición de la población de investigadores en el algoritmo. El objetivo principal es eliminar a los investigadores menos eficaces y, si es necesario, reducir la población a un tamaño manejable para mantener la eficiencia y el rendimiento del algoritmo.
Recuento de investigadores «activos». Se inicializa la variable «aliveCount» (número de supervivientes) con el valor «0». A continuación, en un ciclo se recorren todos los investigadores de la población actual (desde 0 hasta actualPopSize - 1). Se comprueba el estado de cada investigador (researchers [i]. alive). Si el investigador está «activo» (su propiedad «alive» es verdadera), «aliveCount» se incrementa en uno.Condición para la compactación/reducción. Después de contar los investigadores activos, la función comprueba si es necesario llevar a cabo la compactación. Esto ocurre si se cumple una de estas dos condiciones: el número de investigadores activos «aliveCount» es inferior al 75 % del tamaño total actual de la población «actualPopSize», o si el tamaño actual de la población «actualPopSize» supera los 200 (aunque la mayoría de ellos estén activos, la población se considera demasiado grande y debe reducirse).
Primera fase de compactación (eliminación de los «inactivos»). Si se cumple una de las condiciones para la compactación, se inicia el proceso. Se inicializa un nuevo índice con el valor «0». Este índice indicará el siguiente espacio libre al principio del array «researchers», al que se trasladarán los investigadores «activos». Luego se inicia un ciclo que recorre a todos los investigadores (del 0 al actualPopSize - 1). Dentro del ciclo, si el investigador actual está «activo», se comprueba si ya se encuentra en la posición correcta; de no ser así, significa que hay que desplazarlo hacia delante en el array.
El investigador se copia en la posición «newIdx». Normalmente, en estos casos, se establece (researchers [i]. alive = false) para marcar al investigador original como «eliminado» o inactivo, aunque ya se haya copiado. Se trata de una limpieza: «newIdx» se incrementa en uno para indicar el siguiente espacio para el siguiente investigador activo. Una vez finalizado este ciclo, todos los investigadores «activos» se encontrarán al principio del array «researchers». El tamaño de la población se actualiza a «aliveCount».
Segunda fase de compactación (reducción de una población grande). Tras la primera fase (en la que se eliminaron los inactivos y se desplazaron los activos), la función comprueba si «actualPopSize» aún supera los 150. Esta condición está anidada, es decir, solo se cumple si la población ya se ha compactado o contaba con muchos investigadores inactivos. Si «actualPopSize» es mayor que 150, significa que, incluso tras eliminar los investigadores inactivos, la población sigue siendo demasiado grande y es necesario reducirla aún más hasta el tamaño máximo permitido, que es 150. Para ello, se realiza una clasificación según el indicador «fitness». Después de esto, los investigadores con mejor «fitness» quedarán al principio del array.
Eliminación de los «peores» investigadores. Todos los investigadores a partir del elemento 150 (es decir, los que quedaron en la «cola» tras la clasificación) se marcan como «inactivos» (researchers [i]. alive = false). Su parámetro «m» también se pone a cero. Por último, «actualPopSize» se establece en 150, con lo que en la práctica se recorta la población al tamaño máximo deseado. Esta función garantiza que la población:- No acumula individuos no utilizados que podrían ocupar memoria y ralentizar el procesamiento.
- No crezca de forma descontrolada, lo que también puede afectar negativamente al rendimiento y la eficiencia, además de provocar un estancamiento prematuro.
- Mantenga un determinado nivel de calidad, descartando a los individuos menos aptos cuando el tamaño de la población alcanza un nivel crítico.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::CompactPopulation () { // Contamos los investigadores activos int aliveCount = 0; for (int i = 0; i < actualPopSize; i++) { if (researchers [i].alive) aliveCount++; } // Si hay demasiados inactivos, compactamos if (aliveCount < actualPopSize * 0.75 || actualPopSize > 200) { int newIdx = 0; for (int i = 0; i < actualPopSize; i++) { if (researchers [i].alive) { if (i != newIdx) { // Copiamos el investigador activo a una nueva ubicación researchers [newIdx] = researchers [i]; researchers [i].alive = false; } newIdx++; } } actualPopSize = aliveCount; // Si la población sigue siendo demasiado grande, la limitamos if (actualPopSize > 150) { // Clasificamos por aptitud (fitness) y nos quedamos con los mejores for (int i = 0; i < actualPopSize - 1; i++) { for (int j = i + 1; j < actualPopSize; j++) { if (researchers [i].f < researchers [j].f) { S_Researcher temp = researchers [i]; researchers [i] = researchers [j]; researchers [j] = temp; } } } // Desactivamos a los peores for (int i = 150; i < actualPopSize; i++) { researchers [i].alive = false; researchers [i].m = 0; } actualPopSize = 150; } } } //————————————————————————————————————————————————————————————————————
El método «Revision» restante del algoritmo CoSO. Se inicia un ciclo que recorre todos los individuos del array «a», desde el índice «0» hasta «aSize - 1». Dentro del ciclo, para cada individuo «a [i]» se comprueba la condición: «if (a [i]. f > fB)». Si el valor de la función objetivo del individuo actual resulta ser mayor que el mejor valor global actual, «fB» se actualiza con el nuevo mejor valor: «fB = a [i]. f». Luego se guarda el índice de este mejor individuo.
Una vez finalizado el ciclo que ha recorrido todos los individuos del array «a», se comprueba la condición «if (bestIND != -1)». Esta condición se cumple si se ha encontrado al menos un individuo cuya función objetivo fuera mejor que el valor anterior de «fB». Si se ha encontrado un nuevo mejor individuo (bestIND es distinto de -1), se llama a la función «ArrayCopy», que copia los parámetros «c» del mejor individuo encontrado en el array global «cB».
El objetivo principal de este método es mantener actualizado el estado de la mejor solución global encontrada por el algoritmo hasta ese momento. En los algoritmos evolutivos, como CoSO, el concepto de «mejor global» (global best) se sigue y se actualiza constantemente a medida que se encuentran mejores soluciones. Este resultado «mejor global» se utiliza después para orientar la búsqueda. En esencia, esta función implementa el paso de «memorizar la mejor solución» en cada iteración del algoritmo.
//———————————————————————————————————————————————————————————————————— void C_AO_CoSO::Revision () { int bestIND = -1; int aSize = ArraySize (a); for (int i = 0; i < aSize; i++) { if (a [i].f > fB) { fB = a [i].f; bestIND = i; } } if (bestIND != -1) { ArrayCopy (cB, a [bestIND].c, 0, 0, WHOLE_ARRAY); } } //————————————————————————————————————————————————————————————————————
Resultados de las pruebas
El algoritmo CoSO funciona bastante bien y muestra resultados bastante buenos; por supuesto, quienes lo deseen pueden seguir experimentando con los parámetros. =============================
5 Hilly's; Func runs: 10000; result: 0,8047081198587067
25 Hilly's; Func runs: 10000; result: 0,5429326559833119
500 Hilly's; Func runs: 10000; result: 0,30916988715342353
=============================
5 Forest's; Func runs: 10000; result: 0,7383405771205314
25 Forest's; Func runs: 10000; result: 0,38224371519203115
500 Forest's; Func runs: 10000; result: 0,20600693936217676
=============================
5 Megacity's; Func runs: 10000; result: 0.553846153846154
25 Megacity's; Func runs: 10000; result: 0.2550769230769231
500 Megacity's; Func runs: 10000; result: 0.11129230769230862
=============================
Total score: 3,90362 (43,37%)
Es la primera vez que me encuentro con una visualización tan inusual del algoritmo; esto se debe a la lógica de implementación multicapa.

CoSO en la función de prueba Hilly

CoSO en la función de prueba Forest

CoSO en la función de prueba Megacity
Según los resultados del trabajo, el algoritmo se presenta con fines informativos en la tabla de clasificación de CoSO. Quiero señalar que nuestra tabla se está compactando, y los resultados inferiores al 45 % ya quedan fuera de sus límites.
| N.º | AO | Descripción | Hilly | Hilly Final | Forest | Forest Final | Megacity (discrete) | Megacity Final | Final Resultado | % 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 ptimization 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 | dialectic 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 | atomic orbital search 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 | atmosphere clouds 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 |
| CoSO | community_of_scientist_optimization | 0,80471 | 0,54293 | 0,30917 | 1,65681 | 0,73834 | 0,38224 | 0,20600 | 1,32658 | 0,55384 | 0,25507 | 0,11129 | 0,92020 | 3.904 | 43,37 | |
| 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 CoSO obtiene resultados medios en las funciones de prueba, alcanzando el 43 % del rendimiento máximo posible. Por supuesto, esperaba unos resultados más impresionantes. El banco de pruebas ofrece un conjunto ampliado de funciones, incluidas funciones estándar y ampliamente conocidas, con el que cualquier interesado puede seguir experimentando tanto con la selección de parámetros como con la elección de funciones para aprovechar mejor las posibilidades del algoritmo.
El principal inconveniente de la implementación actual es su elevada complejidad computacional. La arquitectura multicapa con revistas científicas, la asignación dinámica de fondos y la gestión adaptativa de la población generan una carga considerable. Este algoritmo es notablemente más lento que otros métodos poblacionales, lo que limita su aplicabilidad en problemas que requieren soluciones rápidas.
Sin embargo, el marco conceptual de CoSO reviste un gran interés. El modelado de la comunidad científica aporta mecanismos únicos que se han aplicado: la población dinámica adapta automáticamente los recursos computacionales a la complejidad del problema, el sistema de revistas garantiza un intercambio eficaz de información sin perder las mejores soluciones, la financiación competitiva genera una selección natural sin reglas rígidas, y el mecanismo de contratación intenta resolver el dilema entre la búsqueda local y la global.
El potencial de mejora es evidente. CoSO no debe considerarse una solución definitiva, sino una plataforma de investigación con gran potencial. El algoritmo abre una nueva vía en la optimización evolutiva, en la que los mecanismos sociales de las comunidades humanas se convierten en fuente de estrategias computacionales. Con el perfeccionamiento adecuado, CoSO podría encontrar su nicho en problemas en los que sean importantes la adaptabilidad y la robustez frente a los cambios, y el tiempo de cálculo no sea un factor crítico.

Figura 1. Gradación por colores de los algoritmos según las pruebas correspondientes

Figura 2. Histograma de los resultados de las pruebas de los algoritmos (en una escala de 0 a 100; cuanto mayor sea el valor, mejor, donde 100 es el resultado teórico máximo posible; en el archivo comprimido se incluye el script para calcular la tabla de clasificación)
Ventajas y desventajas del algoritmo CoSO:
Ventajas:
- una buena base para desarrollar derivaciones de nuevas variantes.
Desventajas:
- una gran cantidad de parámetros externos;
- propensión a estancarse en los problemas;
- lento.
Se adjunta al artículo un archivo comprimido con las versiones actualizadas de los códigos de los algoritmos. El autor del artículo no se hace responsable de la exactitud absoluta en la descripción de los algoritmos canónicos, ya que en muchos de ellos se han introducido modificaciones para mejorar las capacidades de búsqueda. Las conclusiones y consideraciones que figuran en los artículos se basan en los resultados de los experimentos realizados.
Programas utilizados en el artículo
| # | Nombre | Tipo | Descripción |
|---|---|---|---|
| 1 | #C_AO.mqh | Archivo de inclusión | Clase padre de los algoritmos de optimización poblacional |
| 2 | #C_AO_enum.mqh | Archivo de inclusión | Enumeración de algoritmos de optimización poblacional |
| 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 destinados a la tabla comparativa |
| 7 | Testing AOs.mq5 | Script | Banco de pruebas unificado para todos los algoritmos de optimización poblacional |
| 8 | Simple use of population optimization algorithms.mq5 | Script | Ejemplo sencillo de uso de algoritmos de optimización poblacional sin visualización |
| 9 | Test_AO_CoSO.mq5 | Script | Banco de pruebas para CoSO |
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/18935
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Utilizando redes neuronales en MetaTrader
Redes neuronales en el trading: Desentrañando los componentes estructurados (SCNN)
Particularidades del trabajo con números del tipo double en MQL4
Automatización de estrategias de trading en MQL5 (Parte 22): Desarrollo de un sistema de recuperación por zonas para trading de tendencia con Envelopes
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso