anatomía de un algoritmo genético en jenes

87
Anatomía de un algoritmo genético en Jenes Programación en Jenes es fácil, intuitiva y divertida. En esta sección, vamos a proporcionar algunos conceptos que hay que tener en cuenta al esbozar una solución en Jenes. Estos conceptos le ayudarán a moverse de manera efectiva entre las clases previstas en el API Jenes. Usted se sorprenderá de lo rápido que se puede definir un algoritmo genético, implementado y probado. Los cromosomas, individuos y poblaciones. La primera cosa a tener en cuenta es la diferencia entre los cromosomas, los individuos y las poblaciones. Soluciones en un espacio de búsqueda se representan por los individuos. Están hechas de un cromosoma y de la aptitud de valor: INDIVIDUAL = CROMOSOMA + FITNESS. Los cromosomas son las codificaciones de solución. En Jenes, se les considera como un conjunto de genes. Aquí está una lista de las clases de cromosomas proporcionadas por Jenes. BitwiseChromosome: modelos de un cromosoma de bits. Su genoma contiene valores codificados otorgado a la codificación de bits especificado. BooleanChromosome: modelos de un cromosoma de valores booleanos. Cada gen alelo puede ser verdadera o falsa. DoubleChromosome: modelos de un cromosoma de valores dobles. Cada valor está en el rango [lowerBound, upperBound]. Estos límites se especifican en el momento de instancias.

Upload: luis-dimas-azocar

Post on 31-Jul-2015

471 views

Category:

Education


2 download

TRANSCRIPT

Anatomía de un algoritmo genético en Jenes

Programación en Jenes es fácil, intuitiva y divertida. En esta sección, vamos a proporcionar algunos conceptos que hay que tener en cuenta al esbozar una solución en Jenes. Estos conceptos le ayudarán a moverse de manera efectiva entre las clases previstas en el API Jenes. Usted se sorprenderá de lo rápido que se puede definir un algoritmo genético, implementado y probado.

Los cromosomas, individuos y poblaciones.

La primera cosa a tener en cuenta es la diferencia entre los cromosomas, los individuos y las poblaciones.

Soluciones en un espacio de búsqueda se representan por los individuos. Están hechas de un cromosoma y de la aptitud de valor: INDIVIDUAL = CROMOSOMA + FITNESS.

Los cromosomas son las codificaciones de solución. En Jenes, se les considera como un conjunto de genes. Aquí está una lista de las clases de cromosomas proporcionadas por Jenes.

BitwiseChromosome: modelos de un cromosoma de bits. Su genoma contiene valores codificados otorgado a la codificación de bits especificado.

BooleanChromosome: modelos de un cromosoma de valores booleanos. Cada gen alelo puede ser verdadera o falsa.

DoubleChromosome: modelos de un cromosoma de valores dobles. Cada valor está en el rango [lowerBound, upperBound]. Estos límites se especifican en el momento de instancias.

IntegerChromosome: modelos de un cromosoma de valores enteros. Cada valor está en el rango [lowerBound, upperBound]. Estos límites se especifican en el momento de instancias.

ObjectChromosome: representa un cromosoma con genes que contiene un valor de alelo objeto.

PermutationChromosome: proporciona un cromosoma capaz de modelar permutaciones. Una matriz de valores enteros es su genoma. La propiedad más importante es que el genoma no contiene valores duplicados.

Todas las clases de cromosomas son la implementación de la interfaz del cromosoma. En general, los cromosomas se fija número de genes, pero su longitud puede variar durante la ejecución del algoritmo con el fin de implementar una codificación de longitud variable de solución. Una población es simplemente una colección de individuos (por ejemplo, soluciones).

Los individuos son todas las instancias de la clase paramétrica individual <T extiende Chromosome>, con el fin de tener un mayor control sobre los tipos. Un individuo puede ser legal o no legal. Es posible ajustar el lagality de un individuo mediante la invocación del método setLegal (boolen) en su instancia. Por defecto, cada individuo se fija te bo inicialmente legal.

Durante la evolución de algoritmos, las poblaciones del pasado se almacenan en la historia del algoritmo. En cada iteración de la evolución, la población más antigua y sus individuos se vuelven a utilizar. Las poblaciones del pasado, en lugar de ser cancelado la asignación, se mantenido en la memoria y volver a utilizar. Esta técnica evita la asignación en memoria de las nuevas poblaciones y limita el uso del recolector de basura.

Como se ha dicho, un algoritmo genético procesa una población de individuos. En cada generación hay poblaciones de entrada y salida. Es importante tener en cuenta que la población de salida se pre-inizialized con individuos "reciclados" tomados de la historia (por razones de rendimiento). Así Jenes generalmente no asigna nuevos individuos.

Estructura Algoritmo

Jenes proporciona una estructura flexible para la evolución de una población de individuos. En general, un algoritmo genético está estructurado como se muestra en la figura.

Básicamente, un algoritmo genético realiza el siguiente bucle:

Aleatoriamente crear una población inicial

repetición

      Valorar la aptitud de cada individuo

      Seleccione uno o más individuos de la población con una probabilidad basada en la aptitud para partecipate en las operaciones genéticas

      Crear nuevos individuos mediante la aplicación de las operaciones genéticas con probabilidades especificadas

hasta que una solución aceptable se encuentra o se cumpla alguna otra condición parar

devolverle al individuo mejor tan lejos

En Jenes un algoritmo genético se puede implementar mediante el uso o la subclasificación GeneticAlgorithm y definir una implementación de funcion gimnasio subclasificando Fitness y la implementación del método abstracto evaluar (Individual). Este método se utiliza para evaluar la capacidad de un solo individuo. La implementación de este método está relacionada específicamente con el problema a resolver.

En Jenes cuerpo algoritmo genético es un "tubo" de etapas. Las etapas se ejecutan secuencialmente en el orden en que se agregan a la secuencia. Cada etapa recibe una población de entrada (producido como salida por la etapa anterior) y produce una población de salida. ¿Qué etapas y en qué orden para considerar que queda a las necesidades del algoritmo.

La referencia a la actual y en el proceso de llenado se puede respectivamente obtiene por la getCurrentPopulation métodos () y getNextPopulation ().

Jenes también permite definir etapas paralelas. Una etapa paralelo está formado por diferentes ramas, cada rama es una etapa que recibe una subpoblación de acuerdo con el dispensador de población utilizada. Un dispensador distribuye una población entre las ramas de una etapa en paralelo y se funde la salida de cada rama en la población de salida del paralelo.

El punto de quiebre y los operadores genéticos representan las etapas de tuberías generales más simples.

Una etapa BreakPoint notifica a sus oyentes cuando se invocated su método de proceso. No alterate la población de entrada.

Operadores genéticos utilizados en los algoritmos genéticos son análogos a éstos que se producen en el mundo natural:

Selección: la que da preferencia a los mejores individuos, que les permite pasar a la siguiente generación.

Crossover: lo que representa el apareamiento entre individuos.

Mutación: que introduce modificaciones aleatorias.

Jenes proporciona la implementación de los operadores genéticos más comunes:

TournamentSelector: choses a un número aleatorio de individuos de la población. Estos se comparan entre sí y el mejor de ellos es elegido para ser un padre. Selector torneo hace

asegurar que incluso los individuos de calidad media tienen alguna posibilidad de tener hijos. En Jenes es necesario especificar el número de intentos de torneo.

RouletteWheelSelector: coge un miembro particular de la población para ser un padre con una probabilidad igual a su condición física, dividido por el total de la aptitud de la población.

OnePointCrossover: elige al azar un punto de cruce de los cromosomas de los padres y crea una nueva descendencia. Uno de los puntos de cruce puede tener este aspecto (donde "|" es el punto de cruce):

Chromosome 1 11101 | 001000

Chromosome 2 00001 | 010101

Offspring 1 11101 | 010101

Offspring 2 00001 | 001000

TwoPointsCrossover: escoge al azar dos puntos de cruce de los cromosomas de los padres y crea una nueva descendencia. Dos puntos de cruce puede tener este aspecto:

Chromosome 1 11 | 10100 | 1000

Chromosome 2 00 | 00101 | 0101

Offspring 1 11 | 00101 | 1000

Offspring 2 00 | 10100 | 0101

En Jenes necesita especificar la probabilidad por la cual se utilizará el operador de cruce. En general, para un operador de cruce la probabilidad se establece en 80%

Mutador simple: choses al azar un punto de mutación y aleatoriza su gen. Operador de mutación también necesita un número probabilidad que especifica su uso.

En general, para un operador de mutación la probabilidad se establece en 20%.

Jenes proporciona también una interfaz sencilla para GeneticAlgorithm. Es SimpleGA clase que implementa un algoritmo genético tres etapas hecha de una herramienta de selección, uno de cruce y uno Mutador en secuencia.

Ofrece una forma sencilla de implementar su propio algoritmo genético que le permite descuidar los problemas relacionados con la construcción de los estadios.

La clase proporciona un conjunto de constructores por lo que crear una instancia de un algoritmo SimpleGA. Constructores permite decidir qué método de selección (es decir, Torneo o ruleta) o el método cruzado (es decir, un punto o dos puntos) a adoptar. También cruce y probabilidad de mutación puede ser especificado en el momento de la construcción. SimpleGA es una subclase GeneticAlgorithm.

Jenes incluye un soporte para el elitismo, es decir los mejores individuos de cada generación tienen la garantía de estar en la próxima generación. El número de individuos de la élite es fijado por el setElitism método (int).

Estos individuos se sustituyen a algunos individuos a la población procesada de acuerdo con las siguientes estrategias:

Random Estrategia Elitismo: próximos individuos de población son seleccionados al azar y se sustituye por la élite.

Peor Estrategia Elitismo: próximo de población peores individuos son sustituidos por la élite.

Usted puede configurar su estrategia de elitismo preferida de la siguiente manera:

    sga.setElitismStrategy(ElitismStrategy.RANDOM); or        sga.setElitismStrategy(ElitismStrategy.WORST);

La primera estrategia es más eficiente, ya que no requiere para ordenar la población. El inconveniente es que los individuos con una buena aptitud podrían ser sustituidos por la élite. La segunda estrategia es más lento, pero asegura que sólo los peores individuos están sustituidos.

Jenes utiliza el MersenneTwisterRandom clase para la generación de números y valores de pseudo-aleatorios. Este una clase optimizado que proporciona para la generación rápida de números aleatorios de muy alta calidad. Por esta razón, se utiliza en lugar de java.util.Random. La generación de números pseudoaleatorios es muy útil durante todas las fases de la evolución algoritmo (tales como la inicialización de la población, el uso de operadores de selección, la determinación de puntos de cruce y mutación, y así sucesivamente).

Eventos, oyentes y Estadísticas

La ejecución del algoritmo genético es invocado por el método de evolucionar (). La ejecución del algoritmo pasa a través de los siguientes eventos:

Inicio: la evolución algoritmo comienza.

Init: estructuras internas, como la población dada como entrada a la generación 0 y la historia, se inicializan.

Generación: una generación se ha acaba de realizar.

Stop: el algoritmo termina sus ejecuciones.

Cada uno de estos eventos pueden ser capturados por AlgorithmEventListeners y GenerationEventListeners. También pueden ser caputured por la subclase GeneticAlgorithm, reemplazando los métodos onStart (largos), onInit (largo), onGeneration (tiempo) y onStop (largo). La captura de eventos es útil para recopilar estadísticas y realizar análisis.

AlgorithmEventListeners proporciona la interfaz para la captura de eventos a nivel de algoritmo. Esta interfaz debe ser implementado por todas las clases interesadas en beign notificado por acontecimientos algoritmo (Start, inicio, parada). Un AlgorithmEventListener se puede registrar en el algoritmo por el método GeneticAlgorithm.addAlgorithmEventListener (AlgorithmEventListener). El oyente puede ser eliminado por la invocación del método GeneticAlgorithm.removeAlgorithmEventListener (AlgorithmEventListener).

GenerationEventListener es un oyente del evento de generación de algoritmo genético. Esta escucha se notifica una vez que se ejecuta una etapa de generación. A GenerationEventListener se puede registrar en el algoritmo por el método GeneticAlgorithm.addGenerationEventListener (GenerationEventListener). El oyente puede ser eliminado por la invocación del método GeneticAlgorithm.removeGenerationEventListener (GenerationEventListener).

Durante la evolución del algoritmo genético , Jenes recopila estadísticas sobre:

Ejecución de algoritmo: La clase GeneticAlgorithm.Statistics se encarga de almacenar información sobre el tiempo dedicado por todo el proceso evolutivo y el número de generaciones creadas . Puede invocar el método () GeneticAlgorithm.getStatistics para obtener las estadísticas de algoritmos .

Población: La clase Population.Statistics se encarga de almacenar información sobre una población. A medida que cada lata población contiene individuos legales e ilegales , mantiene los individuos con la aptitud mayor y menor , los valores medios y la desviación ambos consideran a las personas jurídicas y las ilegales . Puede invocar el método las Population.getStatistics () para obtener sus estadísticas .

Operadores: Las Selection.Statistics , Crossover.Statistics y Mutator.Statistics clases son responsables de almacenar información sobre los operadores utilizados y el tiempo empleado para su ejecución . Ellos sostienen respectivamente el número de cruce , selección y mutación realizado . Puede invocar el método () Operator.getStatistics en una instancia de la clase operador para obtener sus estadísticas.

