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...
Todas las clases de cromosomas son la implementación de la interfaz del cromosoma. En
general, los cromosomas se fija núme...
Básicamente, un algoritmo genético realiza el siguiente bucle:
Aleatoriamente crear una población inicial
repetición
Valor...
En Jenes cuerpo algoritmo genético es un "tubo" de etapas. Las etapas se ejecutan
secuencialmente en el orden en que se ag...
asegurar que incluso los individuos de calidad media tienen alguna posibilidad de tener
hijos. En Jenes es necesario espec...
La clase proporciona un conjunto de constructores por lo que crear una instancia de un
algoritmo SimpleGA. Constructores p...
La ejecución del algoritmo genético es invocado por el método de evolucionar (). La
ejecución del algoritmo pasa a través ...
Población: La clase Population.Statistics se encarga de almacenar información sobre una
población. A medida que cada lata ...
Un problema boolean sencilla
Vamos a empezar con un problema sencillo. Dado un espacio de búsqueda hecha de
variables bool...
Cualquier algoritmo en Jenes se basa en GeneticAlgorithm, una clase abstracta cuyo único
método es abstracto evaluateIndiv...
tubo más complejo que tiene paralléles y secuencias. A los efectos de este tutorial vamos a
adoptar la siguiente estructur...
104
105
106
107
108

System.out.println( solution );
System.out.format("found in %d ms.n", algostats.getExecutionTime() );...
@Override
public void evaluate(Individual<BooleanChromosome> individual) {
BooleanChromosome chrom = individual.getChromos...
Estructuración de un algoritmo genético avanzado
En nuestro segundo tutorial mostramos cómo crear un escenario paralelo y ...
065
066

IntegerChromosome chrom = new IntegerChromosome(CHROMOSOME_LENGTH,0,MAX_INT);
Individual<IntegerChromosome> ind =...
El dispensador distribuye la población entre las ramas de la etapa en paralelo y se funde la
salida de cada rama en la pob...
077
parallel.add(crossover1p);
078
079
AbstractStage<IntegerChromosome> crossover2p = new TwoPointsCrossover<IntegerChromo...
115
116
117
118
119

Group legals = stat.getGroup(Population.LEGALS);
System.out.println("Current generation: " + ga.getGe...
025 import jenes.population.Individual;
026 import jenes.population.Population;
027 import jenes.population.Population.Sta...
086
algorithm.addStage(mutation);
087
algorithm.addGenerationEventListener(this);
088 }
089
090 public void run(int[] targ...
133
134
135
136
137
138
139
140
141
142
143
144
145
146 }
147
148 }