Un problema boolean sencilla

Vamos a empezar con un problema sencillo. Dado un espacio de búsqueda hecha de variables booleanas, nuestro objetivo es encontrar una solución hecha de verdaderos valores (o valores falsos). Este problema es enfrentado por el diseño de un algoritmo genético de trabajo en los cromosomas booleanos. La función de aptitud se calcula contando el número de verdaderos valores dentro del cromosoma. Así que con el fin de encontrar la solución con todos los verdaderos valores podemos maximizar la función de aptitud, mientras que se minimiza la función de aptitud con el fin de encontrar una solución a base de todos los falsos valores.

Este tutorial te dará la oportunidad de entender cómo se estructura un algoritmo genético y taylored a un problema de optimización. Por otra parte, vamos a ver cómo los oyentes se pueden utilizar para capturar los eventos algoritmos.

1. Elegir un problema cromosómico adecuado y crear la población inicial.

La elección de una representación cromosómica adecuada es la tarea más importante que hacer antes de ejecutar un algoritmo genético. ¿Qué representación a utilizar depende de la estructura de las soluciones a los problemas. En nuestro caso, las soluciones están hechas de matrices booleanas. Por lo tanto, BooleanChromosome parece ser la opción approppriate. Los cromosomas representan el componente clave de las soluciones (es decir, individuos). Para la construcción de la población inicial que necesitamos un prototipo de soluciones (muestra), como se muestra en el siguiente código.

060         Individual<BooleanChromosome> sample = new Individual<BooleanChromosome>(new BooleanChromosome(CHROMOSOME_LENGTH));061         Population<BooleanChromosome> pop = new Population<BooleanChromosome>(sample, POPULATION_SIZE);

cuando

045     private static int POPULATION_SIZE=50;046     private static int CHROMOSOME_LENGTH=100;047     private static int GENERATION_LIMIT=1000;

2. Puesta en marcha del algoritmo genético.

Cualquier algoritmo en Jenes 2.0 se basa en GeneticAlgorithm, para wich debe definir una función de aptitud que se utiliza para evaluar a los individuos. Para definir una función de aptitud en Jenes 2.0 sólo tenemos que crear una subclase de fitness, una clase abstracta, la aplicación del método de evaluar (individual).

Cualquier algoritmo en Jenes se basa en GeneticAlgorithm, una clase abstracta cuyo único método es abstracto evaluateIndividual que es un problema dependiente. A continuación se muestra el código para crear una subclase de GeneticAlgorithm y evaluar a un individuo en nuestro problema.

Por ejemplo, podría ser fácil de definir una función de aptitud mediante el uso de una clase interna anónima como seguimiento:

063         Fitness<BooleanChromosome> fit = new Fitness<BooleanChromosome>(false) {064 065             @Override066             public void evaluate(Individual<BooleanChromosome> individual) {067                 BooleanChromosome chrom = individual.getChromosome();068                 int count = 0;069                 int length=chrom.length();070                 for(int i=0;i<length;i++)071                     if(chrom.getValue(i))072                         count++;073                 074                 individual.setScore(count);075             }076             077         };

Y luego pasar este objeto como primer parámetro de algoritmo genético (o cualquier subclase predefinido)

079         GeneticAlgorithm<BooleanChromosome> ga = new GeneticAlgorithm<BooleanChromosome>080                 (fit, pop, GENERATION_LIMIT);

La clase de fitness ofrece dos constructores diferentes para definir el número de objetivos a considerar en la evaluación de las personas, y para cada objetivo de la bandera que indica si se trata de una función de maximizar o no. En el código que aparece más arriba, creamos un gimnasio para un solo problema objetivo (sólo una bandera como parámetros).

3. Elija los operadores a utilizar por el algoritmo genético y agregarlos como etapas en el ga.

Una vez definido el algoritmo genético, es necesario especificar la secuencia de la población operadores atravesará. El esquema más simple contiene sólo tres operadores en secuencia: un selector, una de cruce y uno de mutador. Sin embargo, es posible crear un

tubo más complejo que tiene paralléles y secuencias. A los efectos de este tutorial vamos a adoptar la siguiente estructura simple (ver APIs forman más detalles sobre los operadores adoptados):

082   AbstractStage<BooleanChromosome> selection = new TournamentSelector<BooleanChromosome>(3);083   AbstractStage<BooleanChromosome> crossover = new OnePointCrossover<BooleanChromosome>(0.8);084   AbstractStage<BooleanChromosome> mutation = new SimpleMutator<BooleanChromosome>(0.02);085   ga.addStage(selection);086   ga.addStage(crossover);087   ga.addStage(mutation);

4. Establezca los parámetros del algoritmo y ejecutar la evolución.

Es posible personalizar el ajuste del valor de elitismo algoritmo genético y el objetivo de optimización antes de ejecutar la evolución. El elitismo es el número de las mejores personas para celebrar en la próxima generación (1 en nuestro caso).

089         ga.setElitism(1);

Por último, podemos hacer que el algoritmo de funcionamiento.

091         ga.evolve();

5. Obtención del resultado de la evolución.

Jenes proporciona estadísticas tanto para el algoritmo y la población. La primera referencia a las estadísticas relativas a la ejecución de algoritmo, es decir, los tiempos de inicialización, comenzando, la evolución y las generaciones. El segundo a la distribución de soluciones y servicios conexos valores de fitness, como las personas ordenadas por la disminución de la función física, la media máxima, y mínima de los valores de fitness. Ellos se pueden recuperar en cualquier momento. Le llamaremos cuando el algoritmo ha terminado.

093         Population.Statistics stats = ga.getCurrentPopulation().getStatistics();094         GeneticAlgorithm.Statistics algostats = ga.getStatistics();095         096         System.out.println("Objective: " + (fit.getBiggerIsBetter()[0] ? "Max! (All true)" : "Min! (None true)"));097         System.out.println();098         099         Group legals = stats.getGroup(Population.LEGALS);100         101         Individual solution = legals.get(0);102                 103         System.out.println("Solution: ");

104         System.out.println( solution );105         System.out.format("found in %d ms.\n", algostats.getExecutionTime() );106         System.out.println();107         108         Utils.printStatistics(stats);

Ejemplo completo:

package jenes.tutorials.problem1;

import jenes.Fitness;import jenes.GeneticAlgorithm;import jenes.chromosome.BooleanChromosome;import jenes.population.Individual;import jenes.population.Population;import jenes.population.Population.Statistics.Group;import jenes.stage.AbstractStage;import jenes.stage.operator.common.OnePointCrossover;import jenes.stage.operator.common.SimpleMutator;import jenes.stage.operator.common.TournamentSelector;import jenes.tutorials.utils.Utils;

public class BooleanProblem {        private static int POPULATION_SIZE=50;    private static int CHROMOSOME_LENGTH=100;    private static int GENERATION_LIMIT=1000;        public static void main(String[] args) throws Exception {                Utils.printHeader();        System.out.println();                System.out.println("TUTORIAL 1:");        System.out.println("This algorithm aims to find a vector of booleans that is entirely true or false.");        System.out.println();                // Random.getInstance().setStandardSeed();                Individual<BooleanChromosome> sample = new Individual<BooleanChromosome>(new BooleanChromosome(CHROMOSOME_LENGTH));        Population<BooleanChromosome> pop = new Population<BooleanChromosome>(sample, POPULATION_SIZE);                Fitness<BooleanChromosome> fit = new Fitness<BooleanChromosome>(false) {

            @Override            public void evaluate(Individual<BooleanChromosome> individual) {                BooleanChromosome chrom = individual.getChromosome();                int count = 0;                int length=chrom.length();                for(int i=0;i<length;i++)                    if(chrom.getValue(i))                        count++;                                individual.setScore(count);            }                    };                GeneticAlgorithm<BooleanChromosome> ga = new GeneticAlgorithm<BooleanChromosome>                (fit, pop, GENERATION_LIMIT);                AbstractStage<BooleanChromosome> selection = new TournamentSelector<BooleanChromosome>(3);        AbstractStage<BooleanChromosome> crossover = new OnePointCrossover<BooleanChromosome>(0.8);        AbstractStage<BooleanChromosome> mutation = new SimpleMutator<BooleanChromosome>(0.02);        ga.addStage(selection);        ga.addStage(crossover);        ga.addStage(mutation);                ga.setElitism(1);                ga.evolve();                Population.Statistics stats = ga.getCurrentPopulation().getStatistics();        GeneticAlgorithm.Statistics algostats = ga.getStatistics();                System.out.println("Objective: " + (fit.getBiggerIsBetter()[0] ? "Max! (All true)" : "Min! (None true)"));        System.out.println();                Group legals = stats.getGroup(Population.LEGALS);                Individual solution = legals.get(0);                        System.out.println("Solution: ");        System.out.println( solution );        System.out.format("found in %d ms.\n", algostats.getExecutionTime() );        System.out.println();                Utils.printStatistics(stats);    }    }

Estructuración de un algoritmo genético avanzado

En nuestro segundo tutorial mostramos cómo crear un escenario paralelo y lo puso en la secuencia algoritmo, cómo distribuir y combinar estrategias paralelas, cómo establecer una condición de terminación definida por el usuario y cómo utilizar los oyentes de atrapar eventos algoritmo. El objetivo en este problema tutorial es para encontrar la matriz más cercano número entero (representable con un número especificado de cifras decimales) a una de destino con cada número dentro de la gama [0,49].

1. Elegir un problema cromosómico adecuado y crear la población inicial

Un IntegerChromosome es una representación natural de la matriz de enteros, cada valor gen se verá limitado en el rango [0,49] para respetar el problema de alcance restricción.

065         IntegerChromosome chrom = new IntegerChromosome(CHROMOSOME_LENGTH,0,MAX_INT);066         Individual<IntegerChromosome> ind = new Individual<IntegerChromosome>(chrom);

Donde MAX_INT esta definido como:

059     private static int MAX_INT = 49;

2. Puesta en marcha del algoritmo genético.

En este tutorial vamos a crear una subclase de GeneticAlogithm llamado PatternGA en wich personalizamos la condición de terminación del algoritmo ovverriding final () método que mejor se expone en el apartado 4.

La aptitud de cada individuo es el error absoluto entre su cromosoma y el cromosoma de destino. Por lo tanto, la mejor individuo es el uno con el error absoluto más pequeño. La función de aptitud se codifica en clase PatternFitness definida como clase interna en PatternGA. En este caso le ofrecemos una definición de un problema de un solo objetivo que ofrece al programador la posibilidad de configurar el esquema de solución esperada y la precisión mínima a alcanzar para detener la búsqueda.

El método de evaluar se mostró a continuación:

67         @Override68         public void evaluate(Individual<IntegerChromosome> individual) {69             IntegerChromosome chrom = individual.getChromosome();70             int diff = 0;71             int length = chrom.length();72             for (int i = 0; i < length; i++) {73                 diff += Math.abs(chrom.getValue(i) - target[i]);74             }75             individual.setScore(diff);76         }

3 . Elija los operadores a utilizar por el algoritmo genético y agregarlos como etapas en la ga.

Supongamos que tenemos dos operadores de cruce diferentes (un punto con probabilidad 0,8 y dos puntos con una probabilidad de 0,5) para aplicarlos en dos subconjuntos de población separados. En Jenes podemos hacer esto a través del uso de la clase paralela. Por lo tanto organizamos los dos operadores de cruce como dos ramas paralelas de la tubería principal.

El dispensador distribuye la población entre las ramas de la etapa en paralelo y se funde la salida de cada rama en la población salida de la etapa paralela. En Jenes hay dos tipos de dispenses : el dispencer general y la dispencer exclusiva . El dispencer en general permite que , durante la operación de distribución, para agregar un individuo en más sucursales ( se requieren copias de la misma persona para evitar la superposición de referencias entre subpopolations sucursales ) . El dispencer exclusiva no lo permite: cada individuo se puede agregar en una sola rama (no es necesario añadir una copia de la misma). Elegimos utilizar un dispencer exclusiva. La aplicación se mostró a continuación.

43 public class SimpleDispenser<T extends Chromosome> extends ExclusiveDispenser<T> {44     45     private int count;46     47     public SimpleDispenser(int span) {48         super(span);49     }50     51     public void preDistribute(Population<T> population){52         this.count = 0;53     }54     55     @Override56     public int distribute(Individual<T> ind) {57         return count++ % span;58     }59     60 }

Esta implementación básica de un dispencer exclusiva utiliza una política de distribución simple. Esto pone a las personas en posiciones pares en la primera rama y los individuos en las posiciones impares en la rama otros. El método preDistribute es útil para restablecer el estado dispencer. El método de distribuir devuelve el índice de la sección donde poner el individuo especificado. No hay que preocuparse por la fusión de la salida de los manojos, ya que se lleva a cabo por la clase ExclusiveDispencer.

El código siguiente muestra cómo crear un escenario paralelo y la inserta en la tubería.

072         AbstractStage<IntegerChromosome> selection = new TournamentSelector<IntegerChromosome>(2);073         074         Parallel<IntegerChromosome> parallel =  new Parallel<IntegerChromosome>(new SimpleDispenser<IntegerChromosome>(2));075         076         AbstractStage<IntegerChromosome> crossover1p = new OnePointCrossover<IntegerChromosome>(0.8);

077         parallel.add(crossover1p);078         079         AbstractStage<IntegerChromosome> crossover2p = new TwoPointsCrossover<IntegerChromosome>(0.5);080         parallel.add(crossover2p);081         082         AbstractStage<IntegerChromosome> mutation = new SimpleMutator<IntegerChromosome>(0.02);083         084         algorithm.addStage(selection);085         algorithm.addStage(parallel);086         algorithm.addStage(mutation);

3. Personalizar el algoritmo genético.

Como se dijo antes la meta de nuestro algoritmo genético es minimizar el error absoluto de los individuos generados, con el fin de obtener una matriz de enteros, tan pronto como sea posible cerca del destino.

En Jenes la evolución del algoritmo genético se ejecuta hasta que alcance el límite de generación especificada o hasta que se cumpla un criterio de terminación. Para especificar el criterio de terminación nuestro algoritmo genético tiene que reemplazar el método "extremo". Por defecto, este método tiene un cuerpo vacío por lo que no tiene ningún efecto sobre la evolución del algoritmo. En nuestro ejemplo, la evolución se detiene cuando el valor de aptitud más bajo es inferior a un valor (denominado precisión) especificado por el usuario.

52     @Override53     protected boolean end() {54         jenes.population.Population.Statistics stat = this.getCurrentPopulation(). getStatistics();55         return stat.getGroup(Population.LEGALS).getMin()[0] <= this.fitness.precision;56     }

La clase GeneticAlgorithm implementa el patrón Observer para notificar a sus oyentes la ocurrencia de un evento en particular. En Jenes hay dos tipos de detectores de eventos: el detector de eventos de generación (invocado cuando finaliza una generación) y el detector de eventos algoritmo (Se invoca cuando un evento occours algoritmo, por ejemplo, el inicio, el final y el inicio del algoritmo).

En este tutorial vamos optar por utilizar un detector de eventos de generación con el fin de imprimir algunas informaciones al final de cada generación. El código de oyente se mostró a continuación.

113     public void onGeneration(GeneticAlgorithm ga, long time) {114         Statistics stat = ga.getCurrentPopulation().getStatistics();

115         Group legals = stat.getGroup(Population.LEGALS);116         System.out.println("Current generation: " + ga.getGeneration());117         System.out.println("\tBest score: " + legals.getMin()[0]);118         System.out.println("\tAvg score : " + legals.getMean()[0]);119     }

El código para añadir un detector de eventos generación en la clase Algoritmo Genético es:

087         algorithm.addGenerationEventListener(this);

En el código siguiente se resumen los principales pasos para la configuración del algoritmo genético.

65         IntegerChromosome chrom = new IntegerChromosome(CHROMOSOME_LENGTH,0,MAX_INT);066         Individual<IntegerChromosome> ind = new Individual<IntegerChromosome>(chrom);067         Population<IntegerChromosome> pop = new Population<IntegerChromosome>(ind,  POPULATION_SIZE);068         069         algorithm = new PatternGA(pop, GENERATION_LIMIT);070         algorithm.setElitism(5);071         072         AbstractStage<IntegerChromosome> selection = new TournamentSelector<IntegerChromosome>(2);073         074         Parallel<IntegerChromosome> parallel =  new Parallel<IntegerChromosome>(new SimpleDispenser<IntegerChromosome>(2));075         076         AbstractStage<IntegerChromosome> crossover1p = new OnePointCrossover<IntegerChromosome>(0.8);077         parallel.add(crossover1p);078         079         AbstractStage<IntegerChromosome> crossover2p = new TwoPointsCrossover<IntegerChromosome>(0.5);080         parallel.add(crossover2p);081         082         AbstractStage<IntegerChromosome> mutation = new SimpleMutator<IntegerChromosome>(0.02);

083         084         algorithm.addStage(selection);085         algorithm.addStage(parallel);086         algorithm.addStage(mutation);087         algorithm.addGenerationEventListener(this);

Ejemplo1:

package jenes.tutorials.problem2;020 021 import jenes.GenerationEventListener;022 import jenes.GeneticAlgorithm;023 import jenes.utils.Random;024 import jenes.chromosome.IntegerChromosome;

025 import jenes.population.Individual;026 import jenes.population.Population;027 import jenes.population.Population.Statistics;028 import jenes.population.Population.Statistics.Group;029 import jenes.stage.AbstractStage;030 import jenes.stage.Parallel;031 import jenes.stage.operator.common.OnePointCrossover;032 import jenes.stage.operator.common.SimpleMutator;033 import jenes.stage.operator.common.TournamentSelector;034 import jenes.stage.operator.common.TwoPointsCrossover;035 import jenes.tutorials.utils.Utils;

054 public class PatternProblem implements GenerationEventListener<IntegerChromosome> {055     056     private static int POPULATION_SIZE = 100;057     private static int CHROMOSOME_LENGTH = 10;058     private static int GENERATION_LIMIT = 1000;059     private static int MAX_INT = 49;060     061     private PatternGA algorithm = null;062     063     public PatternProblem() {064         065         IntegerChromosome chrom = new IntegerChromosome(CHROMOSOME_LENGTH,0,MAX_INT);066         Individual<IntegerChromosome> ind = new Individual<IntegerChromosome>(chrom);067         Population<IntegerChromosome> pop = new Population<IntegerChromosome>(ind, POPULATION_SIZE);068         069         algorithm = new PatternGA(pop, GENERATION_LIMIT);070         algorithm.setElitism(5);071         072         AbstractStage<IntegerChromosome> selection = new TournamentSelector<IntegerChromosome>(2);073         074         Parallel<IntegerChromosome> parallel = new Parallel<IntegerChromosome>(new SimpleDispenser<IntegerChromosome>(2));075         076         AbstractStage<IntegerChromosome> crossover1p = new OnePointCrossover<IntegerChromosome>(0.8);077         parallel.add(crossover1p);078         079         AbstractStage<IntegerChromosome> crossover2p = new TwoPointsCrossover<IntegerChromosome>(0.5);080         parallel.add(crossover2p);081         082         AbstractStage<IntegerChromosome> mutation = new SimpleMutator<IntegerChromosome>(0.02);083         084         algorithm.addStage(selection);085         algorithm.addStage(parallel);

086         algorithm.addStage(mutation);087         algorithm.addGenerationEventListener(this);088     }089     090     public void run(int[] target, int precision) {091         ((PatternGA.PatternFitness) algorithm.getFitness()).setTarget(target);092         ((PatternGA.PatternFitness) algorithm.getFitness()).setPrecision(precision);093         algorithm.evolve();094         095         Population.Statistics stats = algorithm.getCurrentPopulation().getStatistics();096         GeneticAlgorithm.Statistics algostats = algorithm.getStatistics();097         098         System.out.println();099         System.out.print("Target:[");100         for( int i = 0; i < target.length; ++i ) {101             System.out.print(target[i]+ ( i < target.length - 1 ? " " : ""));102         }103         System.out.println("]");104         System.out.println();105         106         System.out.println("Solution: ");107         System.out.println(stats.getGroup(Population.LEGALS).get(0));108         System.out.format("found in %d ms and %d generations.\n", algostats.getExecutionTime(), algostats.getGenerations() );109         System.out.println();110     }111     112     113     public void onGeneration(GeneticAlgorithm ga, long time) {114         Statistics stat = ga.getCurrentPopulation().getStatistics();115         Group legals = stat.getGroup(Population.LEGALS);116         System.out.println("Current generation: " + ga.getGeneration());117         System.out.println("\tBest score: " + legals.getMin()[0]);118         System.out.println("\tAvg score : " + legals.getMean()[0]);119     }120     121     private static void randomize(int[] sample) {122         for(int i=0;i<sample.length;i++)123             sample[i] = Random.getInstance().nextInt(0, MAX_INT+1);124     }125     126     public static void main(String[] args) {127         128         Utils.printHeader();129         System.out.println();130         131         System.out.println("TUTORIAL 2:");132         System.out.println("This algorithm aims to autonomously find a vector of integers that best matches with a target vector.");

133         System.out.println();134         135         Random.getInstance().setStandardSeed();136         137         PatternProblem problem = new PatternProblem();138         int[] target = new int[CHROMOSOME_LENGTH];139         140         randomize(target);141         problem.run(target, 2);142         143         randomize(target);144         problem.run(target, 0);145         146     }147     148 }

Ejemplo2:

19 package jenes.tutorials.problem2;20 21 import jenes.chromosome.Chromosome;22 import jenes.population.Individual;23 import jenes.population.Population;24 import jenes.stage.ExclusiveDispenser;

43 public class SimpleDispenser<T extends Chromosome> extends ExclusiveDispenser<T> {44     45     private int count;46     47     public SimpleDispenser(int span) {48         super(span);49     }50     51     public void preDistribute(Population<T> population){52         this.count = 0;53     }54     55     @Override56     public int distribute(Individual<T> ind) {57         return count++ % span;58     }59     60 }

Ejemplo3:

19 package jenes.tutorials.problem2;20 21 import jenes.Fitness;

22 import jenes.GeneticAlgorithm;23 import jenes.chromosome.IntegerChromosome;24 import jenes.population.Individual;25 import jenes.population.Population;

43 public class PatternGA extends GeneticAlgorithm<IntegerChromosome> {44 45     private PatternFitness fitness = new PatternFitness();46 47     public PatternGA(Population<IntegerChromosome> pop, int numGen) {48         super(pop, numGen);49         this.setFitness(fitness);50     }51     52     @Override53     protected boolean end() {54         jenes.population.Population.Statistics stat = this.getCurrentPopulation().getStatistics();55         return stat.getGroup(Population.LEGALS).getMin()[0] <= this.fitness.precision;56     }57     58     public class PatternFitness extends Fitness<IntegerChromosome> {59 60         private int[] target = null;61         private int precision = 0;62         63         private PatternFitness() {64             super(false);65         }66     67         @Override68         public void evaluate(Individual<IntegerChromosome> individual) {69             IntegerChromosome chrom = individual.getChromosome();70             int diff = 0;71             int length = chrom.length();72             for (int i = 0; i < length; i++) {73                 diff += Math.abs(chrom.getValue(i) - target[i]);74             }75             individual.setScore(diff);76         }77         78         public void setTarget(int[] target) {79             this.target = target;80         }81         82         public void setPrecision(int precision) {83             this.precision = precision;84         }85     }86 }

Redefinición de las operaciones genéticas

En algunas circunstancias el espacio de búsqueda es escasa dentro de un espacio más grande. Este es el caso del problema del agente de viajes, con el objetivo de encontrar una mínima de enrutamiento entre un conjunto de puntos, teniendo en cuenta las distancias entre ellos.

Una forma natural para la representación de una solución es por una permutación de elementos, proporcionando el orden por el que la mínima de enrutamiento visita los puntos. Por lo tanto, un cromosoma es generalmente de Indices de enteros, cada referencia a un punto en particular (ciudad). Los operadores tradicionales de cruce y mutación no aseguran para producir soluciones válidas, es decir, permutaciones, ya que algunas ciudades podrían reproducirse o falta. Hay una necesidad para la redefinición de estas operaciones. En este tutorial se muestran dos formas de realizar esta tarea.

1. El uso o la creación de una clase cromosoma específico2. Redefinir el cruce y mutador

1. El uso o la creación de una clase cromosoma específico.

En Jenes, los operadores genéticos se basan en los primitivos puestos a disposición por la interfaz de cromosomas, tales como cruz, de forma aleatoria, de intercambio y desplazamiento. Por lo tanto, es posible también definir una subclase cromosoma específico con un conjunto de primitivas evitando transformaciones que conducen a soluciones no factibles.

En Jenes la PermutationChromosome es capaz de procesar permutaciones de acuerdo a la siguiente Stategy:

Crossover: alelos en un cromosoma se ordenarán de acuerdo con el orden en que son considerados por el otro cromosoma

Mutación: un alelo se intercambia con otro elegido al azar

El código de código utilizado para configurar el algoritmo y la función de aptitud se mostró a continuación:

127         Individual<PermutationChromosome> sample = new Individual<PermutationChromosome>(new PermutationChromosome(cities));128         Population<PermutationChromosome> pop = new Population<PermutationChromosome>(sample, POPULATION_SIZE);129         130         Fitness<PermutationChromosome> fitness = new Fitness<PermutationChromosome>(false) {131 132             @Override133             public void evaluate(Individual<PermutationChromosome> individual) {134                 PermutationChromosome chrom = individual.getChromosome();135                 double count = 0;136                 int size = chrom.length();137                 for(int i=0;i<size-1;i++){138                     int val1 = chrom.getElementAt(i);139                     int val2 = chrom.getElementAt(i+1);140                     count += TravelSalesmanProblem.this.map[val1][val2];141                 }142                 count += TravelSalesmanProblem.this.map[size-1][0];143                 individual.setScore(count);144             }145             146         };147         148         SimpleGA<PermutationChromosome> sga = new SimpleGA<PermutationChromosome>(fitness, pop, GENERATION_LIMIT);

2. Redefinir el cruce y mutador

Crossover

Redefinición de un crossover es bastante simple. Lo primero que debe hacer es extender la clase del cromosoma.