System.out.println();
Random.getInstance().setStandar...
22 import jenes.GeneticAlgorithm;
23 import jenes.chromosome.IntegerChromosome;
24 import jenes.population.Individual;
25 ...
Redefinición de las operaciones genéticas
En algunas circunstancias el espacio de búsqueda es escasa dentro de un espacio ...
Crossover: alelos en un cromosoma se ordenarán de acuerdo con el orden en que son
considerados por el otro cromosoma
Mutac...
078 protected void cross(Individual<IntegerChromosome> offsprings[]) {
079
080
IntegerChromosome chrom_child1 = offsprings...
Mutador
Redefinir el mutador es sencillo también. En primer lugar, tenemos que crear una subclase
de la operadora Mutador....
029 import jenes.population.Population.Statistics.Group;
030 import jenes.stage.AbstractStage;
031 import jenes.stage.oper...
090
091
IntegerChromosome chrom = new IntegerChromosome(cities,0,cities-1);
092
for( int i = 0; i < cities; ++i ) {
093
ch...
134
PermutationChromosome chrom = individual.getChromosome();
135
double count = 0;
136
int size = chrom.length();
137
for...
181 public static double[][] randomMap( int cities ) {
182
double[][] matrix = new double[cities][cities];
183
for( int i ...
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102 }

* <p>
* @pa...
@Override
protected void randomizeIndividual(Individual<IntegerChromosome> individual) {
Random rand = Random.getInstance(...
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
09...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
13...
Una forma natural para la representación de una solución es por una permutación de
elementos, proporcionando el orden por ...
139
int val2 = chrom.getElementAt(i+1);
140
count += TravelSalesmanProblem.this.map[val1][val2];
141
}
142
count += Travel...
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

int city = Random...
089
090
091
092
093
094
095
096
097
098
099
100
101

base[i]= chrom.getValue(min+i);
//the loop ends when the temporany ar...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

@Override
public void evaluate(Individual<DoubleChromosome...
63
64

System.out.println("Solving Min!:");
solve( EntropyFitness.MIN );

Como puede ver, el algoritmo genético se ha inic...
52
System.out.println("Find the probability distribution that maximizes (or minimize) the Shannon's entr
opy.");
53
System...
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 }

public static EntropyFitness MAX...
ObjectChromosome

En este tutorial se muestra cómo utilizar el ObjectChromosome en Jenes. El
ObjectChromosome representa u...
especificados ) . El conjunto alelo real se obtiene de la misma manera . El grupo de alelos
boolean se obtiene creando un ...
En nuestro ejemplo los mejores individuos son los que tienen los valores más altos para el
entero y genes dobles, con un v...
044 *
045 * @version 2.0
046 * @since 1.0
047 */
048 public class OCProblem {
049
050 private static int POPULATION_SIZE =...
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 }
116 }

System.out.printl...
39
40 }
Ejemplos del tema:
19 package jenes.tutorials.problem5;
20
21 import java.util.HashSet;
22 import java.util.Set;
2...
63
64
return new DoubleAlleleSet(values);
65 }
66
67 /**
68
* Builds a new DoubleAlleleSet with uniformly distributed valu...
39 * @since 1.0
40 */
41 public class IntegerAlleleSet extends GenericAlleleSet<Integer> {
42
43 public IntegerAlleleSet(S...
87
88
89
90
91
92
93
94
95
96 }
97
98 }

if( size > s0 ) size = s0;
double step = 1.0/(upperBound - lowerBound);
for( doub...
056
057
058
059

double weight = KnapsackGA.this.getWeightOf(individual);
individual.setScore(utility);
individual.setLega...
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104

});
this.setFitness(this.maximize);
S...
044 private static final double[] WEIGHTS = {1, 5, 3, 2, 8, 6, 4, 7, 9, 6};
045 private static final double[] UTILITIES = ...
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
12...
141
return s;
142 }
143
144 }
Ejemplo del tema:
019 package jenes.tutorials.problem6;
020
021 import jenes.Fitness;
022 im...
061 }
062
063 private double capacity;
064 private double[] weights;
065 private double[] utilities;
066
067 private Knaps...
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 }

}

publ...
Registro de las estadísticas

Experimentar con algoritmo genético requiere a menudo para recopilar datos sobre la evolució...
Finalmente, en el tercer caso grabamos LegalHighestScore, LegalScoreAvg and Run, representando este
último el número de ej...
Recolección de Datos

Una vez que los madereros están establecidos y esquema definido, podemos recoger datos.
La mejor man...
Anatomía de un algoritmo genético en jenes
Anatomía de un algoritmo genético en jenes
Anatomía de un algoritmo genético en jenes
Anatomía de un algoritmo genético en jenes
Anatomía de un algoritmo genético en jenes
Upcoming SlideShare
Loading in...5
×

Anatomía de un algoritmo genético en jenes

471

Published on