057 public class TSPCityCenteredCrossover extends Crossover<IntegerChromosome>{

El Crossover Ciudad Centrado, elige una ciudad y volver a ordenar las siguientes ciudades en un cromosoma de acuerdo a la orden dada por el otro. Esta operación se realiza mediante la aplicación del método de cruz.

078     protected void cross(Individual<IntegerChromosome> offsprings[]) {079         080         IntegerChromosome chrom_child1 = offsprings[0].getChromosome();081         IntegerChromosome chrom_child2 = offsprings[1].getChromosome();082         083         if( chrom_parent1 == null ) {084             chrom_parent1 = chrom_child1.clone();085             chrom_parent2 = chrom_child2.clone();086         } else {087             chrom_parent1.setAs(chrom_child1);088             chrom_parent2.setAs(chrom_child2);089         }090         091         final int size = chrom_child1.length();092         if( chrom_child2.length() != size )093             throw new AlgorithmException("Error: the two chromosomes are required to have the same length.");094         095         096         //we choose a random city097         int city = Random.getInstance().nextInt(0, size);098         099         //i1, i2 are the positions of the city respectively in child1 and child2100         int i1 = findPositionOf(city, chrom_child1);101         int i2 = findPositionOf(city, chrom_child2);102         103         int j1 = 0;104         int j2 = 0;105         for( int i = 0; i < size; ++i ) {106             // get the city c1 in position i for parent1107             int c1 = chrom_parent1.getValue(i);108             // find the position of c1 in parent 2109             int p2 = findPositionOf(c1, chrom_parent2);110             // if the position is over the cross-point, it copies c1 in child2111             if( p2 > i2 ) {112                 chrom_child2.setValue(i2 + (++j2), c1);113             }114             115             // similarly we process the other pair116             int c2 = chrom_parent2.getValue(i);117             int p1 = findPositionOf(c2, chrom_parent1);118             if( p1 > i1 ) {119                 chrom_child1.setValue(i1 + (++j1), c2);120             }121         }122     }

Mutador

Redefinir el mutador es sencillo también. En primer lugar, tenemos que crear una subclase de la operadora Mutador.

047 public class TSPScrambleMutator extends Mutator<IntegerChromosome> {

El mutador Scramble se basa en la siguiente estrategia: dos Indices de i1 e i2 se eligen al azar y el orden de los elementos dentro de la gama [i1, i2] cambia aleatoriamente.

Este algoritmo es ejecutado por el método randomize:

081     public void randomize(IntegerChromosome chrom, int min, int max) {082 083         //we create a temporany array084         int len = max-min+1;085         int[] base = new int[len];086 087         //we fill it with the elements within [min,max]088         for(int i=0;i<len;i++)089             base[i]= chrom.getValue(min+i);090         091         //the loop ends when the temporany array is empty092         for( int i = 0; len > 0; --len, ++i) {093             //we choose a random position pos in the array and copy the element at pos in the chromosome094             int pos = Random.getInstance().nextInt(0,len);095             chrom.setValue(min+i,base[pos]);096             //we removes the chosen element from the temporany array097             for(int j=pos;j<(len-1);j++){098                 base[j]=base[j+1];099             }100         }101     }

Ejemplo del tema:

019 package jenes.tutorials.problem3;020 021 import jenes.Fitness;022 import jenes.GeneticAlgorithm;023 import jenes.utils.Random;024 import jenes.algorithms.SimpleGA;025 import jenes.chromosome.IntegerChromosome;026 import jenes.chromosome.PermutationChromosome;027 import jenes.population.Individual;028 import jenes.population.Population;

029 import jenes.population.Population.Statistics.Group;030 import jenes.stage.AbstractStage;031 import jenes.stage.operator.common.TournamentSelector;032 import jenes.tutorials.utils.Utils;

046 public class TravelSalesmanProblem {047     048     public static final int POPULATION_SIZE = 1000;049     private static int GENERATION_LIMIT = 2000;050     public static final int MAX_DISTANCE = 10;051     052     private TSPGA algorithm;053     private int cities;054     private double[][] map;055     056     public static void main(String[] args) {057         058         Utils.printHeader();059         System.out.println();060         061         System.out.println("TUTORIAL 3:");062         System.out.println("The Travel Salesman Problem, a classics.");063         System.out.println();064         065         Random.getInstance().setStandardSeed();066         067         System.out.println("Case 1: 10 cities in circle");068         double[][] m1 = simpleMap(10);069         TravelSalesmanProblem tsp1 = new TravelSalesmanProblem(m1);070         tsp1.solve();071         072         System.out.println("Case 2: 30 cities in circle");073         double[][] m2 = simpleMap(30);074         TravelSalesmanProblem tsp2 = new TravelSalesmanProblem(m2);075         tsp2.solve();076         077         System.out.println("Case 3: 30 cities at random");078         double[][] m3 = randomMap(30);079         TravelSalesmanProblem tsp3 = new TravelSalesmanProblem(m3);080         tsp3.solve();081         082         System.out.println("Case 4: An application of PermutationChromosome");083         tsp2.solvePC();084     }085     086     public TravelSalesmanProblem(double[][] matrix) {087         088         cities = matrix[0].length;089         map = matrix;

090         091         IntegerChromosome chrom = new IntegerChromosome(cities,0,cities-1);092         for( int i = 0; i < cities; ++i ) {093             chrom.setValue(i, i < cities - 1 ? i+1 : 0);094         }095         Individual<IntegerChromosome> sample = new Individual<IntegerChromosome>(chrom);096         Population<IntegerChromosome> pop = new Population<IntegerChromosome>(sample, POPULATION_SIZE);097         098         algorithm = new TSPGA(matrix, pop, GENERATION_LIMIT);099         algorithm.setRandomization(true);100         101         AbstractStage<IntegerChromosome> selection = new TournamentSelector<IntegerChromosome>(1);102         AbstractStage<IntegerChromosome> crossover = new TSPCityCenteredCrossover(0.8);103         AbstractStage<IntegerChromosome> mutation = new TSPScrambleMutator(0.02);104         105         algorithm.addStage(selection);106         algorithm.addStage(crossover);107         algorithm.addStage(mutation);108         109         algorithm.setElitism(10);110     }111     112     public void solve() {113         algorithm.evolve();114         115         Population.Statistics stats = algorithm.getCurrentPopulation().getStatistics();116         GeneticAlgorithm.Statistics algostats = algorithm.getStatistics();117         118         Group legals = stats.getGroup(Population.LEGALS);119         120         System.out.println(legals.get(0));121         System.out.format("found in %d ms and %d generations.\n", algostats.getExecutionTime(), algostats.getGenerations() );122         System.out.println();123     }124     125     public void solvePC() {126         127         Individual<PermutationChromosome> sample = new Individual<PermutationChromosome>(new PermutationChromosome(cities));128         Population<PermutationChromosome> pop = new Population<PermutationChromosome>(sample, POPULATION_SIZE);129         130         Fitness<PermutationChromosome> fitness = new Fitness<PermutationChromosome>(false) {131 132             @Override133             public void evaluate(Individual<PermutationChromosome> individual) {

134                 PermutationChromosome chrom = individual.getChromosome();135                 double count = 0;136                 int size = chrom.length();137                 for(int i=0;i<size-1;i++){138                     int val1 = chrom.getElementAt(i);139                     int val2 = chrom.getElementAt(i+1);140                     count += TravelSalesmanProblem.this.map[val1][val2];141                 }142                 count += TravelSalesmanProblem.this.map[size-1][0];143                 individual.setScore(count);144             }145             146         };147         148         SimpleGA<PermutationChromosome> sga = new SimpleGA<PermutationChromosome>(fitness, pop, GENERATION_LIMIT);149         150         sga.setElitism(10);151         sga.setMutationProbability(0.02);152         sga.evolve();153         154         Population.Statistics stats = sga.getCurrentPopulation().getStatistics();155         GeneticAlgorithm.Statistics algostats = sga.getStatistics();156         157         Group legals = stats.getGroup(Population.LEGALS);158         159         System.out.println(legals.get(0));160         System.out.format("found in %d ms and %d generations.\n", algostats.getExecutionTime(), algostats.getGenerations() );161         System.out.println();162     }163     164     public static double[][] simpleMap( int cities ) {165         double[][] matrix = new double[cities][cities];166         167         matrix[0][0] = 0;168         for( int i = 1; i <= cities/2; ++i) {169             matrix[0][i] = i;170             matrix[0][cities-i] = i;171         }172         173         for( int i = 1; i < cities; ++i ) {174             for( int j = 0; j < cities; ++j ) {175                 matrix[i][(i+j)%cities] = matrix[0][j];176             }177         }178         return matrix;179     }180     

181     public static double[][] randomMap( int cities ) {182         double[][] matrix = new double[cities][cities];183         for( int i = 0; i < cities; ++i ) {184             for( int j = 0; j < cities; ++j ) {185                 matrix[i][j] = i!=j ? Random.getInstance().nextDouble(MAX_DISTANCE) : 0;186             }187         }188         return matrix;189     }190     191 }

Ejemplo del tema:

019 package jenes.tutorials.problem3;020 021 import jenes.utils.Random;022 import jenes.chromosome.IntegerChromosome;023 import jenes.population.Individual;024 import jenes.stage.operator.Mutator;

047 public class TSPScrambleMutator extends Mutator<IntegerChromosome> {048     049     public TSPScrambleMutator(double pMut) {050         super(pMut);051     }052     053     @Override054     protected void mutate(Individual<IntegerChromosome> t) {055         int size = t.getChromosomeLength();056         int index1,index2;057         do{058             index1 = Random.getInstance().nextInt(0,size);059             index2 = Random.getInstance().nextInt(0,size);060         }while(index2==index1);061         062         int min,max;063         if(index1<index2){064             min=index1;065             max=index2;066         }else{067             min=index2;068             max=index1;069         }070         071         randomize(t.getChromosome(),min, max);072     }073     074     /**

075      * Randomizes the elements chromosome within the range [min,max]076      * <p>077      * @param chrom the individual to mutate078      * @param min the lower bound079      * @param max the upper bound080      */081     public void randomize(IntegerChromosome chrom, int min, int max) {082 083         //we create a temporany array084         int len = max-min+1;085         int[] base = new int[len];086 087         //we fill it with the elements within [min,max]088         for(int i=0;i<len;i++)089             base[i]= chrom.getValue(min+i);090         091         //the loop ends when the temporany array is empty092         for( int i = 0; len > 0; --len, ++i) {093             //we choose a random position pos in the array and copy the element at pos in the chromosome094             int pos = Random.getInstance().nextInt(0,len);095             chrom.setValue(min+i,base[pos]);096             //we removes the chosen element from the temporany array097             for(int j=pos;j<(len-1);j++){098                 base[j]=base[j+1];099             }100         }101     }102 }

Ejemplo del tema:

package jenes.tutorials.problem3;

import jenes.Fitness;import jenes.GeneticAlgorithm;import jenes.utils.Random;import jenes.chromosome.IntegerChromosome;import jenes.population.Individual;import jenes.population.Population;

public class TSPGA extends GeneticAlgorithm<IntegerChromosome> {        private double[][] matrix;    private TSPFitness fitness;        public TSPGA(double[][] matrix, Population<IntegerChromosome> pop, int genlimit) {        super(null, pop, genlimit);        this.matrix = matrix;        fitness = new TSPFitness();

        this.setFitness(fitness);    }            @Override    protected void randomizeIndividual(Individual<IntegerChromosome> individual) {        Random rand = Random.getInstance();        int len = individual.getChromosomeLength();        for( int i = 0; i < 100; ++i ) {            int j = rand.nextInt(len);            int k = rand.nextInt(len);            individual.getChromosome().swap(j, k);        }    }

    public class TSPFitness extends Fitness<IntegerChromosome> {

        public TSPFitness() {            super(false);        }

        @Override        public void evaluate(Individual<IntegerChromosome> individual) {            IntegerChromosome chrom = individual.getChromosome();            double count = 0;            int size = chrom.length();            for (int i = 0; i < size - 1; i++) {                int val1 = chrom.getValue(i);                int val2 = chrom.getValue(i + 1);                count += matrix[val1][val2];            }            count += matrix[size - 1][0];

            individual.setScore(count);        }    }        }

Ejemplo del tema:

019 package jenes.tutorials.problem3;020 021 import jenes.AlgorithmException;022 import jenes.utils.Random;023 import jenes.chromosome.IntegerChromosome;024 import jenes.population.Individual;025 import jenes.stage.operator.Crossover;

057 public class TSPCityCenteredCrossover extends Crossover<IntegerChromosome>{058     059     public TSPCityCenteredCrossover(double pCross) {060         super(pCross);061     }062     063     /**064      * Returns the number of chromosomes (i.e. 2) this operator entails.065      */066     @Override067     public int spread() {068         return 2;069     }070     071     private IntegerChromosome chrom_parent1 = null;072     private IntegerChromosome chrom_parent2 = null;073     /**074      * This method implements the crossover operation.075      *076      * @param offsprings the chromosomes to be crossed.077      */078     protected void cross(Individual<IntegerChromosome> offsprings[]) {079         080         IntegerChromosome chrom_child1 = offsprings[0].getChromosome();081         IntegerChromosome chrom_child2 = offsprings[1].getChromosome();082         083         if( chrom_parent1 == null ) {084             chrom_parent1 = chrom_child1.clone();085             chrom_parent2 = chrom_child2.clone();086         } else {087             chrom_parent1.setAs(chrom_child1);088             chrom_parent2.setAs(chrom_child2);089         }090         091         final int size = chrom_child1.length();092         if( chrom_child2.length() != size )093             throw new AlgorithmException("Error: the two chromosomes are required to have the same length.");094         095         096         //we choose a random city097         int city = Random.getInstance().nextInt(0, size);098         099         //i1, i2 are the positions of the city respectively in child1 and child2100         int i1 = findPositionOf(city, chrom_child1);101         int i2 = findPositionOf(city, chrom_child2);102         103         int j1 = 0;104         int j2 = 0;

105         for( int i = 0; i < size; ++i ) {106             // get the city c1 in position i for parent1107             int c1 = chrom_parent1.getValue(i);108             // find the position of c1 in parent 2109             int p2 = findPositionOf(c1, chrom_parent2);110             // if the position is over the cross-point, it copies c1 in child2111             if( p2 > i2 ) {112                 chrom_child2.setValue(i2 + (++j2), c1);113             }114             115             // similarly we process the other pair116             int c2 = chrom_parent2.getValue(i);117             int p1 = findPositionOf(c2, chrom_parent1);118             if( p1 > i1 ) {119                 chrom_child1.setValue(i1 + (++j1), c2);120             }121         }122     }123     124     /**125      * Finds the position of one specific city in the chromosome.126      * <p>127      * @param city the city to find128      * @param chrom the chromosome to search129      * @return the city position130      */131     private int findPositionOf(int city, IntegerChromosome chrom){132         final int size = chrom.length();133         for( int i = 0; i < size; ++i ) {134             if( chrom.getValue(i) == city )135                 return i;136         }137         return -1;138     }139     140 }

Redefinición de las operaciones genéticas

En algunas circunstancias el espacio de búsqueda es escasa dentro de un espacio más grande. Este es el caso del problema del agente de viajes, con el objetivo de encontrar una

mínima de enrutamiento entre un conjunto de puntos, teniendo en cuenta las distancias entre ellos.

Una forma natural para la representación de una solución es por una permutación de elementos, proporcionando el orden por el que la mínima de enrutamiento visita los puntos. Por lo tanto, un cromosoma es generalmente de Indices de enteros, cada referencia a un punto en particular (ciudad). Los operadores tradicionales de cruce y mutación no aseguran para producir soluciones válidas, es decir, permutaciones, ya que algunas ciudades podrían reproducirse o falta. Hay una necesidad para la redefinición de estas operaciones. En este tutorial se muestran dos formas de realizar esta tarea.

1. El uso o la creación de una clase cromosoma específico2. Redefinir el cruce y matador

1. El uso o la creación de una clase cromosoma específico

En Jenes, los operadores genéticos se basan en los primitivos puestos a disposición por la interfaz de cromosomas, tales como cruz, de forma aleatoria, de intercambio y desplazamiento. Por lo tanto, es posible también definir una subclase cromosoma específico con un conjunto de primitivas evitando transformaciones que conducen a soluciones no factibles.

En Jenes la PermutationChromosome es capaz de procesar permutaciones de acuerdo a la siguiente Stategy:

Crossover: alelos en un cromosoma se ordenarán de acuerdo con el orden en que son considerados por el otro cromosoma

Mutación: un alelo se intercambia con otro elegido al azar

El código de código utilizado para configurar el algoritmo y la función de aptitud se mostró a continuación:

127         Individual<PermutationChromosome> sample = new Individual<PermutationChromosome>(new PermutationChromosome(cities));128         Population<PermutationChromosome> pop = new Population<PermutationChromosome>(sample, POPULATION_SIZE);129         130         Fitness<PermutationChromosome> fitness = new Fitness<PermutationChromosome>(false) {131 132             @Override133             public void evaluate(Individual<PermutationChromosome> individual) {

134                 PermutationChromosome chrom = individual.getChromosome();135                 double count = 0;136                 int size = chrom.length();137                 for(int i=0;i<size-1;i++){138                     int val1 = chrom.getElementAt(i);139                     int val2 = chrom.getElementAt(i+1);140                     count += TravelSalesmanProblem.this.map[val1][val2];141                 }142                 count += TravelSalesmanProblem.this.map[size-1][0];143                 individual.setScore(count);144             }145             146         };147         148         SimpleGA<PermutationChromosome> sga = new SimpleGA<PermutationChromosome>(fitness, pop, GENERATION_LIMIT);

2. Redefinir el cruce y mutador

crossover

Redefinición de un crossover es bastante simple. Lo primero que debe hacer es extender la clase del cromosoma.

057 public class TSPCityCenteredCrossover extends Crossover<IntegerChromosome>{

El Crossover Ciudad Centrado, elige una ciudad y volver a ordenar las siguientes ciudades en un cromosoma de acuerdo a la orden dada por el otro. Esta operación se realiza mediante la aplicación del método de cruz.

078     protected void cross(Individual<IntegerChromosome> offsprings[]) {079         080         IntegerChromosome chrom_child1 = offsprings[0].getChromosome();081         IntegerChromosome chrom_child2 = offsprings[1].getChromosome();082         083         if( chrom_parent1 == null ) {084             chrom_parent1 = chrom_child1.clone();085             chrom_parent2 = chrom_child2.clone();086         } else {087             chrom_parent1.setAs(chrom_child1);088             chrom_parent2.setAs(chrom_child2);089         }090         091         final int size = chrom_child1.length();092         if( chrom_child2.length() != size )

093             throw new AlgorithmException("Error: the two chromosomes are required to have the same length.");094         095         096         //we choose a random city097         int city = Random.getInstance().nextInt(0, size);098         099         //i1, i2 are the positions of the city respectively in child1 and child2100         int i1 = findPositionOf(city, chrom_child1);101         int i2 = findPositionOf(city, chrom_child2);102         103         int j1 = 0;104         int j2 = 0;105         for( int i = 0; i < size; ++i ) {106             // get the city c1 in position i for parent1107             int c1 = chrom_parent1.getValue(i);108             // find the position of c1 in parent 2109             int p2 = findPositionOf(c1, chrom_parent2);110             // if the position is over the cross-point, it copies c1 in child2111             if( p2 > i2 ) {112                 chrom_child2.setValue(i2 + (++j2), c1);113             }114             115             // similarly we process the other pair116             int c2 = chrom_parent2.getValue(i);117             int p1 = findPositionOf(c2, chrom_parent1);118             if( p1 > i1 ) {119                 chrom_child1.setValue(i1 + (++j1), c2);120             }121         }122     }

mutador

Redefinir el mutador es sencillo también. En primer lugar, tenemos que crear una subclase de la operadora Mutador.

047 public class TSPScrambleMutator extends Mutator<IntegerChromosome> {

El mutador Scramble se basa en la siguiente estrategia: dos Indices de i1 e i2 se eligen al azar y el orden de los elementos dentro de la gama [i1, i2] cambia aleatoriamente.

Este algoritmo es ejecutado por el método randomize.

081     public void randomize(IntegerChromosome chrom, int min, int max) {082 083         //we create a temporany array

084         int len = max-min+1;085         int[] base = new int[len];086 087         //we fill it with the elements within [min,max]088         for(int i=0;i<len;i++)089             base[i]= chrom.getValue(min+i);090         091         //the loop ends when the temporany array is empty092         for( int i = 0; len > 0; --len, ++i) {093             //we choose a random position pos in the array and copy the element at pos in the chromosome094             int pos = Random.getInstance().nextInt(0,len);095             chrom.setValue(min+i,base[pos]);096             //we removes the chosen element from the temporany array097             for(int j=pos;j<(len-1);j++){098                 base[j]=base[j+1];099             }100         }101     }

Cómo utilizar SimpleGa

En este tutorial se muestra cómo utilizar SimpleGA, una subclase estándar GeneticAlgorithm. Representa la configuración clásica de un algoritmo genético, utilizando sólo los principales operadores (selectores, cruce y mutantes) en un tubo muy simple. Es útil cuando no se necesitan operadores de complejos y se requiere una ga rápida puesta en marcha. El objetivo de este tutorial es para minimizar la entropía de Shannon de un conjunto de valores en el rango [0,1].

1. Elegir un problema cromosómico adecuada y crear la población inicial;

Un DoubleChromosome es adecuado para este problema con cada alelo dentro del rango [0,1].

55         Individual<DoubleChromosome> sample = new Individual<DoubleChromosome>(new DoubleChromosome(CHROMOSOME_LENGTH,0,1));56         Population<DoubleChromosome> pop = new Population<DoubleChromosome>(sample, POPULATION_SIZE);

2. Puesta en marcha del algoritmo genético

Para utilizar SimpleGA tenemos que definir sólo la codificación función de aptitud. En este caso, la aptitud de cada individuo es igual al valor de entropía de acuerdo a la definición clásica de entropía: la entropía es la medida de la cantidad de información que falta antes de la recepción y se refiere a veces como la entropía de Shannon.

38     @Override39     public void evaluate(Individual<DoubleChromosome> individual) {40         DoubleChromosome chrom = individual.getChromosome();41 42         int length = chrom.length();43 44         double sum = 0.0;45         for (int i = 0; i < length; ++i) {46             sum += chrom.getValue(i);47         }48 49         double entropy = 0.0;50         for (int i = 0; i < length; ++i) {51             double pxi = chrom.getValue(i) / sum;52             chrom.setValue(i, pxi);53 54             entropy -= (pxi * Math.log(pxi) / Math.log(2));55         }56 57         individual.setScore(entropy);58     }

3. Elija los operadores a utilizar por el algoritmo genético y agregarlos como etapas en la ga.

Con SimpleGA nuestro algoritmo genético ya está configurado con respecto a los operadores a utilizar. Por defecto se utiliza la selección del torneo (intentos = 2), cruce de un punto (probabilidad = 0,8) y simple mutador (probabilidad = 0,2). Además SimpleGA usa por defecto una estrategia de sustitución de azar para el elitismo. De todos modos, es possibile para modificar esta configuración predeterminada que proporciona diferentes parámetros para los operadores y / o una estrategia de elitismo diferente. En nuestro caso utilizamos la configuración SimpleGA defecto.

4. Personalizar el algoritmo genético

El código de configuración entera se enumeran a continuación:

55         Individual<DoubleChromosome> sample = new Individual<DoubleChromosome>(new DoubleChromosome(CHROMOSOME_LENGTH,0,1));56         Population<DoubleChromosome> pop = new Population<DoubleChromosome>(sample, POPULATION_SIZE);57         

58         ga = new SimpleGA<DoubleChromosome>(null, pop, GENERATION_LIMIT);59         60         System.out.println("Solving Max!:");61         solve( EntropyFitness.MAX );62 63         System.out.println("Solving Min!:");64         solve( EntropyFitness.MIN );

Como puede ver, el algoritmo genético se ha inicializado sin la definición de la función de idoneidad para su uso. Este es possibile en que los casos en wich el gimnasio podría ser determinada sólo en un momento posterior con respecto a la creación del algoritmo genético. De todos modos la definición de una función de aptitud se requiere antes de que el método de evolucionar de GeneticAlgorithm se invoca, y esto es posible sólo hacer la siguiente llamada al método:

68         ga.setFitness(fitness);69         ga.evolve(); 

Ejemplos del tema:

19 package jenes.tutorials.problem4;20 21 import jenes.GeneticAlgorithm;22 import jenes.algorithms.SimpleGA;23 import jenes.chromosome.DoubleChromosome;24 import jenes.population.Individual;25 import jenes.population.Population;26 import jenes.population.Population.Statistics;27 import jenes.population.Population.Statistics.Group;28 import jenes.tutorials.utils.Utils;29 30 /**31  * Tutorial showing how to set-up a minimization problem.32  * The problem is to find a vector whose entroy, after normalization, is minimal.33  *34  * @author Luigi Troiano35  *36  * @version 2.037  * @since 1.038  */39 public class EntropyProblem {40     41     private static int POPULATION_SIZE   = 100;42     private static int CHROMOSOME_LENGTH = 5;43     private static int GENERATION_LIMIT  = 100;44     45     private static GeneticAlgorithm<DoubleChromosome> ga; 46         

47     public static void main(String[] args) {48         Utils.printHeader();49         System.out.println();50         51         System.out.println("TUTORIAL 4:");52         System.out.println("Find the probability distribution that maximizes (or minimize) the Shannon's entropy.");53         System.out.println();54         55         Individual<DoubleChromosome> sample = new Individual<DoubleChromosome>(new DoubleChromosome(CHROMOSOME_LENGTH,0,1));56         Population<DoubleChromosome> pop = new Population<DoubleChromosome>(sample, POPULATION_SIZE);57         58         ga = new SimpleGA<DoubleChromosome>(null, pop, GENERATION_LIMIT);59         60         System.out.println("Solving Max!:");61         solve( EntropyFitness.MAX );62 63         System.out.println("Solving Min!:");64         solve( EntropyFitness.MIN );65     }66     67     private static void solve(EntropyFitness fitness) {68         ga.setFitness(fitness);69         ga.evolve();70         71         Statistics stats = ga.getCurrentPopulation().getStatistics();72         GeneticAlgorithm.Statistics algostats = ga.getStatistics();73         74         Group legals = stats.getGroup(Population.LEGALS);       75         76         System.out.println(legals.get(0));77         System.out.format("found in %d ms.\n", algostats.getExecutionTime() );78         System.out.println();79         80         Utils.printStatistics(stats);        81     }82 }

Ejemplos del tema:

19 package jenes.tutorials.problem4;20 21 import jenes.Fitness;22 import jenes.chromosome.DoubleChromosome;23 import jenes.population.Individual;24 25 /**

26  *27  * @author Luigi Troiano28  */29 public class EntropyFitness extends Fitness<DoubleChromosome> {30 31     public static EntropyFitness MAX = new EntropyFitness(true);32     public static EntropyFitness MIN = new EntropyFitness(false);33 34     private EntropyFitness(boolean maximize) {35         super(maximize);36     }37 38     @Override39     public void evaluate(Individual<DoubleChromosome> individual) {40         DoubleChromosome chrom = individual.getChromosome();41 42         int length = chrom.length();43 44         double sum = 0.0;45         for (int i = 0; i < length; ++i) {46             sum += chrom.getValue(i);47         }48 49         double entropy = 0.0;50         for (int i = 0; i < length; ++i) {51             double pxi = chrom.getValue(i) / sum;52             chrom.setValue(i, pxi);53 54             entropy -= (pxi * Math.log(pxi) / Math.log(2));55         }56 57         individual.setScore(entropy);58     }59 }

ObjectChromosome

En este tutorial se muestra cómo utilizar el ObjectChromosome en Jenes. El ObjectChromosome representa un cromosoma complejo con genes que contienen un valor de alelo objeto. Dado un espacio de búsqueda hecho de variables objeto de cromosomas, nuestro objetivo es encontrar la secuencia más cercana de los valores (representable con objetos específicos) a una de destino. En nuestro problema de ejemplo cada cromosoma tiene cinco genes pertenecientes a diferentes valores de los alelos objeto. El primer gen es un número entero en el intervalo [0,9], el segundo es también un número entero, pero en el intervalo [10,30], la tercera es un número real en el intervalo [0,1], la cuarta es una boolean y el último es un gen que es el alfabeto {NEGRO, ROJO, BLANCO}

1 . Elegir un problema cromosómico adecuada y crear la población inicial ;

Un ObjectChromosome es adecuado para este problema . Contará con cinco genes cada uno de ellos con un conjunto de alelos diferentes : dos conjuntos de alelos entero para los dos primeros genes , la primera con el rango [ 0,9 ] y el segundo con rango [ 10,30 ], un doble alelo fijado para el tercer gen con rango [ 0,1] , un alelo boolean fijado para el gen de la vuelta y un grupo de alelos de la enumeración basada contiene { NEGRO , ROJO, BLANCO } para el último gen .

Para crear instancias de un grupo de alelos que podemos implementar la interfaz AlleleSet o utilizar la clase GenericAlleleSet . El grupo de alelos de número entero se obtiene subclases la clase GenericAlleleSet e implementación de dos métodos de fábrica , que se utiliza para crear instancias de los valores enteros en sus rangos especificados ( los valores son elegidos al azar o con una distribución de probabilidad uniforme en los intervalos especificados ) . El conjunto alelo real se obtiene de la misma manera . El grupo de alelos boolean se obtiene creando un objeto GenericAlleleSet containg los valores booleanos true y false. Por último , se define una enumeración, llamada Color , que contiene los valores NEGRO , rojo y blanco, entonces se crea un objeto GenericAlleleSet con los valores de la enumeración de color. El código se mostró a continuación.

36 public enum Color {37     38     RED, BLACK, WHITE;39     40 }

Ahora podemos construir nuestra representación cromosoma.

053     private static ObjectChromosome template =054             new ObjectChromosome( IntegerAlleleSet.createUniform(10, 0, 9),055             IntegerAlleleSet.createUniform(21, 10, 30),056             DoubleAlleleSet.createRandom(10, 0, 1),057             new GenericAlleleSet<Boolean>(true, false),058             new GenericAlleleSet<Color>(Color.values()) );

2. Puesta en marcha del algoritmo genético

A continuación se muestra el código para evaluar a un individuo en nuestro problema.

062         @Override063         public void evaluate(Individual<ObjectChromosome> individual) {064             ObjectChromosome template = individual.getChromosome();065             066             int i1 = (Integer)template.getValue(0);067             int i2 = (Integer)template.getValue(1);068             double d = (Double)template.getValue(2);069             boolean b = (Boolean)template.getValue(3);070             Color c = (Color)template.getValue(4);071             072             double acc = b ? (3*i1 + 4*i2 + d) : i1;073             074             switch( c ) {075             case BLACK : acc += 10; break;076             case RED   : acc += 10; break;077             case WHITE : acc += 10; break;078             }079             

080             individual.setScore(acc);081         }

En nuestro ejemplo los mejores individuos son los que tienen los valores más altos para el entero y genes dobles, con un verdadero valor para el gen boolean y con cualquier valor para el gen "Color".

Por lo tanto, la mejor persona que esperamos ejecutar este ejemplo podría ser: [9, 30, 0,99, es cierto, NEGRO].

3. Elija los operadores a utilizar por el algoritmo genético y agregarlos como etapas en la ga

En este tutorial se utiliza la configuración simple algoritmo clásico.

098         ga.addStage(new TournamentSelector<ObjectChromosome>(3));099         ga.addStage(new OnePointCrossover<ObjectChromosome>(0.8));100         ga.addStage(new SimpleMutator<ObjectChromosome>(0.02));

4.Personalizar el algoritmo genético

El objetivo global del algoritmo genético es maximizar los valores de fitness. Todo el código es visible en los archivos adjuntos a este tutorial.

Ejemplo de tema:

019 package jenes.tutorials.problem5;020 021 import jenes.Fitness;022 import jenes.GeneticAlgorithm;023 import jenes.chromosome.GenericAlleleSet;024 import jenes.chromosome.ObjectChromosome;025 import jenes.population.Individual;026 import jenes.population.Population;027 import jenes.population.Population.Statistics;028 import jenes.population.Population.Statistics.Group;029 import jenes.stage.operator.common.OnePointCrossover;030 import jenes.stage.operator.common.SimpleMutator;031 import jenes.stage.operator.common.TournamentSelector;032 import jenes.tutorials.utils.Utils;033 034 /**035  * Tutorial illustrating the use of object-oriented chromosomes, whose036  * allele set can be defined by the user for each gene.037  *038  * In this example the chromosomes are combinations of colors. We aim at finding039  * the vector of colors closest to a given sequence.040  *041  * This class defines the problem.

042  *043  * @author Luigi Troiano044  *045  * @version 2.0046  * @since 1.0047  */048 public class OCProblem {049     050     private static int POPULATION_SIZE = 10;051     private static int GENERATION_LIMIT = 100;052     053     private static ObjectChromosome template =054             new ObjectChromosome( IntegerAlleleSet.createUniform(10, 0, 9),055             IntegerAlleleSet.createUniform(21, 10, 30),056             DoubleAlleleSet.createRandom(10, 0, 1),057             new GenericAlleleSet<Boolean>(true, false),058             new GenericAlleleSet<Color>(Color.values()) );059     060     private static Fitness<ObjectChromosome> fitness = new Fitness<ObjectChromosome>(true) {061 062         @Override063         public void evaluate(Individual<ObjectChromosome> individual) {064             ObjectChromosome template = individual.getChromosome();065             066             int i1 = (Integer)template.getValue(0);067             int i2 = (Integer)template.getValue(1);068             double d = (Double)template.getValue(2);069             boolean b = (Boolean)template.getValue(3);070             Color c = (Color)template.getValue(4);071             072             double acc = b ? (3*i1 + 4*i2 + d) : i1;073             074             switch( c ) {075             case BLACK : acc += 10; break;076             case RED   : acc += 10; break;077             case WHITE : acc += 10; break;078             }079             080             individual.setScore(acc);081         }        082     };083     084     private static GeneticAlgorithm<ObjectChromosome> ga =085             new GeneticAlgorithm<ObjectChromosome>( fitness, new Population<ObjectChromosome>(new Individual<ObjectChromosome>(template), POPULATION_SIZE), GENERATION_LIMIT);086         087     088     public static void main(String[] args)throws Exception {089         Utils.printHeader();

090         System.out.println();091         092         System.out.println("TUTORIAL 5:");093         System.out.println("Find the sequence of colors nearest to the target.");094         System.out.println();095         096         //Random.getInstance().setStandardSeed();097         098         ga.addStage(new TournamentSelector<ObjectChromosome>(3));099         ga.addStage(new OnePointCrossover<ObjectChromosome>(0.8));100         ga.addStage(new SimpleMutator<ObjectChromosome>(0.02));101         102         ga.evolve();103         104         Statistics stats = ga.getCurrentPopulation().getStatistics();105         GeneticAlgorithm.Statistics algostats = ga.getStatistics();106 107         Group legals = stats.getGroup(Population.LEGALS);108         109         System.out.println("Solution: ");110         System.out.println(legals.get(0));111         System.out.format("found in %d ms.\n", algostats.getExecutionTime() );112         System.out.println();113         114         Utils.printStatistics(stats);115     }116 }

Ejemplos de tema:

19 package jenes.tutorials.problem5;20 21 22 /**23  * Tutorial illustrating the use of object-oriented chromosomes, whose24  * allele set can be defined by the user for each gene.25  *26  * In this example the chromosomes are combinations of colors. We aim at finding27  * the vector of colors closest to a given sequence.28  *29  * This class defines the enumeration of possible colors.30  *31  * @author Luigi Troiano32  *33  * @version 1.034  * @since 1.035  */36 public enum Color {37     

38     RED, BLACK, WHITE;39     40 }

Ejemplos del tema:

19 package jenes.tutorials.problem5;20 21 import java.util.HashSet;22 import java.util.Set;23 24 import jenes.utils.Random;25 import jenes.chromosome.GenericAlleleSet;26 27 /**28  * Tutorial illustrating the use of object-oriented chromosomes, whose29  * allele set can be defined by the user for each gene.30  *31  * In this example the chromosomes are combinations of colors. We aim at finding32  * the vector of colors closest to a given sequence.33  *34  * This class defines an allele set made of doubles.35  *36  * @author Luigi Troiano37  *38  * @version 1.039  * @since 1.040  */41 42 public class DoubleAlleleSet extends GenericAlleleSet<Double> {43     44     public DoubleAlleleSet(Set<Double> set) {45         super(set);46     }47     48     /**49      * Builds a DoubleAlleleSet with random values within the range [lowerBound,upperBound]50      * <p>51      * @param size the allala set cardinality52      * @param lowerBound the min value to choose53      * @param upperBound the max value to choose54      * @return a new DoubleAlleleSet55      */56     public static DoubleAlleleSet createRandom(int size,  double lowerBound, double upperBound ) {57         HashSet<Double> values = new HashSet<Double>();58         Random rand = Random.getInstance();59         60         for( int i = 0; i < size; ++i  ) {61             values.add(rand.nextDouble(lowerBound, upperBound+Double.MIN_VALUE));

62         }63         64         return new DoubleAlleleSet(values);65     }66     67     /**68      * Builds a new DoubleAlleleSet with uniformly distributed values within the range [lowerBound,upperBound]69      * <p>70      * @param size the allala set cardinality71      * @param lowerBound the min value to choose72      * @param upperBound the max value to choose73      * @return a new DoubleAlleleSet74      */75     public static DoubleAlleleSet createUniform(int size,  int lowerBound, int upperBound ) {76         HashSet<Double> values = new HashSet<Double>();77         78         double step = 1.0/upperBound - lowerBound;79         for( double x = lowerBound; x <= upperBound; x += step ) {80             values.add(x);81         }82         83         return new DoubleAlleleSet(values);84     }85     86     87 }

Ejemplos del tema:

19 package jenes.tutorials.problem5;20 21 import java.util.HashSet;22 import java.util.Set;23 24 import jenes.utils.Random;25 import jenes.chromosome.GenericAlleleSet;26 27 /**28  * Tutorial illustrating the use of object-oriented chromosomes, whose29  * allele set can be defined by the user for each gene.30  *31  * In this example the chromosomes are combinations of colors. We aim at finding32  * the vector of colors closest to a given sequence.33  *34  * This class defines a set of integers.35  *36  * @author Luigi Troiano37  *

38  * @version 1.039  * @since 1.040  */41 public class IntegerAlleleSet extends GenericAlleleSet<Integer> {42     43     public IntegerAlleleSet(Set<Integer> set) {44         super(set);45     }46     47     /**48      * Builds an IntegerAlleleSet with random values within the range [lowerBound,upperBound]49      * <p>50      * @param size the allala set cardinality51      * @param lowerBound the min value to choose52      * @param upperBound the max value to choose53      * @return a new IntegerAlleleSet54      */55     public static IntegerAlleleSet createRandom(int size,  int lowerBound, int upperBound ) {56         HashSet<Integer> values = new HashSet<Integer>();57         int s0 = upperBound - lowerBound + 1;58         if( size > s0 ) size = s0;59         60         Random rand = Random.getInstance();61         62         for( int i = 0; i < s0; ++i  ) {63             64             int chosen = values.size();65             double coin = ((double)size-chosen)/(s0-i);66             boolean justEnough = s0-i == size-chosen;67             68             if( justEnough || rand.nextBoolean(coin) ) {69                 values.add(lowerBound + i);70             }71         }72         73         return new IntegerAlleleSet(values);74     }75     76     /**77      * Builds a new IntegerAlleleSet with uniformly distributed values within the range [lowerBound,upperBound]78      * <p>79      * @param size the allala set cardinality80      * @param lowerBound the min value to choose81      * @param upperBound the max value to choose82      * @return a new IntegerAlleleSet83      */84     public static IntegerAlleleSet createUniform(int size,  int lowerBound, int upperBound ) {85         HashSet<Integer> values = new HashSet<Integer>();

86         int s0 = upperBound - lowerBound + 1;87         if( size > s0 ) size = s0;88         89         double step = 1.0/(upperBound - lowerBound);90         for( double x = lowerBound; x <= upperBound; x += step ) {91             int i = (int) Math.round(x);92             values.add(i);93         }94         95         return new IntegerAlleleSet(values);96     }97     98 }

El uso de metas de algoritmo genético locales

Jenes ofrece la posibilidad de utilizar objetivos de algoritmos genéticos locales. El objetivo global es el utilizado por GeneticAlgorithm durante la evolución de la población en su principal secuencia de etapas. En su lugar, el objetivo local es el utilizado por la sola etapa (por ejemplo, una secuencia contenida en una rama paralela, etc.). Esta tutoriales muestra cómo resolver el problema de la mochila que define dos secuencias paralelas diferentes, con diferentes objetivos internos. El objetivo del problema de la mochila es maximizar la utilidad total de los elementos dentro de la bolsa, sin exceder la capacidad máxima de la bolsa. Tenemos n elementos cada uno con tiene una huella y un valor de utilidad.

1. Elegir un problema cromosómico adecuada y crear la población inicial

Una solución candidata es un conjunto de elementos con un peso y una utilidad. Las soluciones se codifican usando un cromosoma booleano. Los valores boolean Indica si un elemento está presente o no dentro de la bolsa. Por ejemplo, si el gen i-ésimo es verdad, entonces el elemento de orden i está en la bolsa. Un cromosoma con todos los genes que tiene un valor falso representa una bolsa vacía, mientras que un cromosoma con todos los genes que tengan un verdadero valor representa una bolsa con todos los elementos posibles.

070     public KnapsackGA( int popsize, int generations, double[] utilities, double[] weights) {071         super( new Population<BooleanChromosome>(new Individual<BooleanChromosome>(new BooleanChromosome(utilities.length)), popsize), generations);072  

2. Puesta en marcha del algoritmo genético

Ponemos en práctica la clase KnapsackGA subclasificando GeneticAlgorithm e implementación de la función de aptitud como se informa a continuación.

053         @Override054         public void evaluate(Individual<BooleanChromosome> individual) {

055             double utility = KnapsackGA.this.getUtilityOf(individual);056             double weight = KnapsackGA.this.getWeightOf(individual);057             individual.setScore(utility);058             individual.setLegal(weight <= KnapsackGA.this.capacity);059         }

La aptitud de cada solución es igual a la suma de las utilidades de los elementos que contiene. Si el peso total supera la capacidad de la bolsa, entonces el individuo se establece como ilegal. La función de código anterior, utilice los siguientes métodos de utilidad para evaluar la utilidad y el peso de una solución particular.

116     public double getUtilityOf(Individual<BooleanChromosome> individual) {117         BooleanChromosome chrom = individual.getChromosome();118         double utility = 0.0;119         int size = chrom.length();120         for(int i = 0; i < size; ++i){121             utility += chrom.getValue(i) ? this.utilities[i] : 0.0;122         }123         return utility;124     }125     126     public double getWeightOf(Individual<BooleanChromosome> individual) {127         BooleanChromosome chrom = individual.getChromosome();128         double weight=0.0;129         int size = chrom.length();130         for(int i = 0; i < size; ++i){131             weight += chrom.getValue(i) ? this.weights[i] : 0.0;132         }133         return weight;134     } 

3. Elija los operadores a utilizar por el algoritmo genético y agregarlos como etapas en la ga

Decidimos procesar individuos de manera diferente legales e ilegales. Por lo tanto, creamos una secuencia, llamada seq_legal, para procesar persona jurídica y una secuencia, llamada seq_illegal, para procesar los individuos ilegales. Estas secuencias tienen el mismo cuerpo (selector de torneo, un punto de cruce y simple mutador), pero diferentes objetivos. De hecho, el objetivo de seq_legal es maximizar la aptitud de las personas jurídicas, mientras que la de seq_illegal es minimizar la aptitud de las personas ilegales con el fin de eliminar el exceso de elementos y hacer legal la persona.

Evolucionamos en personas legales e ilegales paralelas y en cada generación pasamos las soluciones legales para seq_legal y las soluciones ilegales para seq_illegal a través del uso de un dispensador exclusivo

076         Parallel<BooleanChromosome> parallel =077                 new Parallel<BooleanChromosome>(new ExclusiveDispenser<BooleanChromosome>(2){078             079             @Override080             public int distribute(Individual<BooleanChromosome> ind) {081                 return ind.isLegal() ? 0 :1;

082             }083             084         });085         086         this.setFitness(this.maximize);087         088         Sequence<BooleanChromosome> seq_legal = new Sequence<BooleanChromosome>();089         seq_legal.appendStage(new TournamentSelector<BooleanChromosome>(2));090         seq_legal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8));091         seq_legal.appendStage(new SimpleMutator<BooleanChromosome>(0.02));092         093         Sequence<BooleanChromosome> seq_illegal = new Sequence<BooleanChromosome>();094         seq_illegal.appendStage(new TournamentSelector<BooleanChromosome>(2));095         seq_illegal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8));096         seq_illegal.appendStage(new SimpleMutator<BooleanChromosome>(0.2));097         098         parallel.add(seq_legal);099         parallel.add(seq_illegal);100         101         this.addStage(parallel);102         103         seq_legal.setFitness(this.maximize);104         seq_illegal.setFitness(this.minimize);

Ejemplo del tema:

019 package jenes.tutorials.problem6;020 021 import jenes.utils.Random;022 import jenes.population.Individual;023 import jenes.population.Population;024 import jenes.population.Population.Statistics;025 import jenes.population.Population.Statistics.Group;026 import jenes.tutorials.utils.Utils;027 028 /**029  * Tutorial showing how to minimization and maximization sub-prolems can cohesists in030  * the breeding structure of Jenes.031  *032  * This class defines the problem to solve.033  *034  * @author Luigi Troiano035  *036  * @version 1.0037  * @since 1.0038  */039 public class KnapsackProblem {040     041     private static int POPSIZE=100;

042     private static int GENERATION_LIMIT=100;043     044     private static final double[] WEIGHTS = {1, 5, 3, 2, 8, 6, 4, 7, 9, 6};045     private static final double[] UTILITIES = {7, 2, 7, 1, 6, 4, 2, 8, 9, 2};046     047     private KnapsackGA algorithm;048     private double[] utilities;049     private double[] weights;050     051     public KnapsackProblem(double[] utilities, double[] weights) {052         algorithm = new KnapsackGA(POPSIZE, GENERATION_LIMIT, utilities, weights);053         this.weights = weights;054         this.utilities = utilities;055     }056     057     @SuppressWarnings("unchecked")058     public void run() {059         this.algorithm.evolve();060         061         Statistics stat=algorithm.getCurrentPopulation().getStatistics();062         Group legals = stat.getGroup(Population.LEGALS);063         Individual solution= legals.get(0);064         System.out.println(solution.getChromosome());065         System.out.format("W: %f U: %f\n", algorithm.getWeightOf(solution), algorithm.getUtilityOf(solution) );066     }067     068     public double getCapacity() {069         return this.algorithm.getCapacity();070     }071     072     public void setCapacity(double c) {073         this.algorithm.setCapacity(c);074     }075     076     public double[] getUtilities() {077         return utilities;078     }079     080     public double[] getWeights() {081         return weights;082     }083     084     public static KnapsackProblem build(int n) {085         086         Random r = Random.getInstance();087         088         double[] utilities = new double[n];089         for( int i = 0; i < n; ++i ) {

090             utilities[i] = r.nextInt(10);091         }092         093         double[] weights = new double[n];094         for( int i = 0; i < n; ++i ) {095             weights[i] = r.nextInt(10);096         }097         098         return new KnapsackProblem(utilities, weights);099     }100     101     public static void main(String[] args) {102         103         Utils.printHeader();104         System.out.println();105         106         System.out.println("TUTORIAL 6:");107         System.out.println("The Knapsack Problem.");108         System.out.println();109         110         KnapsackProblem p1 = new KnapsackProblem(UTILITIES, WEIGHTS);111         112         System.out.println("Case 1: 10 elements, capacity 15");113         System.out.println("Utilities: " + toString(p1.getUtilities()) );114         System.out.println("  Weights: " + toString(p1.getWeights()) );115         p1.setCapacity(15);116         p1.run();117         System.out.println();118         119         System.out.println("Case 2: 10 elements, capacity 30");120         System.out.println("Utilities: " + toString(p1.getUtilities()) );121         System.out.println("  Weights: " + toString(p1.getWeights()) );122         p1.setCapacity(30);123         p1.run();124         System.out.println();125         126         KnapsackProblem p2 = KnapsackProblem.build(20);127         128         System.out.println("Case 3: 20 random elements, capacity 50");129         System.out.println("Utilities: " + toString(p2.getUtilities()) );130         System.out.println("  Weights: " + toString(p2.getWeights()) );131         p2.setCapacity(50);132         p2.run();133         System.out.println();134     }135     136     private static String toString(double[] values) {137         String s = "[";138         for(int i = 0; i < values.length; ++i ){

139             s += values[i]+ (i < values.length-1 ? " " : "]");140         }141         return s;142     }143     144 }

Ejemplo del tema:

019 package jenes.tutorials.problem6;020 021 import jenes.Fitness;022 import jenes.GeneticAlgorithm;023 import jenes.chromosome.BooleanChromosome;024 import jenes.population.Individual;025 import jenes.population.Population;026 import jenes.stage.ExclusiveDispenser;027 import jenes.stage.Parallel;028 import jenes.stage.Sequence;029 import jenes.stage.operator.common.OnePointCrossover;030 import jenes.stage.operator.common.SimpleMutator;031 import jenes.stage.operator.common.TournamentSelector;032 033 /**034  * Tutorial showing how to minimization and maximization sub-prolems can cohesists in035  * the breeding structure of Jenes.036  *037  * This class implements a genetic algorithm for solving the Knapsack problem.038  *039  * @author Luigi Troiano040  *041  * @version 2.0042  *043  * @since 1.0044  */045 public class KnapsackGA extends GeneticAlgorithm<BooleanChromosome>{046     047     private class KnapsackFitness extends Fitness<BooleanChromosome> {048                 049         private KnapsackFitness(boolean maximize) {050             super( maximize );051         }052         053         @Override054         public void evaluate(Individual<BooleanChromosome> individual) {055             double utility = getUtilityOf(individual);056             double weight = getWeightOf(individual);057             individual.setScore(utility);058             individual.setLegal(weight <= KnapsackGA.this.capacity);

059         }060         061     }062     063     private double capacity;064     private double[] weights;065     private double[] utilities;066     067     private KnapsackFitness maximize = new KnapsackFitness(true);068     private KnapsackFitness minimize = new KnapsackFitness(false);069 070     public KnapsackGA( int popsize, int generations, double[] utilities, double[] weights) {071         super( new Population<BooleanChromosome>(new Individual<BooleanChromosome>(new BooleanChromosome(utilities.length)), popsize), generations);072         073         this.utilities = utilities;074         this.weights = weights;075         076         Parallel<BooleanChromosome> parallel =077                 new Parallel<BooleanChromosome>(new ExclusiveDispenser<BooleanChromosome>(2){078             079             @Override080             public int distribute(Individual<BooleanChromosome> ind) {081                 return ind.isLegal() ? 0 :1;082             }083             084         });085         086         this.setFitness(this.maximize);087         088         Sequence<BooleanChromosome> seq_legal = new Sequence<BooleanChromosome>();089         seq_legal.appendStage(new TournamentSelector<BooleanChromosome>(2));090         seq_legal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8));091         seq_legal.appendStage(new SimpleMutator<BooleanChromosome>(0.02));092         093         Sequence<BooleanChromosome> seq_illegal = new Sequence<BooleanChromosome>();094         seq_illegal.appendStage(new TournamentSelector<BooleanChromosome>(2));095         seq_illegal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8));096         seq_illegal.appendStage(new SimpleMutator<BooleanChromosome>(0.2));097         098         parallel.add(seq_legal);099         parallel.add(seq_illegal);100         101         this.addStage(parallel);102         103         seq_legal.setFitness(this.maximize);104         seq_illegal.setFitness(this.minimize);105     }106     

107     public double getCapacity() {108         return this.capacity;109     }110     111     112     public void setCapacity(double capacity) {113         this.capacity = capacity;114     }115     116     public double getUtilityOf(Individual<BooleanChromosome> individual) {117         BooleanChromosome chrom = individual.getChromosome();118         double utility = 0.0;119         int size = chrom.length();120         for(int i = 0; i < size; ++i){121             utility += chrom.getValue(i) ? this.utilities[i] : 0.0;122         }123         return utility;124     }125     126     public double getWeightOf(Individual<BooleanChromosome> individual) {127         BooleanChromosome chrom = individual.getChromosome();128         double weight=0.0;129         int size = chrom.length();130         for(int i = 0; i < size; ++i){131             weight += chrom.getValue(i) ? this.weights[i] : 0.0;132         }133         return weight;134     }    135     136 }

Registro de las estadísticas

Experimentar con algoritmo genético requiere a menudo para recopilar datos sobre la evolución a lo largo de los diferentes experimentos. En este tutorial vamos a aprender a capturar estadísticas evolución en. Csv y los archivos de MS Excel.

Los madereros

Hay dos tres métodos para registrar las estadísticas en Jenes. La primera es hacerlo usted mismo por guardar los datos en un archivo o base de datos. Los otros dos se basan en los registradores disponibles desde Jenes 1.3.0. La forma más fácil es usar un StatisticsLogger. Esta clase es capaz de grabar automáticamente los objetos que pertenecen desde LoggableStatistics, por ejemplo, Population.Statistics y objetos GeneticAlgorithm.Statistics. StatisticsLogger basa en un registrador real para grabar realmente los datos en algún medio. Por ejemplo, se puede hacer uso de un CSVLogger para grabar en. Csv (es decir, valores separados por comas) archive

072         csvlogger = new StatisticsLogger(073                     new CSVLogger(new String[]{"LegalHighestScore", "LegalScoreAvg","LegalScoreDev"}, FOLDER + "knapsackproblem.csv" ) );

o XLSLogger para grabar directamente en un archivo xls MS Excel.

075         xlslogge1 = new StatisticsLogger(076                     new XLSLogger(new String[]{"LegalHighestScore", "LegalScoreAvg","LegalScoreDev"}, FOLDER + "knapsack1.log.xls" ) );

En algún momento es útil volver a utilizar un spreedsheet. En este caso, podemos especificar que plantilla se usan en el método constructor de XLSLogger.

078         xlslogge2 = new StatisticsLogger(079                     new XLSLogger(new String[]{"LegalHighestScore", "LegalScoreAvg" , "IllegalScoreAvg"}, FOLDER + "knapsack2.log.xls", FOLDER +"knapsack.tpl.xls" ) );

El tercer método hace uso directo de registrador real, por ejemplo

081         xlslogge3 = new XLSLogger(new String[]{"LegalHighestScore", "LegalScoreAvg" , "Run"}, FOLDER + "knapsack3.log.xls");

Esquema

Los madereros son capaces de procesar datos tabulares con un esquema determinado, es decir, un conjunto de campos etiquetados. El esquema de datos se tiene que dar en el momento de la construcción. Por ejemplo, en el primer y segundo caso estamos interesados en grabar LegalHighestScore, LegalScoreAvg y LegalScoreDev

largo de las generaciones. En el tercer caso grabamos LegalHighestScore, LegalScoreAvg y IllegalScoreAvg. Finalmente, en el tercer caso grabamos LegalHighestScore, LegalScoreAvg and Run, representando este último el número de ejecución de la experimentación.

Si utilizamos StatisticsLogger, los campos tienen que ser etiquetados de la misma manera las estadísticas son anotados por registrable (etiqueta). Si utilizamos directamente los madereros reales, podemos hacer uso de distintivos que deseamos para el esquema, como el mapeo estará en nuestro poder, como se describe a continuación.

Tenga en cuenta que el esquema entre mayúsculas y minúsculas, por lo que "someStatistic" es diferente de "SomeStatistic", y ambos son diferentes de "SOMESTATISTIC".

Medios de comunicación

Grabación en. Csv es sencillo. Si el archivo existe, se puede decidir si desea sobrescribir los datos (por defecto) o para añadir datos.

Cuando usamos. Xls debemos cuidar algunos detalles. Cuando no existe el archivo de registro, el registrador crea un libro vacío con una hoja, donde las columnas se asignan de acuerdo con el esquema con primera fila asignada a las etiquetas de campo.

Podemos optar por utilizar un pre-hechos xls.. En este caso tenemos que reservar una columna para cada campo en el esquema. La columna puede colocarse en cualquier parte de la hoja, que la hoja no importa. La única restricción es que la celda en la fila 1 debe contener la etiqueta del campo. También podemos optar por utilizar un archivo xls. Como plantilla. Una plantilla es simplemente un archivo de pre-hechos. En este caso, el archivo no se sobrescribe como el destino es diferente (ver xlslogge2 para un ejemplo).

Por ejemplo, podemos decidir utilizar la plantilla se muestra en la Figura 1.

Recolección de Datos

Una vez que los madereros están establecidos y esquema definido, podemos recoger datos. La mejor manera de recoger los datos es por medio de oyentes. Por ejemplo

143         GenerationEventListener<BooleanChromosome> logger1 = new GenerationEventListener<BooleanChromosome>() {144 145             public void onGeneration(GeneticAlgorithm ga, long time) {146                 Population.Statistics stats = ga.getCurrentPopulation().getStatistics();147                 148                 prb.csvlogger.record(stats);149                 prb.xlslogge1.record(stats);150                 prb.xlslogge2.record(stats);151 152             }153 154         };

En este caso StatisticsLogger se encarga de registrar datos. Tan sólo hay que proporcionar una LoggableStatistics y StatisticsLogger haremos el trabajo por nosotros. El inconveniente de esta solución es que no somos capaces de añadir datos no considerados por el objeto de estadísticas. Para obtener un control más preciso del proceso, podemos hacer uso directo de un registrador real. Por ejemplo

172         GenerationEventListener<BooleanChromosome> logger2 = new GenerationEventListener<BooleanChromosome>() {173             public void onGeneration(GeneticAlgorithm ga, long time) {174                 Population.Statistics stats = ga.getCurrentPopulation().getStatistics();175 176                 Group legals = stats.getGroup(Population.LEGALS);177                 178                 prb.xlslogge3.put("LegalHighestScore", legals.getMax());179                 prb.xlslogge3.put("LegalScoreAvg", legals.getMin());180                 prb.xlslogge3.put("Run", prb.exec);181 182                 prb.xlslogge3.log();183             }184 185         };

Entrar cierre

Por último, podemos hacer que los datos persistentes cerrando los madereros.

165         prb.csvlogger.close();166         prb.xlslogge1.close();167         prb.xlslogge2.close();

195         prb.xlslogge3.close();

Salida

La salida consiguió al final se representa en las figuras siguientes. Ver también los archivos adjuntos de abajo.

Ejemplos del tema:

019 package jenes.tutorials.problem7;020 021 import java.io.File;022 import java.io.FileNotFoundException;023 import java.io.IOException;024 import jenes.GenerationEventListener;025 import jenes.GeneticAlgorithm;026 import jenes.chromosome.BooleanChromosome;027 import jenes.utils.Random;028 import jenes.population.Individual;029 import jenes.population.Population;030 import jenes.population.Population.Statistics;031 import jenes.population.Population.Statistics.Group;032 import jenes.tutorials.utils.Utils;033 import jenes.utils.CSVLogger;034 import jenes.statistics.StatisticsLogger;035 import jenes.tutorials.problem6.KnapsackGA;036 import jenes.utils.XLSLogger;037 038 /**039  * A tutorial showing how to log statistics on different media.040  *041  * @author Luigi Troiano042  *043  * @version 1.3044  *045  * @since 1.3046  */047 public class KnapsackLoggedProblem  {048     049     private static int POPSIZE=20;050     private static int GENERATION_LIMIT=100;051     052     private static final double[] WEIGHTS = {1, 5, 3, 2, 8, 6, 4, 7, 9, 6};053     private static final double[] UTILITIES = {7, 2, 7, 1, 6, 4, 2, 8, 9, 2};054     

055     private KnapsackGA algorithm;056     private double[] utilities;057     private double[] weights;058     059     private StatisticsLogger csvlogger;060     private StatisticsLogger xlslogge1;061     private StatisticsLogger xlslogge2;062     private XLSLogger xlslogge3;063     private int exec;064 065     private final String FOLDER = "files.Tutorial7" + File.separatorChar;066 067     public KnapsackLoggedProblem(double[] utilities, double[] weights) throws IOException {068         algorithm = new KnapsackGA(POPSIZE, GENERATION_LIMIT, utilities, weights);069         this.weights = weights;070         this.utilities = utilities;071 072         csvlogger = new StatisticsLogger(073                     new CSVLogger(new String[]{"LegalHighestScore","LegalScoreAvg","LegalScoreDev"}, FOLDER+"knapsackproblem.csv" ) );074 075         xlslogge1 = new StatisticsLogger(076                     new XLSLogger(new String[]{"LegalHighestScore","LegalScoreAvg","LegalScoreDev"}, FOLDER+"knapsack1.log.xls" ) );077 078         xlslogge2 = new StatisticsLogger(079                     new XLSLogger(new String[]{"LegalHighestScore", "LegalScoreAvg" , "IllegalScoreAvg"}, FOLDER+"knapsack2.log.xls", FOLDER+"knapsack.tpl.xls" ) );080 081         xlslogge3 = new XLSLogger(new String[]{"LegalHighestScore", "LegalScoreAvg" , "Run"}, FOLDER+"knapsack3.log.xls");082 083     }084     085     @SuppressWarnings("unchecked")086     public void run() {087         this.algorithm.evolve();088         089         Statistics stat=algorithm.getCurrentPopulation().getStatistics();090         Individual solution=stat.getLegalHighestIndividual();091         System.out.println(solution.getChromosome());092         System.out.format("W: %f U: %f\n", algorithm.getWeightOf(solution), algorithm.getUtilityOf(solution) );093     }094     095     public double getCapacity() {096         return this.algorithm.getCapacity();097     }098     

099     public void setCapacity(double c) {100         this.algorithm.setCapacity(c);101     }102     103     public double[] getUtilities() {104         return utilities;105     }106     107     public double[] getWeights() {108         return weights;109     }110     111     public static KnapsackLoggedProblem build(int n) throws FileNotFoundException, IOException {112         113         Random r = Random.getInstance();114         115         double[] utilities = new double[n];116         for( int i = 0; i < n; ++i ) {117             utilities[i] = r.nextInt(10);118         }119         120         double[] weights = new double[n];121         for( int i = 0; i < n; ++i ) {122             weights[i] = r.nextInt(10);123         }124         125         return new KnapsackLoggedProblem(utilities, weights);126     }127     128     public static void main(String[] args) throws FileNotFoundException, IOException {129         130         Utils.printHeader();131         System.out.println();132         133         System.out.println("TUTORIAL 7:");134         System.out.println("Logging the Knapsack Problem.");135         System.out.println();136         137         final KnapsackLoggedProblem prb = KnapsackLoggedProblem.build(20);138 139         System.out.println("Utilities: " + toString(prb.getUtilities()) );140         System.out.println("  Weights: " + toString(prb.getWeights()) );141         System.out.println();142 143         GenerationEventListener<BooleanChromosome> logger1 = new GenerationEventListener<BooleanChromosome>() {144 145             public void onGeneration(GeneticAlgorithm ga, long time) {146                 Population.Statistics stats = ga.getCurrentPopulation().getStatistics();

147                 148                 prb.csvlogger.record(stats);149                 prb.xlslogge1.record(stats);150                 prb.xlslogge2.record(stats);151 152             }153 154         };155 156         prb.algorithm.addGenerationEventListener(logger1);157 158 159         System.out.println("50 random elements, capacity 50");160         prb.setCapacity(50);161         prb.run();162         System.out.println();163 164         System.out.println("Saving the logs ...");165         prb.csvlogger.close();166         prb.xlslogge1.close();167         prb.xlslogge2.close();168         System.out.println("Done.");169 170         prb.algorithm.removeGenerationEventListener(logger1);171 172         GenerationEventListener<BooleanChromosome> logger2 = new GenerationEventListener<BooleanChromosome>() {173             public void onGeneration(GeneticAlgorithm ga, long time) {174                 Population.Statistics stats = ga.getCurrentPopulation().getStatistics();175 176                 Group legals = stats.getGroup(Population.LEGALS);177                 178                 prb.xlslogge3.put("LegalHighestScore", legals.getMax());179                 prb.xlslogge3.put("LegalScoreAvg", legals.getMin());180                 prb.xlslogge3.put("Run", prb.exec);181 182                 prb.xlslogge3.log();183             }184 185         };186 187         prb.algorithm.addGenerationEventListener(logger2);188 189         System.out.println();190         System.out.println("Repeating 10 times: 20 random elements, capacity 50");191         for( prb.exec = 0; prb.exec < 10; ++prb.exec) {192              System.out.println((prb.exec+1) + " of 10");193              prb.run();194         }

195         prb.xlslogge3.close();196         System.out.println("Done.");197     }198     199     private static String toString(double[] values) {200         String s = "[";201         for(int i = 0; i < values.length; ++i ){202             s += values[i]+ (i < values.length-1 ? " " : "]");203         }204         return s;205     }206     207 }