buena libreria para algoritmo geneticos

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
471
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Anatomía de un algoritmo genético en jenes

  1. 1. 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.
  2. 2. 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.
  3. 3. 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.
  4. 4. 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
  5. 5. 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.
  6. 6. 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
  7. 7. 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 .
  8. 8. 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.
  9. 9. 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 BooleanC hromosome(CHROMOSOME_LENGTH)); 061 Population<BooleanChromosome> pop = new Population<BooleanChromosome>(sample, POPUL ATION_SIZE); cuando 045 046 047 private static int POPULATION_SIZE=50; private static int CHROMOSOME_LENGTH=100; 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).
  10. 10. 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 064 065 066 067 068 069 070 071 072 073 074 075 076 077 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); } }; Y luego pasar este objeto como primer parámetro de algoritmo genético (o cualquier subclase predefinido) 079 080 GeneticAlgorithm<BooleanChromosome> ga = new GeneticAlgorithm<BooleanChromosome> (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
  11. 11. 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 083 ); 084 085 086 087 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); 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 094 095 096 ")); 097 098 099 100 101 102 103 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: ");
  12. 12. 104 105 106 107 108 System.out.println( solution ); System.out.format("found in %d ms.n", algostats.getExecutionTime() ); System.out.println(); 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 BooleanChro mosome(CHROMOSOME_LENGTH)); Population<BooleanChromosome> pop = new Population<BooleanChromosome>(sample, POPULATI ON_SIZE); Fitness<BooleanChromosome> fit = new Fitness<BooleanChromosome>(false) {
  13. 13. @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); } }
  14. 14. 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.
  15. 15. 065 066 IntegerChromosome chrom = new IntegerChromosome(CHROMOSOME_LENGTH,0,MAX_INT); 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 68 69 70 71 72 73 74 75 76 @Override public void evaluate(Individual<IntegerChromosome> individual) { IntegerChromosome chrom = individual.getChromosome(); int diff = 0; int length = chrom.length(); for (int i = 0; i < length; i++) { diff += Math.abs(chrom.getValue(i) - target[i]); } individual.setScore(diff); } 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.
  16. 16. 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 @Override 56 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 SimpleDispense r<IntegerChromosome>(2)); 075 076 AbstractStage<IntegerChromosome> crossover1p = new OnePointCrossover<IntegerChromosome> (0.8);
  17. 17. 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 53 54 55 56 @Override protected boolean end() { jenes.population.Population.Statistics stat = this.getCurrentPopulation(). getStatistics(); return stat.getGroup(Population.LEGALS).getMin()[0] <= this.fitness.precision; } 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 114 public void onGeneration(GeneticAlgorithm ga, long time) { Statistics stat = ga.getCurrentPopulation().getStatistics();
  18. 18. 115 116 117 118 119 Group legals = stat.getGroup(Population.LEGALS); System.out.println("Current generation: " + ga.getGeneration()); System.out.println("tBest score: " + legals.getMin()[0]); System.out.println("tAvg score : " + legals.getMean()[0]); } 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 SimpleDispense r<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 085 086 087 algorithm.addStage(selection); algorithm.addStage(parallel); algorithm.addStage(mutation); 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;
  19. 19. 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, POPULATIO N_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);
  20. 20. 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.");
  21. 21. 133 134 135 136 137 138 139 140 141 142 143 144 145 146 } 147 148 } System.out.println(); Random.getInstance().setStandardSeed(); PatternProblem problem = new PatternProblem(); int[] target = new int[CHROMOSOME_LENGTH]; randomize(target); problem.run(target, 2); randomize(target); problem.run(target, 0); 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 @Override 56 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. 22. 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 @Override 53 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 @Override 68 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 }
  23. 23. 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ífico 2. 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:
  24. 24. 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 P ermutationChromosome(cities)); 128 Population<PermutationChromosome> pop = new Population<PermutationChromosome>(sample, POPULATION_SIZE); 129 130 Fitness<PermutationChromosome> fitness = new Fitness<PermutationChromosome>(false) { 131 132 @Override 133 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, po p, 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.
  25. 25. 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 lengt h."); 094 095 096 //we choose a random city 097 int city = Random.getInstance().nextInt(0, size); 098 099 //i1, i2 are the positions of the city respectively in child1 and child2 100 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 parent1 107 int c1 = chrom_parent1.getValue(i); 108 // find the position of c1 in parent 2 109 int p2 = findPositionOf(c1, chrom_parent2); 110 // if the position is over the cross-point, it copies c1 in child2 111 if( p2 > i2 ) { 112 chrom_child2.setValue(i2 + (++j2), c1); 113 } 114 115 // similarly we process the other pair 116 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 }
  26. 26. 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 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 public void randomize(IntegerChromosome chrom, int min, int max) { //we create a temporany array int len = max-min+1; int[] base = new int[len]; //we fill it with the elements within [min,max] for(int i=0;i<len;i++) base[i]= chrom.getValue(min+i); //the loop ends when the temporany array is empty for( int i = 0; len > 0; --len, ++i) { //we choose a random position pos in the array and copy the element at pos in the chromosome int pos = Random.getInstance().nextInt(0,len); chrom.setValue(min+i,base[pos]); //we removes the chosen element from the temporany array for(int j=pos;j<(len-1);j++){ base[j]=base[j+1]; } } } 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;
  27. 27. 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;
  28. 28. 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, POPULAT ION_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 P ermutationChromosome(cities)); 128 Population<PermutationChromosome> pop = new Population<PermutationChromosome>(sample, POPULATION_SIZE); 129 130 Fitness<PermutationChromosome> fitness = new Fitness<PermutationChromosome>(false) { 131 132 @Override 133 public void evaluate(Individual<PermutationChromosome> individual) {
  29. 29. 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, po p, 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
  30. 30. 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 @Override 054 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]
  31. 31. 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 } * <p> * @param chrom the individual to mutate * @param min the lower bound * @param max the upper bound */ public void randomize(IntegerChromosome chrom, int min, int max) { //we create a temporany array int len = max-min+1; int[] base = new int[len]; //we fill it with the elements within [min,max] for(int i=0;i<len;i++) base[i]= chrom.getValue(min+i); //the loop ends when the temporany array is empty for( int i = 0; len > 0; --len, ++i) { //we choose a random position pos in the array and copy the element at pos in the chromosome int pos = Random.getInstance().nextInt(0,len); chrom.setValue(min+i,base[pos]); //we removes the chosen element from the temporany array for(int j=pos;j<(len-1);j++){ base[j]=base[j+1]; } } } 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); }
  32. 32. @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) {
  33. 33. 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 h."); 094 095 096 097 098 099 100 101 102 103 104 105 106 107 super(pCross); } /** * Returns the number of chromosomes (i.e. 2) this operator entails. */ @Override public int spread() { return 2; } private IntegerChromosome chrom_parent1 = null; private IntegerChromosome chrom_parent2 = null; /** * This method implements the crossover operation. * * @param offsprings the chromosomes to be crossed. */ protected void cross(Individual<IntegerChromosome> offsprings[]) { IntegerChromosome chrom_child1 = offsprings[0].getChromosome(); IntegerChromosome chrom_child2 = offsprings[1].getChromosome(); if( chrom_parent1 == null ) { chrom_parent1 = chrom_child1.clone(); chrom_parent2 = chrom_child2.clone(); } else { chrom_parent1.setAs(chrom_child1); chrom_parent2.setAs(chrom_child2); } final int size = chrom_child1.length(); if( chrom_child2.length() != size ) throw new AlgorithmException("Error: the two chromosomes are required to have the same lengt //we choose a random city int city = Random.getInstance().nextInt(0, size); //i1, i2 are the positions of the city respectively in child1 and child2 int i1 = findPositionOf(city, chrom_child1); int i2 = findPositionOf(city, chrom_child2); int j1 = 0; int j2 = 0; for( int i = 0; i < size; ++i ) { // get the city c1 in position i for parent1 int c1 = chrom_parent1.getValue(i);
  34. 34. 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 } // find the position of c1 in parent 2 int p2 = findPositionOf(c1, chrom_parent2); // if the position is over the cross-point, it copies c1 in child2 if( p2 > i2 ) { chrom_child2.setValue(i2 + (++j2), c1); } // similarly we process the other pair int c2 = chrom_parent2.getValue(i); int p1 = findPositionOf(c2, chrom_parent1); if( p1 > i1 ) { chrom_child1.setValue(i1 + (++j1), c2); } } } /** * Finds the position of one specific city in the chromosome. * <p> * @param city the city to find * @param chrom the chromosome to search * @return the city position */ private int findPositionOf(int city, IntegerChromosome chrom){ final int size = chrom.length(); for( int i = 0; i < size; ++i ) { if( chrom.getValue(i) == city ) return i; } return -1; } 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.
  35. 35. 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ífico 2. 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 P ermutationChromosome(cities)); 128 Population<PermutationChromosome> pop = new Population<PermutationChromosome>(sample, POPULATION_SIZE); 129 130 Fitness<PermutationChromosome> fitness = new Fitness<PermutationChromosome>(false) { 131 132 @Override 133 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);
  36. 36. 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, po p, 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 lengt h."); 094 095 096 //we choose a random city
  37. 37. 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 int city = Random.getInstance().nextInt(0, size); //i1, i2 are the positions of the city respectively in child1 and child2 int i1 = findPositionOf(city, chrom_child1); int i2 = findPositionOf(city, chrom_child2); int j1 = 0; int j2 = 0; for( int i = 0; i < size; ++i ) { // get the city c1 in position i for parent1 int c1 = chrom_parent1.getValue(i); // find the position of c1 in parent 2 int p2 = findPositionOf(c1, chrom_parent2); // if the position is over the cross-point, it copies c1 in child2 if( p2 > i2 ) { chrom_child2.setValue(i2 + (++j2), c1); } // similarly we process the other pair int c2 = chrom_parent2.getValue(i); int p1 = findPositionOf(c2, chrom_parent1); if( p1 > i1 ) { chrom_child1.setValue(i1 + (++j1), c2); } } } 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 082 083 084 085 086 087 088 public void randomize(IntegerChromosome chrom, int min, int max) { //we create a temporany array int len = max-min+1; int[] base = new int[len]; //we fill it with the elements within [min,max] for(int i=0;i<len;i++)
  38. 38. 089 090 091 092 093 094 095 096 097 098 099 100 101 base[i]= chrom.getValue(min+i); //the loop ends when the temporany array is empty for( int i = 0; len > 0; --len, ++i) { //we choose a random position pos in the array and copy the element at pos in the chromosome int pos = Random.getInstance().nextInt(0,len); chrom.setValue(min+i,base[pos]); //we removes the chosen element from the temporany array for(int j=pos;j<(len-1);j++){ base[j]=base[j+1]; } } } 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 DoubleChro mosome(CHROMOSOME_LENGTH,0,1)); 56 Population<DoubleChromosome> pop = new Population<DoubleChromosome>(sample, POPULATI ON_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.
  39. 39. 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 @Override public void evaluate(Individual<DoubleChromosome> individual) { DoubleChromosome chrom = individual.getChromosome(); int length = chrom.length(); double sum = 0.0; for (int i = 0; i < length; ++i) { sum += chrom.getValue(i); } double entropy = 0.0; for (int i = 0; i < length; ++i) { double pxi = chrom.getValue(i) / sum; chrom.setValue(i, pxi); entropy -= (pxi * Math.log(pxi) / Math.log(2)); } individual.setScore(entropy); } 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 DoubleChro mosome(CHROMOSOME_LENGTH,0,1)); 56 Population<DoubleChromosome> pop = new Population<DoubleChromosome>(sample, POPULATI ON_SIZE); 57 58 ga = new SimpleGA<DoubleChromosome>(null, pop, GENERATION_LIMIT); 59 60 System.out.println("Solving Max!:"); 61 solve( EntropyFitness.MAX ); 62
  40. 40. 63 64 System.out.println("Solving Min!:"); 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 69 ga.setFitness(fitness); 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 Troiano 35 * 36 * @version 2.0 37 * @since 1.0 38 */ 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:");
  41. 41. 52 System.out.println("Find the probability distribution that maximizes (or minimize) the Shannon's entr opy."); 53 System.out.println(); 54 55 Individual<DoubleChromosome> sample = new Individual<DoubleChromosome>(new DoubleChro mosome(CHROMOSOME_LENGTH,0,1)); 56 Population<DoubleChromosome> pop = new Population<DoubleChromosome>(sample, POPULATI ON_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 Troiano 28 */ 29 public class EntropyFitness extends Fitness<DoubleChromosome> { 30
  42. 42. 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 } public static EntropyFitness MAX = new EntropyFitness(true); public static EntropyFitness MIN = new EntropyFitness(false); private EntropyFitness(boolean maximize) { super(maximize); } @Override public void evaluate(Individual<DoubleChromosome> individual) { DoubleChromosome chrom = individual.getChromosome(); int length = chrom.length(); double sum = 0.0; for (int i = 0; i < length; ++i) { sum += chrom.getValue(i); } double entropy = 0.0; for (int i = 0; i < length; ++i) { double pxi = chrom.getValue(i) / sum; chrom.setValue(i, pxi); entropy -= (pxi * Math.log(pxi) / Math.log(2)); } individual.setScore(entropy); }
  43. 43. 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
  44. 44. 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 054 055 056 057 058 private static ObjectChromosome template = new ObjectChromosome( IntegerAlleleSet.createUniform(10, 0, 9), IntegerAlleleSet.createUniform(21, 10, 30), DoubleAlleleSet.createRandom(10, 0, 1), new GenericAlleleSet<Boolean>(true, false), 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 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 @Override public void evaluate(Individual<ObjectChromosome> individual) { ObjectChromosome template = individual.getChromosome(); int i1 = (Integer)template.getValue(0); int i2 = (Integer)template.getValue(1); double d = (Double)template.getValue(2); boolean b = (Boolean)template.getValue(3); Color c = (Color)template.getValue(4); double acc = b ? (3*i1 + 4*i2 + d) : i1; switch( c ) { case BLACK : acc += 10; break; case RED : acc += 10; break; case WHITE : acc += 10; break; } individual.setScore(acc); }
  45. 45. 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 099 100 ga.addStage(new TournamentSelector<ObjectChromosome>(3)); ga.addStage(new OnePointCrossover<ObjectChromosome>(0.8)); 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, whose 036 * 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 finding 039 * the vector of colors closest to a given sequence. 040 * 041 * This class defines the problem. 042 * 043 * @author Luigi Troiano
  46. 46. 044 * 045 * @version 2.0 046 * @since 1.0 047 */ 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 @Override 063 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>(ne w 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
  47. 47. 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 } 116 } System.out.println("TUTORIAL 5:"); System.out.println("Find the sequence of colors nearest to the target."); System.out.println(); //Random.getInstance().setStandardSeed(); ga.addStage(new TournamentSelector<ObjectChromosome>(3)); ga.addStage(new OnePointCrossover<ObjectChromosome>(0.8)); ga.addStage(new SimpleMutator<ObjectChromosome>(0.02)); ga.evolve(); Statistics stats = ga.getCurrentPopulation().getStatistics(); GeneticAlgorithm.Statistics algostats = ga.getStatistics(); Group legals = stats.getGroup(Population.LEGALS); System.out.println("Solution: "); System.out.println(legals.get(0)); System.out.format("found in %d ms.n", algostats.getExecutionTime() ); System.out.println(); Utils.printStatistics(stats); Ejemplos de tema: 19 package jenes.tutorials.problem5; 20 21 22 /** 23 * Tutorial illustrating the use of object-oriented chromosomes, whose 24 * 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 finding 27 * the vector of colors closest to a given sequence. 28 * 29 * This class defines the enumeration of possible colors. 30 * 31 * @author Luigi Troiano 32 * 33 * @version 1.0 34 * @since 1.0 35 */ 36 public enum Color { 37 38 RED, BLACK, WHITE;
  48. 48. 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, whose 29 * 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 finding 32 * the vector of colors closest to a given sequence. 33 * 34 * This class defines an allele set made of doubles. 35 * 36 * @author Luigi Troiano 37 * 38 * @version 1.0 39 * @since 1.0 40 */ 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 cardinality 52 * @param lowerBound the min value to choose 53 * @param upperBound the max value to choose 54 * @return a new DoubleAlleleSet 55 */ 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 }
  49. 49. 63 64 return new DoubleAlleleSet(values); 65 } 66 67 /** 68 * Builds a new DoubleAlleleSet with uniformly distributed values within the range [lowerBound,upper Bound] 69 * <p> 70 * @param size the allala set cardinality 71 * @param lowerBound the min value to choose 72 * @param upperBound the max value to choose 73 * @return a new DoubleAlleleSet 74 */ 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, whose 29 * 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 finding 32 * the vector of colors closest to a given sequence. 33 * 34 * This class defines a set of integers. 35 * 36 * @author Luigi Troiano 37 * 38 * @version 1.0
  50. 50. 39 * @since 1.0 40 */ 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 cardinality 51 * @param lowerBound the min value to choose 52 * @param upperBound the max value to choose 53 * @return a new IntegerAlleleSet 54 */ 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,upper Bound] 78 * <p> 79 * @param size the allala set cardinality 80 * @param lowerBound the min value to choose 81 * @param upperBound the max value to choose 82 * @return a new IntegerAlleleSet 83 */ 84 public static IntegerAlleleSet createUniform(int size, int lowerBound, int upperBound ) { 85 HashSet<Integer> values = new HashSet<Integer>(); 86 int s0 = upperBound - lowerBound + 1;
  51. 51. 87 88 89 90 91 92 93 94 95 96 } 97 98 } if( size > s0 ) size = s0; double step = 1.0/(upperBound - lowerBound); for( double x = lowerBound; x <= upperBound; x += step ) { int i = (int) Math.round(x); values.add(i); } return new IntegerAlleleSet(values); 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 Boole anChromosome(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 054 055 @Override public void evaluate(Individual<BooleanChromosome> individual) { double utility = KnapsackGA.this.getUtilityOf(individual);
  52. 52. 056 057 058 059 double weight = KnapsackGA.this.getWeightOf(individual); individual.setScore(utility); individual.setLegal(weight <= KnapsackGA.this.capacity); } 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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 public double getUtilityOf(Individual<BooleanChromosome> individual) { BooleanChromosome chrom = individual.getChromosome(); double utility = 0.0; int size = chrom.length(); for(int i = 0; i < size; ++i){ utility += chrom.getValue(i) ? this.utilities[i] : 0.0; } return utility; } public double getWeightOf(Individual<BooleanChromosome> individual) { BooleanChromosome chrom = individual.getChromosome(); double weight=0.0; int size = chrom.length(); for(int i = 0; i < size; ++i){ weight += chrom.getValue(i) ? this.weights[i] : 0.0; } return weight; } 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 077 078 079 080 081 082 083 Parallel<BooleanChromosome> parallel = new Parallel<BooleanChromosome>(new ExclusiveDispenser<BooleanChromosome>(2){ @Override public int distribute(Individual<BooleanChromosome> ind) { return ind.isLegal() ? 0 :1; }
  53. 53. 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 }); this.setFitness(this.maximize); Sequence<BooleanChromosome> seq_legal = new Sequence<BooleanChromosome>(); seq_legal.appendStage(new TournamentSelector<BooleanChromosome>(2)); seq_legal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8)); seq_legal.appendStage(new SimpleMutator<BooleanChromosome>(0.02)); Sequence<BooleanChromosome> seq_illegal = new Sequence<BooleanChromosome>(); seq_illegal.appendStage(new TournamentSelector<BooleanChromosome>(2)); seq_illegal.appendStage(new OnePointCrossover<BooleanChromosome>(0.8)); seq_illegal.appendStage(new SimpleMutator<BooleanChromosome>(0.2)); parallel.add(seq_legal); parallel.add(seq_illegal); this.addStage(parallel); seq_legal.setFitness(this.maximize); 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 in 030 * the breeding structure of Jenes. 031 * 032 * This class defines the problem to solve. 033 * 034 * @author Luigi Troiano 035 * 036 * @version 1.0 037 * @since 1.0 038 */ 039 public class KnapsackProblem { 040 041 private static int POPSIZE=100; 042 private static int GENERATION_LIMIT=100; 043
  54. 54. 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: %fn", algorithm.getWeightOf(solution), algorithm.getUtilityOf(solut ion) ); 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 }
  55. 55. 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 double[] weights = new double[n]; for( int i = 0; i < n; ++i ) { weights[i] = r.nextInt(10); } return new KnapsackProblem(utilities, weights); } public static void main(String[] args) { Utils.printHeader(); System.out.println(); System.out.println("TUTORIAL 6:"); System.out.println("The Knapsack Problem."); System.out.println(); KnapsackProblem p1 = new KnapsackProblem(UTILITIES, WEIGHTS); System.out.println("Case 1: 10 elements, capacity 15"); System.out.println("Utilities: " + toString(p1.getUtilities()) ); System.out.println(" Weights: " + toString(p1.getWeights()) ); p1.setCapacity(15); p1.run(); System.out.println(); System.out.println("Case 2: 10 elements, capacity 30"); System.out.println("Utilities: " + toString(p1.getUtilities()) ); System.out.println(" Weights: " + toString(p1.getWeights()) ); p1.setCapacity(30); p1.run(); System.out.println(); KnapsackProblem p2 = KnapsackProblem.build(20); System.out.println("Case 3: 20 random elements, capacity 50"); System.out.println("Utilities: " + toString(p2.getUtilities()) ); System.out.println(" Weights: " + toString(p2.getWeights()) ); p2.setCapacity(50); p2.run(); System.out.println(); } private static String toString(double[] values) { String s = "["; for(int i = 0; i < values.length; ++i ){ s += values[i]+ (i < values.length-1 ? " " : "]"); }
  56. 56. 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 in 035 * the breeding structure of Jenes. 036 * 037 * This class implements a genetic algorithm for solving the Knapsack problem. 038 * 039 * @author Luigi Troiano 040 * 041 * @version 2.0 042 * 043 * @since 1.0 044 */ 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 @Override 054 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
  57. 57. 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 Boole anChromosome(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 @Override 080 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;
  58. 58. 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 } } public void setCapacity(double capacity) { this.capacity = capacity; } public double getUtilityOf(Individual<BooleanChromosome> individual) { BooleanChromosome chrom = individual.getChromosome(); double utility = 0.0; int size = chrom.length(); for(int i = 0; i < size; ++i){ utility += chrom.getValue(i) ? this.utilities[i] : 0.0; } return utility; } public double getWeightOf(Individual<BooleanChromosome> individual) { BooleanChromosome chrom = individual.getChromosome(); double weight=0.0; int size = chrom.length(); for(int i = 0; i < size; ++i){ weight += chrom.getValue(i) ? this.weights[i] : 0.0; } return weight; }
  59. 59. 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"}, FOL DER + "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.
  60. 60. 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.
  61. 61. 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<Boolean Chromosome>() { 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<Boolean Chromosome>() { 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 166 prb.csvlogger.close(); prb.xlslogge1.close();

×