Escolar Documentos
Profissional Documentos
Cultura Documentos
Facultad de Ciencias
Licenciatura en Matemáticas
Algoritmos Evolutivos
para la Resolución de
1. Introducción 4
3. El Problema de Satisfactibilidad 36
3.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.2. Conceptos Básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.3. Los Algoritmos Evolutivos para Resolver SAT . . . . . . . . . . . . . . . . . 39
1
4.3. El Algoritmo de Makanin . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.3.1. Representación Gráfica . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.3.2. Las Ecuaciones Generalizadas . . . . . . . . . . . . . . . . . . . . . . 55
4.3.3. EL Algoritmo de Transformación . . . . . . . . . . . . . . . . . . . . 60
4.4. Casos Particulares de Sistemas de “Word Equations” . . . . . . . . . . . . . 66
2
C.5. El problema 10-5-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
C.6. El problema 10-8-3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
C.7. El problema 10-8-5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
C.8. El problema 12-6-4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
C.9. El problema 15-12-4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
C.10.El problema 15-25-5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
C.11.El problema 15-7-5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
C.12.El problema 25-23-4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
C.13.El problema 25-8-3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
C.14.El problema 25-8-5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
C.15.El problema 5-15-3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
C.16.El problema 5-3-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Bibliografı́a 204
3
Capı́tulo 1
Introducción
En este trabajo hemos intentado reunir los resultados obtenidos a lo largo del curso
que comenzamos con el objetivo de diseñar un algoritmo que proporcione una solución a
un sistema de ecuaciones conocido como sistema de “word equations”.
El capı́tulo 2 lo dedicamos al estudio del tipo de algoritmos que pretendemos usar
para resolver estos sitemas, los llamados algoritmos evolutivos. Podrı́amos decir que en
este capı́tulo se encuentran las herramientas básicas necesarias para su diseño. Además,
como aplicación de los mismos a la resolución de diferentes problemas, estudiamos en el
capı́tulo 3 los llamados problemas SAT y explicamos el funcionamiento de los algoritmos
evolutivos más conocidos para su resolución. Algunos de estos algoritmos nos servirán de
referencia a la hora de diseñar el nuestro pues, como veremos, los problemas SAT se
reducen a sistemas de “word equations”.
En el capı́tulo 4 introducimos el problema que pretendemos resolver: los sistemas de
“word equations”, e intentamos resumir la teorı́a que ya ha sido desarrollada sobre estos
sistemas, destacando las dificultades que aparecen en su resolución, pues aunque existe
un algoritmo que los resuelve, el algoritmo de Makanin, éste no se puede usar en la
práctica por ser un algoritmo con una complejidad triplemente exponencial.
En los siguientes capı́tulos explicamos las distintas propuestas que emplearemos para
el diseño del algoritmo evolutivo.
Nuestro trabajo propiamente dicho comienza en el capı́tulo 5 diseñando un algoritmo
evolutivo denominado algoritmo genético simple, cuyos primeros resultados experi-
mentales aparecen en el capitulo 7. En el capı́tulo 6, hacemos un pequeño paréntesis
para diseñar un algoritmo que construya sistemas de “word equations”, pues no existen
4
documentos donde podamos encontrar estos problemas.
En el capı́tulo 8, obtenemos nuevos algoritmos evolutivos añadiendo algunas modifi-
caciones al algoritmo genético simple. Los resultados experimentales nos permitirán com-
probar las mejoras obtenidas al añadir búsqueda local al algoritmo genético simple.
Finalizamos exponiendo los resultados obtenidos del mejor de los algoritmos evolutivos
que hemos diseñado a lo largo de este curso.
Todos los algoritmos diseñados se encuentran en los distintos apéndices, escritos en el
lenguaje C++. También aparecen algunos de los sistemas de “word equations” que hemos
utlizado en los diferentes experimentos.
5
Capı́tulo 2
2.1. Introducción
Diseñar sistemas artificiales que conserven los mecanismos de los sistemas naturales.
6
2.2. Conceptos Básicos
Definición 1
Se llama alfabeto a un conjunto finito de sı́mbolos dados.
Se denotará por A.
Ejemplo 1
Los siguientes conjuntos pueden ser alfabetos
1. { 1, 3, 5, 7, 9}
2. { a, b, c,. . . , x, y, z}
3. {α, β, γ}
5. { 0, 1}
Definición 2
Una cadena o palabra es una sucesión ordenada y finita de sı́mbolos de un alfabeto.
Se denotará por ω.
Definición 3
El número de sı́mbolos que constituyen una cadena ω se llama longitud de ω.
Se denotará por |ω|.
Ejemplo 2
ω = 10011 es una cadena de longitud |ω| = 5 del alfabeto binario A = { 0, 1}.
Definición 4
Se dice cadena vacia a la cadena que no contiene sı́mbolos y por lo tanto tiene longitud
cero.
Se denotará por Λ.
Definición 5
El exponente de periodicidad de una cadena ω es el máximo número p tal que
ω = uv p z
7
Definición 6
Dado un alfabeto A.
Se define el conjunto de todas las cadenas que se pueden formar con sı́mbolos de A como
[
A∗ = {Λ} ∪ A ∪ A2 ∪ . . . ∪ An ∪ . . . = Ak
k≥0
Definición 7
Sea A un alfabeto.
Dadas dos cadenas ω1 y ω2 sobre A se define la concatenación de ω1 y ω2 como la cadena
que resulta de colocar primero ω1 y a continuación ω2 .
Se denotará ω1 ω2 .
Propiedades de la concatenación:
Asociativa,
( ω1 ω2 ) ω3 = ω1 ( ω2 ω3 ) ∀ ω1 , ω2 , ω3 ∈ A.
En general, no es conmutativa.
Ejemplo 3
Si ω1 = ab y ω2 = b entonces
ω1 ω2 = abb 6= bab = ω2 ω1
Nota 1
El alfabeto A con la operación de concatenación tiene estructura de semigrupo con iden-
tidad.
Nota 2
Será frecuente usar el término “bit” para referirnos a los sı́mbolos de un alfabeto, en
particular, cuando trabajemos con el alfabeto binario A = { 0, 1}.
8
2.3. Caracterı́sticas de los Algoritmos Genéticos
Algunas de las principales caracterı́sticas de los algoritmos genéticos, que los diferencia
de otros procesos de optimización, son las siguientes:
Trabajan con una codificación del conjunto de variables del problema, no con las
propias variables.
En general, se codifican como cadenas de algún alfabeto.
Aleatoriedad controlada.
Estas cuatro caracterı́sticas contribuyen a dar fuerza a los algoritmos genéticos y re-
sultan de gran utilidad, por encima incluso de otras técnicas usadas con más frecuencia.
9
Además, la habilidad del algoritmo genético para explotar la información acumula-
da sobre un espacio de búsqueda permite su aplicación a espacios de búsqueda grandes,
complejos y poco entendidos.
Por lo tanto, los algoritmos genéticos tratan de alcanzar un equilibrio entre dos ob-
jetivos aparentemente en conflicto: explotar las buenas cualidades de las candidatas a
solución y explorar el espacio de búsqueda.
La simplicidad de las operaciones y la gran eficacia del proceso son dos de los principales
atractivos de los algoritmos genéticos. Veremos que la explicación de por qué este proceso
funciona es mucho más sutil.
Definición 8
Se llama individuo a cualquier cadena candidata a ser solución del problema que se pre-
tende resolver mediante un algoritmo genético.
Un conjunto finito de individuos se dice población.
Definición 9
Se llama función fitness, de calidad, o de aptitud... a aquella función que determina los
individuos mejor adaptados o, de alguna manera, más cercanos a la solución del problema.
Para seleccionar una función fitness adecuada hay que hacer un balance entre aquellas que
reflejen diferencias muy grandes (provocando una convergencia prematura de los indivi-
duos de la población hacia un óptimo local) y las que proporcionen diferencias pequeñas
(dando lugar a un estacionamiento).
En ocasiones se añade un factor de penalización para controlar los individuos que no
responden a las caracterı́sticas de las soluciones del problema.
El algoritmo genético simple está constituido principalmente por tres etapas bien dife-
renciadas: selección, cruce y mutación. Sin embargo, en la práctica es necesario especificar
para su diseño los siguientes aspectos:
10
la codificación de las variables del problema que constituirán los individuos
el criterio de selección
el tipo de cruce
Los operadores genéticos (selección, cruce y mutación) dependen del tipo de repre-
sentación utilizado. Originalmente, las soluciones se representaban por cadenas binarias,
es decir, listas de ceros y unos. Este tipo de representación permite definir fácilmente el
proceso de cruce. Sin embargo, en algunos problemas resulta poco natural y eficiente. Por
este motivo, es importante estudiar el problema que se pretende resolver para determinar
la representación más adecuada de los individuos y, en consecuencia, de la solución que se
busca.
Ejemplo 4
Consideramos el problema del viajante dado por 5 ciudades y 20 aristas.
Hay que calcular un camino cerrado que pase por todas las ciudades, sólo una vez por
cada ciudad, y tal que la distancia recorrida sea mı́nima.
Sean C1 , C2 , C3 , C4 y C5 las ciudades que hay que recorrer.
Suponemos que el viajante parte siempre de la ciudad C1 .
Tenemos que codificar cinco variables, una por cada una de las ciudades del problema.
Proponemos codificarlas como cadenas de longitud 4 del alfabeto A = { 0, 1} pues a cada
ciudad llegan y salen cuatro aristas. De esta forma, representamos para cada ciudad las
aristas que salen de esta y le asignamos el valor uno a aquella que forma parte del camino
elegido. Ası́, la cadena
|{z } 1000
0010 |{z } 0100
|{z} 0010
|{z } 1000
|{z }
C1 C2 C3 C4 C5
11
C2 C4
0 0 1
0 1 C3 1 1 C5 0
C1 C3 C5 ...
1 0 0
C4 C1
0 0 0
C5 C2
Sin embargo, no resulta una representación natural y, además, no todos los individuos que
tienen cinco unos representan una solución del problema.
La cadena
11101100000000000000
01001000001000101000
aunque si representa un camino no permite recorrer todas las ciudades y no puede ser
aceptada como solución candidata del problema.
C2 C2 C2
7 M k
w
C3 1 C3 C3
/
C1 i C1 C1 6
] q C4
C4 C4
?
C5 C5 C5
12
Por lo tanto, resulta más natural representar la ruta de las ciudades por una permutación,
digamos
(5, 4, 2, 3)
2
Con esta representación sólo
] ~3
tenemos que preocuparnos de
9 encontrar la permutación que
1
haga mı́nima la distancia necesaria
4
~ 3 para recorrer todas las ciudades.
5
Además, el problema del viajante en su enunciado general no exige que el camino comience
en una ciudad concreta sino que se enuncia en los siguientes términos:
Con este enunciado y suponiendo, como hasta ahora, que todas las ciudades estan comu-
nicadas entre sı́ en ambos sentidos, la mejor representación de los individuos está formada
por permutaciones de cinco elementos, pues la representación binaria necesitarı́a además
indicar cuál es la ciudad inicial del camino para cada individuo.
Nota 3
Una codificación correcta es una de las claves más importantes para tener exito en la
resolución de los problemas.
13
2.4.2. Generación de la Población Inicial
Cada vez que se genera una población de individuos es necesario evaluarlos para obtener
una medida de calidad, es decir, el fitness asociado a cada individuo. Este valor es utilizado
en el proceso de selección para la obtención de las sucesivas generaciones.
Como ya se mencionó, la elección del fitness que guiará el proceso de búsqueda será una
de las claves para garantizar el buen funcionamiento del algoritmo genético.
Ejemplo 5
En el problema del viajante anterior, en su versión general, generamos de forma aleatoria
una población de tamaño tp = 3.
Como se trata de un problema de minimización podemos tomar como función fitness f la
función que nos proporciona la distacia recorrida. De este modo, un individuo será mejor
que otro si la función fitness asociada tiene un valor más pequeño.
Definimos dij la distancia entre las ciudades Ci y Cj para i, j = 1, 2, 3, 4, 5 con i 6= j.
Suponemos que
14
Individuo fitness
I1 = (1, 4, 2, 3, 5) 172
I2 = (2, 3, 5, 4, 1) 158
I3 = (3, 1, 4, 2, 5) 199
Luego, la ruta que proporciona el individuo I2 es la mejor de las tres rutas de la población.
2.4.4. Selección
15
0 −→ 00000
4 −→ 00100
17 −→ 10001
31 −→ 11111
I1 = 01010 I2 = 01001
I3 = 11100 I4 = 00010
P
Individuo Pob. Inicial Valor de x f (x) = x2 P (i) = fi / fj
Existen otras técnicas para la selección de los individuos, como las denominadas:
Torneo: Se seleccionan dos individuos aleatoriamente y se elige el más apto con una
probabilidad p fijada. (el menos apto se elige con probabilidad (1 − p))
16
Ranqueo: Se ordena la población según el fitness de cada individuo y se le asigna la
probabilidad de selección de acuerdo a la posición que ocupa.
2.4.5. Cruce
2. Se obtienen dos nuevas cadenas al intercambiar las subcadenas situadas entre las
posiciones k + 1 y l, ambas inclusive.
Ejemplo 7
Consideramos las cadenas w1 y w2 de la población inicial en el ejemplo anterior,
w1 = 01010
w2 = 01001
Como la longitud de estas cadenas es l = 5, tenemos que elegir la posición k como valor
entero entre 1 y 4.
Suponemos k = 4 (como indica el sı́mbolo separador | )
w1 = 0101|0
w2 = 0100|1
w10 = 01011
w20 = 01000
Ası́ se genera una nueva población de individuos que hereda parte de la información de la
población anterior.
17
Nota 4
Se pueden seleccionar tantos individuos de la población actual como sean necesarios para
generar una nueva población que reemplace completamente a la actual.
Sin embargo, en muchas ocasiones se copian los N mejores individuos de la población actual
a la siguiente de modo que sólo se seleccionan los individuos necesarios para completar la
nueva población. Este tipo de selección se denomina elitista.
Normalmente, se suele copiar el mejor o los dos mejores individuos de cada población a la
siguiente. De esta forma se mantiene siempre en la población al mejor individuo alcanzado
hasta el momento.
Existen muchos otros procesos de cruce que se van adaptando a las necesidades con-
cretas de cada problema. A continuación definimos algunos de los más conocidos.
Ejemplo 8
Cosideramos dos individuos de longuitud l = 15 dados por
010101000001000
100100101011101
Vamos a aplicar un cruce de 4 puntos. Para ello seleccionamos al azar cuatro posiciones
enteras entre 1 y 14.
Supongamos que k1 = 3, k2 = 7, k3 = 9 y k4 = 13, entonces
010|1010|00|0010|00 : 100|1010|01|0010|01
100|1001|01|0111|01 z 010|1001|00|0111|00
100101001001001
010100100011100
18
Definición 11 (Cruce uniforme)
Se dice cruce uniforme cuando se cruzan dos cadenas dadas de longitud l mediante un
proceso que compara los sı́mbolos que ocupan las mismas posiciones en ambas cadenas, es
decir, para cada posición i = 0, . . . , l se compara el sı́mbolo que ocupa la i ésima posición
de la primera cadena con el que ocupa la i ésima posición de la segunda cadena.
El más utilizado cruce uniforme, genera una nueva cadena cruzando dos cadenas como
sigue:
para cada i = 0, . . . , l,
si los simbolos que ocupan la i ésima posición coinciden, entonces se copia dicho sı́mbolo
a la posición i ésima de la nueva cadena, en otro caso, se elige uno de los dos sı́mbolos
comparados (con probabilidad p se elige el de la primera cadena y con probabilidad (1-p)
el de la segunda) y se copia a la i ésima posición de la nueva cadena.
Ejemplo 9
Dadas dos cadenas sobre el alfabeto A = { 0, 1}
ω1 = 01010111
ω2 = 00101111
Obtenemos una nueva cadena aplicando un cruce uniforme que elige el sı́mbolo de ω1
con probabilida 0,3 y el sı́mbolo de ω2 con probabilidad 0,7 cuando los sı́mbolos que se
comparan no coinciden.
Comparamos los sı́mbolos que ocupan la primera posición, como coinciden se copia ese
sı́mbolo a la nueva cadena.
ω1 = 01010111
- 0 ···
ω2 = 00101111
Al comparar los sı́mbolos que ocupan la segunda posición, y teniendo en cuenta la proba-
bilidad de cruce, ha resultado que el sı́mbolo de ω1 se copia a la nueva cadena.
ω1 = 01010111
- 0 1 ···
ω2 = 00101111
ω1 = 01010111
- 0 1 1 0 1 1 1 1
ω2 = 00101111
19
Existen otros criterios para definir el operador de cruce uniforme, como por ejemplo:
Cuando dos sı́mbolos no coincidan se intercambian entre sı́ con una determinada
probabilidad, dando lugar a dos nuevas cadenas.
Fijada una de las dos cadenas, se recorre sı́mbolo a sı́mbolo. Cada vez que se en-
cuentre un uno se compara con el sı́mbolo que ocupa la misma posición en la otra
cadena. Si no coinciden, entonces se intercambian estos dos sı́mbolos entre sı́, dando
lugar a dos nuevas cadenas. Además, se puede imponer una probabilidad de cambio.
Ejemplo 10
Dadas dos cadenas sobre el alfabeto A = { 0, 1}
ω1 = 11001001
ω2 = 10011101
Para aplicar el cruce uniforme consideramos el criterio que intercambia dos sı́mbolos dis-
tintos con probabilidad p = 0,5.
Empezamos a recorrer los sı́mbolos de ambas cadenas y encontramos los dos primeros que
no coinciden
11001001
10011101
11001001
10011101
Este proceso se repite hasta que hayamos recorrido todos los sı́mbolos.
Los nuevos individuos que resultan de aplicar el cruce uniforme vienen dados por
11011101
10001001
20
Los procesos de selección y cruce son sorprendentemente sencillos, involucrando gene-
ración aleatoria de números, copias de cadenas y algún intercambio parcial de cadenas.
No obstante, el énfasis combinado de selección, aleatoriedad controlada e intercambio
de información del cruce dan a los algoritmos genéticos gran parte de su potencia. Puede
parecer sorprendente que dos operaciones tan simples resulten útiles en algún caso. Incluso,
parece raro que el azar juege un papel tan fundamental en un proceso de búsqueda directo.
2.4.6. Mutación
21
2.5. Seudocódigo de un Algoritmo Genético Simple
Una vez estudiados los elementos necesarios para construir un algoritmo genético sim-
ple, vamos a describir el funcionamiento del mismo.
Fijados el tamaño de la población tp y la función fitness f que guiará el proceso, se
genera una población inicial P0 donde cada individuo se obtiene de forma aleatoria. En la
siguiente etapa, se evalúan los individuos de la población P0 para conocer el fitness asociado
a cada uno. Finalmente, se realiza un bucle de iteraciones que consiste en la generación de
nuevas poblaciones a partir de las anteriores mediante los operadores genéticos. De esta
forma, en la iteración k ésima se genera la población Pk a partir de los individuos de la
población Pk−1 usando selección, cruce y mutación.
Cuando finaliza la ejecución del algoritmo, se obtiene una población formada por
buenos individuos, siendo el mejor de ellos la solución que se propone.
Seudocódigo de un AGS
P0 ← generar población inicial
E0 ← evaluar (P0 )
para k = 1 hasta NIter hacer
para j = 1 hasta tp hacer
Ij (1) ← seleccionar de Pk−1
Ij (2) ← seleccionar de Pk−1
Ij ← cruzar (Ij (1), Ij (2))
Ij ← mutar (Ij )
Ej ← evaluar (Ij )
Pk ← guardar (Ij )
fin para
fin para
22
Seudocódigo de un AGS elitista
P0 ← generar población inicial
E0 ← evaluar (P0 )
para k = 1 hasta NIter hacer
I ← mejor individuo de Pk−1
Pk ← guardar (I)
para j = 1 hasta tp − 1 hacer
Ij (1) ← seleccionar de Pk−1
Ij (2) ← seleccionar de Pk−1
Ij ← cruzar (Ij (1), Ij (2))
Ij ← mutar (Ij )
Ej ← evaluar (Ij )
Pk ← guardar (Ij )
fin para
fin para
f : [ −2, 2 ] −→ R
exp( x2 ) cos(5x)
x −→ (x+3)2
+1
Tenemos que codificar una única variable x que toma valores reales entre −2 y 2.
Para poder codificarlo como cadena del alfabeto binario A = { 0, 1} definimos la
siguiente traslación:
f˜ : [ 0, 4 ] −→ [ −2, 2 ] −→ R
exp( x̃−2 ) cos(5(x̃−2)) exp( x̃2 −1) cos(5x̃−10)
x̃ −→ x̃ − 2 −→ 2
((x̃−2)+3)2
+1= (x̃+1)2
+1
Suponemos que la solución viene dada con tres cifras decimales. Luego,
0, 000 ≤ x̃ ≤ 4, 000
23
Sabemos que
2048 = 211 < 4000 < 212 = 4096
Por lo tanto, podemos codificar la variable x̃ como una cadena ω de longitud |ω| = 12
en el alfabeto A = { 0, 1}.
Nótese que
111111111111 = 4, 095 > 4, 000
Ası́ que cuando generemos los individuos de la población tendremos que controlar
que el valor asociado a esa cadena es menor o igual que cuatro.
Población inicial
Fitness
Criterio de selección
Cruce
Mutación
24
I1 = 011001010010
I2 = 110000100101
I3 = 101110100100
I4 = 010000100001
P
Individuo P0 x̃ f˜(x̃) P (Ii ) = f˜i / f˜j
Los dos mejores individuos de P0 , I30 y I40 , pasan directamente a la siguiente población,
P1 .
Individuo P1 x̃ f˜(x̃)
Tenemos que generar otros dos individuos mediante los operadores genéticos para comple-
tar la población P1 .
Generación de I31 :
Luego, de los procesos de selección y cruce se tiene que I31 = 011110100100. Además, este
individuo es sometido al proceso de mutación. Sin embargo, ninguno de sus bits muta.
Generación de I41 :
25
Luego, de los procesos de selección y cruce se tiene que I41 = 110000100100. Este individuo
también es seleccionado para la mutación. En esta ocasión mutan los sı́mbolos situados en
la sexta y duodécima posición. Se obtiene
I41 = 110001100101
P
Individuo P1 x̃ f˜(x̃) P (Ii ) = f˜i / f˜j
I32 = 010010100100
I42 = 101110100100
Nótese que para obtener I42 hemos cruzado el mismo individuo, I11 .
Además, al individuo I32 se le aplica el operador de mutación. En este caso, los bits situados
en la quinta, sexta y última posición mutan. Se obtiene
I32 = 010001100101
26
P
Individuo P2 x̃ f˜(x̃) P (Ii ) = f˜i / f˜j
Para generar la siguiente población, tenemos que elegir los dos mejores individuos de P2 .
Como el mejor fitness se tiene para los individuos I12 , I22 y I42 , elegimos al azar dos. Estos
serán los que pasen directamente a la siguiente población, P3 .
Para completar la población aplicamos los operadores genéticos a la población P2 .
Se obtiene la siguiente tabla para la población P3 .
P˜
Individuo P3 x̃ f˜(x̃) P (Ii ) = f˜i / fj
P
Individuo P4 x̃ f˜(x̃) P (Ii ) = f˜i / f˜j
P
Individuo P5 x̃ f˜(x̃) P (Ii ) = f˜i / f˜j
27
Tras estas generaciones, la solución que se propone es
Figura 2.1:
tal que
max{f (x) : x ∈ [−2, 2 ]} = 1,177
Con este ejemplo hemos intentado terminar de comprender el funcionamiento del algo-
ritmo genético y al mismo tiempo ver el buen comportamiento del método. En este caso
particular, en pocas iteraciones nos hemos aproximado al óptimo de la función mediante
unas operaciones muy sencillas. Sin embargo, la convergencia al óptimo en este problema
se podrı́a mejorar, pues hemos aplicado un proceso de selección elitista que mantenı́a los
dos mejores individuos encontrados hasta ese momento para una población de tamaño
tp = 4, resulta más interesante mantener en las nuevas poblaciones sólo al mejor individuo
encontrado hasta ese momento con el fin de aumentar la diversidad de las poblaciones
generadas.
Nota 5
En la práctica, el tamaño de población, el número de iteraciones, la probabilidad de mu-
tación... son determinados de forma experimental para cada problema concreto.
28
2.6. El Teorema de los Esquemas
Definición 12
Se llama esquema a una cadena que representa un conjunto de cadenas con similares ca-
racterı́sticas, es decir, cadenas que tienen los mismos sı́mbolos en determinadas posiciones.
El sı́mbolo ∗ se utiliza para indicar las posiciones donde no es obligada la coincidencia, es
decir, indica las posiciones donde puede ir cualquier elemento del alfabeto.
Ejemplo 12
Consideramos las cadenas
01001001
01000010
01101001
01100011
Es evidente que las posiciones 1, 2, 4 y 6 de todas estas cadenas coinciden. Por lo tanto,
la cadena
01 ∗ 0 ∗ 0 ∗ ∗
Nota 6
Un mismo conjunto de cadenas puede pertenecer a distintos esquemas.
Definición 13
Sea H un esquema.
Se llama orden de H al número de sı́mbolos en H que son distintos de *.
Se denotará por o(H).
Se llama longitud de H al número de sı́mbolos del alfabeto { 0, 1, ∗ } más uno que hay
entre la primera y la última de las posiciones distintas de *.
Se denotará por δ(H).
29
Nota 7
Si el esquema H posee una única posición distinta de * entonces δ(H) = 0.
Ejemplo 13
Sea el alfabeto binario A = { 0, 1}.
Se tiene la siguiente tabla
H1 = 0 1 ∗ ∗ 1 ∗ 0 o(H1 ) = 4 δ(H1 ) = 6
H2 = ∗ 1 ∗ 1 ∗ 1∗ o(H2 ) = 3 δ(H2 ) = 4
H3 = 0 ∗ ∗ 0 1 0 1 o(H3 ) = 5 δ(H3 ) = 6
H4 = ∗ ∗ 0 ∗ 1 ∗ ∗ o(H4 ) = 2 δ(H4 ) = 2
H5 = ∗0 ∗ ∗ ∗ ∗∗ o(H5 ) = 1 δ(H5 ) = 0
H6 = ∗ ∗ ∗11 ∗ ∗ o(H6 ) = 2 δ(H6 ) = 1
f (H) δ(H)
m(H, k + 1) ≥ m(H, k) · · [1 − pc · − o(H) · pm ]
f¯ L−1
Demostración 1
Para obtener esta estimación tenemos que estudiar el efecto individual y combinado de los
operadores genéticos sobre los esquemas contenidos en una población.
30
Sabemos que durante la selección la probabilidad de que un individuo Ii sea seleccionado
viene dada por la expresión P (Ii ) = fi /Σfj . Luego, en n selecciones con reemplazamiento
en la población Pk se obtiene que el número de individuos del esquema H que han sido
escogidos en esas n selecciones viene dado por
f¯ + cf¯
m(H, k + 1) = m(H, k) · = (1 + c) · m(H, k)
f¯
Por otro lado, resulta sencillo deducir que la probabilidad de supervivencia de un esquema
H tras el proceso de cruce viene dada por
δ(H)
ps = 1 −
L−1
δ(H)
ps ≥ 1 − pc ·
L−1
31
· ¸
f (H) δ(H)
m(H, k + 1) ≥ m(H, k) · ¯ · 1 − pc ·
f L−1
Es decir, el esquema H crece o decrece según un factor multiplicativo que, por ahora,
depende de la calidad (su fitness medio) y de la longitud del esquema. Ası́, los esquemas
con fitness medio por encima del fitness medio de la población y de longitud pequeña
crecerán en la siguiente generación.
Finalmente, estudiamos el efecto de la mutación sobre un esquema H.
Es evidente que para que un esquema H sobreviva al proceso de mutación no deben cambiar
ninguno de los sı́mbolos situados en las posiciones fijas, es decir, los sı́mbolos distintos de
*. Por lo tanto, la probabilidad de que un esquema H sobreviva a una mutación viene dada
por
(1 − pm )o(H)
µ ¶
f (H) δ(H)
m(H, k + 1) ≥ m(H, k) · ¯ · 1 − pc · · (1 − o(H) · pm )
f L−1
µ ¶
f (H) δ(H)
m(H, k + 1) ≥ m(H, k) · ¯ · 1 − pc · − o(H) · pm
f L−1
32
Ejemplo 14
Veamos con un sencillo ejemplo el efecto del cruce (en un punto) sobre los esquemas.
Consideramos una cadena de longitud 7,
ω = 0111000
H1 = ∗ 1 ∗ ∗ ∗ ∗ 0
H2 = ∗ ∗ ∗ 1 0 ∗ ∗
H1 = ∗ 1 ∗ | ∗ ∗ ∗ 0
H2 = ∗ ∗ ∗ | 1 0 ∗ ∗
33
2.7. Otros Algoritmos Genéticos: los Algoritmos Evolutivos
Hasta ahora hemos estudiado el funcionamiento del algoritmo genético simple y hemos
descrito cada uno de los operadores necesarios para su diseño. Estos operadores pueden
redefinirse para adaptarlos a las necesidades concretas de cada problema, pero el algoritmo
genético simple deberá de conservar su estructura interna: generación de una población
inicial y generación de nuevas poblaciones mediante los operadores genéticos. Cualquier
modificación que afecte a la estructura del algoritmo genético darı́a lugar a un algoritmo
de búsqueda denominado algoritmo evolutivo.
En general, se llama algoritmo evolutivo a cualquier algoritmo probabilı́stico que par-
tiendo de una población inicial evoluciona, dando lugar a nuevas poblaciones, con la es-
peranza de que se hereden las buenas cualidades de las poblaciones anteriores. Por lo
tanto, el algoritmo genético simple es un caso particular de algoritmo evolutivo donde los
operadores de selección, cruce y mutación actúan sobre cada población para generar una
nueva.
Partiendo de un algoritmo genético simple vamos a definir algunas modificaciones que
dan lugar a diferentes algoritmos evolutivos.
Sólo mutación
Información heurı́stica
Convergencia Prematura
Es posible evitar que una población converga a un valor que no nos permita mejorar
para alcanzar la solución. Para ello, una posibilidad es inyectar de forma artificial
34
diversidad mediante la generación aleatoria de nuevos individuos que reemplacen
parcial o totalmente la población actual.
Búsqueda local
En muchos algoritmos genéticos se introduce un nuevo operador que por si sólo cons-
tituye un algoritmo de búsqueda. Se trata de un proceso que busca puntos próximos
a uno dado con la esperanza de encontrar el óptimo o, por lo menos, mejorar la
solución. Existen muchas tecnicas para diseñar la búsqueda local, una de las más
extendidas consiste en la modificación de los valores de los sı́mbolos que constituyen
un individuo. Cada vez que se cambia el valor de un sı́mbolo se compara el nuevo
individuo con el anterior, tomando el mejor de los dos. Podrı́amos repetirlo para todos
los valores del individuo. Esta búsqueda local viene a ser un proceso de mutación
dirigido.
Seudocódigo
I0 ← generar población inicial
I0 ← busqueda local (I0 )
I0 ← evaluar (I0 )
para k = 1 hasta NIter hacer
I1 ← copiar (I0 )
I1 ← mutar (I1 )
I1 ← busqueda local(I1 )
E1 ← evaluar (I1 )
I0 ← mejor individuo (I0 , I1 )
fin para
35
Capı́tulo 3
El Problema de Satisfactibilidad
3.1. Introducción
36
Definición 17 (Problema NP completo)
Se dice que un problema P es completo para NP o que es NP completo si es NP y, además,
cualquier otro problema NP se reduce a él.
Definición 18 (Variable booleana)
Se dice que una variable es booleana cuando sólo puede tomar los valores verdadero o
falso.
El conjunto booleano viene dado por
B = { falso, verdadero } = { 0, 1}
37
Ejemplo 17 (Un problema SAT)
Dada la función booleana en forma normal
f : B4 −→ B
x −→ f (x) = C1 (x)∧C2 (x)
Nota 8
Cualquier función de un problema SAT puede expresarse en forma normal sin que esto
suponga pérdida de generalidad. Por ello, toda función booleana asociada al problema
SAT que se considere a partir de ahora estará expresada en forma normal.
Definición 22
Un problema SAT se dice de clase k si todas las cláusulas contienen exactamente k literales
distintos.
Para simplificar la notación hablaremos del problema k SAT en lugar del problema SAT
de clase k.
Observaciones:
1. Mientras que los problemas 2 SAT son resolubles en tiempo polinomial, los problemas
k SAT son NP completos para k ≥ 3.
2. Los algoritmos exactos pueden dar una respuesta definitiva (ser satisfactible o in-
satisfactible) a algunos problemas concretos, pero tienen una complejidad de tipo
exponencial en el mejor de los casos.
38
3.3. Los Algoritmos Evolutivos para Resolver SAT
Los algoritmos evolutivos son algoritmos heurı́sticos que han sido utilizados para re-
solver problemas SAT y otros muchos problemas NP completos.
Como hemos visto en el capı́tulo anterior, el primer paso será la codificación de las
variables del problema y la elección de la función fitness más adecuada para obtener una
solución.
A continuación describimos distintos métodos de codificación para el problema SAT.
El proceso inmediato y, hasta ahora, más seguro para representar una solución can-
didata de un problema SAT es una cadena de bits de longitud igual al número de
variables, de manera que a cada variable se le asocia un bit.
Para poder implementar el algoritmo genético tenemos que decidir cuál será nuestra
función fitness. La función booleana f del problema SAT puede ser usada como
función fitness pues las soluciones del problema SAT corresponden al óptimo global
de f . Sin embargo, esta aproximación falla porque el algoritmo genético degenera en
pura búsqueda aleatoria cuando todas las soluciones candidatas toman el valor cero
en la función objetivo, a menos que una solución sea encontrada.
Por este motivo se introduce la formulación MAXSAT, donde la función fitness re-
presenta el número de cláusulas que se verifican, es decir,
Ejemplo 18
Consideramos el problema SAT dado por la función
f : B6 −→ B
x −→ f (x) = C1 (x)∧C2 (x)
x = (x1 , x2 , x3 , x4 , x5 , x6 ) = (1, 0, 0, 1, 1, 0) ∈ B6
39
La codificación de esta solución como cadena de bits es 100110.
La función fitness que guiará el proceso de búsqueda se define como
El elemento que se propone como solución es en realidad solución del problema pues
C2 (101010) = 1. Por lo tanto,
fM AXSAT (101010) = 2
que es el valor máximo que puede tomar el fitness, es decir, se verifican todas las
cláusulas.
En 1998, Bäck [3] propone transformar los problemas SAT en problemas de opti-
mización continuos, de manera que la optimización numérica de estos problemas se
pueda abordar mediante técnicas clásicas.
y ∈ [−1, 1]n
40
Ahora el objetivo es minimizar la función g. De hecho, valores de g nulos se corres-
ponden con soluciones.
Ejemplo 19
Consideramos el problema 3 SAT dado por la fórmula booleana
g(y) = (y1 −1)2 (y2 +1)2 (y4 −1)2 +(y1 +1)2 (y3 −1)2 (y4 +1)2 +(y2 +1)2 (y3 +1)2 (y4 −1)2
Respresentación clausal
Propuesta por Hao [10] en 1995, esta representación resalta los efectos locales de las
variables en las cláusulas.
41
En el resto de los casos, es fácil comprobar que C1 (x) = 1.
Razonando de la misma forma, obtenemos las asignaciones posibles para las otras
cláusulas.
Una combinación de asignaciones posibles para las distintas cláusulas viene dada por
Esta serı́a una candidata a solución, sin embargo, contiene asignaciones inconsis-
tentes para la variable x4 , pues por un lado se tiene que x4 = 0 en la cláusula C1 y,
por otro lado, x4 = 1 para la cláusula C3 . Por lo tanto, esta candidata a solución no
es globalmente consistente.
Siguiendo con este razonamiento, se llega a la candidata a solución
En este caso, el algoritmo genético tiene que ser guiado por una función objetivo
que refleje la cantidad de inconsistencias entre las distintas asignaciones de variables
para las cláusulas. Esto implica un proceso de búsqueda centrado en las relaciones
entre las variables que, al mismo tiempo, están relacionadas entre sı́ por las distintas
cláusulas.
Respresentación “path”
Sugerida por Gottlieb y Voss [6] en 1998, se basa en el hecho de que una solución
viable debe satisfacer al menos una variable en cada cláusula.
42
Una función fitness razonable para este tipo de representación debe medir el número
de inconsistencias.
Ejemplo 21
Dado el problema SAT, encontrar x = (x1 , x2 , x3 , x4 ) ∈ B4 tal que
f (x) = 1
siendo
f (x) = (x1 ∨ x2 ∨ x4 ) ∧ (x1 ∨ x3 ∨ x4 ) ∧ (x2 ∨ x3 ∨ x4 )
Aunque esta representación parece la más idónea, los resultados obtenidos no han
mejorado los de la representación cadena de bits.
Después de esta breve descripción podemos concluir que la mayorı́a de los algoritmos
evolutivos para resolver problemas SAT utilizan como representación la cadena de bits.
La diferencia se encuentra en el tipo de función fitness utilizada. Además, algunos algo-
ritmos evolutivos incorporan otras caracterı́sticas, no genéticas, como la búsqueda local y
la adaptación.
A continuación describimos algunos de los algoritmos evolutivos más conocidos para
SAT.
En 1997, Eiben y van der Hauw [4] proponen una función fitness para resolver
los problemas SAT, principalmente 3 SAT . El algoritmo evolutivo que la utiliza
se denominó SAW y la función fitness se definió como
donde los pesos ωi ∈ N, para i = 1, . . . , m, son adaptados para identificar las cláusu-
las difı́ciles de satisfacer en la actual fase de búsqueda.
43
En la primera fase todos los pesos son inicializados a uno, ωi = 1 para i = 1, . . . , m,
con lo que se utiliza fM AXSAT .
En las siguientes fases, cada 250 evaluaciones de la función fitness, los pesos son
ajustados de acuerdo a la siguiente expresión
ωi ← ωi + 1 − Ci (x∗ )
En 1998, Bäck identifico las mejores caracterı́sticas de este algoritmo evolutivo y que
se conoce por SAWEA. Estas caracterı́sticas son: tamaño de población tp = 1, un o-
perador de mutación que mute exactamente un bit y un esquema de reemplazamiento
en el cual de cada individuo se generan λ hijos mediante mutaciones, sustituyendo
el mejor de todos ellos a su padre, este tipo de reemplazamiento se denota como
(1, λ∗ ).
Más tarde, Jong y Kosters sugieren aplicar un operador adicional a los individuos
obtenidos de la mutación. Este operador selecciona aleatoriamente algunas cláusulas
y, en aquellas que todavı́a no se verifiquen, muta una variable elgida aleatoriamente.
Esta mejora se conoce por LSAWEA.
En 1998, Gottlieb y Voss [7] introducen una nueva función fitness con el fin de
distinguir las distintas cadenas binarias que tienen asociado un mismo valor fitness
fM AXSAT .
r : Bn −→ [0, 1)
44
En la función fREF la constante α > 0 controla la influencia de r. De esta forma, si
usamos un nivel de influencia α ∈ [0, 1), podemos distinguir cadenas que satisfacen
el mismo número de cláusulas.
Una versión mejorada de este algoritmo evolutivo, denominada RFEA, usa una
población de tamaño tp = 4, selección por torneo, y un esquema de reemplaza-
miento basado en la eliminación del peor individuo. Además, un nuevo individuo es
rechazado si ya está en la población. El operador de mutación consiste en seleccionar
una cláusula de entre las que no se verifican y cambiar el valor de una de las variables
de la cláusula, elegida aleatoriamente.
La adaptación de vj tiene como objeto escapar del óptimo local y se define como
sigue
vj ← vj − K(x∗j ) · |Uj (x∗ )|
donde x∗ es el actual individuo mejor adaptado y |Uj (x∗ )| denota el cardinal del
conjunto de cláusulas que no se satisfacen y que contienen la correspondiente variable
x∗j .
Existen otras formas de aproximar los pesos pero que no vamos a mencionarlas pues
no serán de utilidad en nuestro trabajo.
45
Este algoritmo utiliza un tamaño de población tp = 10, proceso de selección propor-
cional al fitness, y un esquema de reemplazamiento generacional elitista, copiando
los dos mejores individuos de la población actual en la población siguiente. Siempre
se aplica cruce uniforme y un proceso de mutación con probabilidad 0,9, de modo
que, cada bit del individuo que muta cambia de valor con probabilidad 0,5.
Es una versión de FlipGA, introducida por Rossi [22] en 2000, denominada como
algoritmo evolutivo adaptado para el problema de satisfactibilidad. Se obtiene de
FlipGA al considerar un único individuo, esto es, tamaño de población tp = 1, un
esquema de reemplazamiento, denotado por (1 + 1), en el cual de cada individuo se
genera un hijo mediante mutación que sustituye al padre si es mejor y un mecanismo
adaptado para controlar la diversificación en el proceso de búsqueda.
ASAP actua sobre el individuo como sigue: primero, se aplica siempre el proceso
de mutación y se cambia, para cada j ∈ {1 . . . n}, el valor del j ésimo bit con pro-
babilidad µj ∈ [0, 0,5], donde µj es adaptado durante la ejecución. Luego, el nuevo
individuo es mejorado mediante búsqueda local como en FlipGA. Además, un meca-
nismo de adaptación basado en la búsqueda tabu es usado para prohibir que cambie
el valor de algunas variables y para controlar la probabilidad de mutación µj .
46
Caracterı́sticas SAWEA RFEA FlipGA ASAP
Nota 9
Todos los algoritmos propuestos utilizan poblaciones iniciales puramente aleatorias.
Por último, hablaremos de la búsqueda local para los problemas SAT. Con este proceso
se pretende explorar el espacio de búsqueda de las asignaciones de valores para encontrar
una solución que maximice el número de cláusulas que se verifican. Se empieza con una
asignación generada de forma aleatoria y se van generando nuevas asignaciones al cambiar
el valor de verdad de una variable simple. La fase crucial de este proceso es la selección de
la variable que cambia. Existen muchas teorı́as y todas incluyen aleatoriedad y memoria.
Uno de los más populares métodos de búsqueda local para SAT es WSAT. Fue desa-
rrollado por Selman [23] en 1994 y McAllester [18] en 1997. En este caso, la selección de
una variable para ser cambiada se realiza en dos etapas. Primero, una cláusula de entre las
que no se verifican es elegida aleatoriamente. Luego, una de las variables de esta clausula
se selecciona para cambiar su valor (pasa de cero a uno o de uno a cero) obteniendose una
nueva asignación de valores.
Para finalizar, observese que WSAT y FlipGA, y en consecuencia ASAP, adoptan
diferentes estrategias de búsqueda. Mientras que una iteración de WSAT actua localmente
sobre una cláusula que no se verifica, modificandola sin afectar al resto de cláusulas que
si se verifican, en FlipGA, cada iteración actua globalmente sobre el problema con el fin
de reducir el número total de cláusulas que no se verifican.
47
Capı́tulo 4
4.1. Introducción
Ejemplo 22
Sea A = { a, b} un alfabeto.
Consideramos las cadenas
ω1 = abbabbab
ω2 = abbabab
Es evidente que ω1 6= ω2 .
Una idea tan sencilla como la de recorrer ambas cadenas sı́mbolo a sı́mbolo (de forma
simultánea) y comparar ambos sı́mbolos, nos permite diseñar un método que determina si
ω1 coincide con ω2 .
48
ω1 - a b b a b b a ···
⇒ ω1 6= ω2
ω2 - a b b a b b b ···
6
Ejemplo 23
Tenemos que encontrar dos cadenas ω1 y ω2 sobre el alfabeto A = { a, b} tal que al
reemplazar x por ω1 e y por ω2 en la ecuación
xabbxy = aabbaabaaa
Nota 10
La búsqueda de patrones en ecuaciones donde uno de los lados es constante (formado
por la cadena texto) y en el otro aparecen los patrones a encontrar (representados por
variables) ha sido muy estudiado y existen algoritmos bastante eficientes que lo resuelven.
Ejemplo 24
Determinar la solución de la ecuación
xaxbya = bybyax
Soluciones parciales de este problema se conocen desde hace tiempo. En 1972, Lentin [15],
Plotkin [20] y Siekmann [25] diseñaron procedimientos de semi decisión, es decir, algorit-
mos que encuentran una solución si existe alguna pero que podrı́an no terminar si no existe
49
solución. En 1971 Hmelevski [11] resuelve el problema para ecuaciones con tres variables.
Finalmente, en 1977 Makanin [16] resuelve el problema mediante el primer algoritmo (y
único conocido hasta la fecha) que encuentra solución si existe alguna y además es capaz
de determinar la no existencia de solución.
Los documentos originales de Makanin estaban enfocados a determinar si la existencia
de solución de este tipo de ecuaciones, denominadas “word equation”, es un problema
decidible. No estaba interesado en la complejidad o en la implementación del algoritmo.
Aunque posteriormente se han realizado mejoras (Pécuchet [19], Abdulrab [1], Jaf-
far [13], Schuld [24], Koscielski, Pachóski [14], entre otros, consiguieron simplificar algunos
de los detalles técnicos de la demostración, empezaron a aproximar el problema desde un
punto de vista computacional y realizaron un estudio sistemático de su complejidad) el
algoritmo de Makanin sigue siendo inviable en la práctica.
El desarrollo teórico del algoritmo de Makanin que aparece en este documento nos
permitirá comprender su funcionamiento y nos dará una idea de su complejidad computa-
cional.
Definición 23
Se llama “word equation” al par
Definición 24
Se llama longitud de la ecuación E ≡ (L, R) al número dado por |E| = |L| + |R|.
Nota 11
Aunque V es un conjunto infinito de variables, en una ecuación E aparecen sólo un número
finito de variables que, en genral, denotaremos por Ω = {x1 , . . . , xn } ⊆ V.
50
Definición 25
Se llama sistema de “word equations” a cualquier conjunto de ecuaciones
{ L1 = R1 , . . . , Lk = Rk }
Definición 26
Un homomorfismo
σ : (A ∪ Ω)∗ −→ A∗
se dice solución de un sistema de “word equations” cuando deja invariantes los elementos
del alfabeto A y además
σ(Li ) = σ(Ri )
para todo i = 1, . . . , k.
Definición 27
X
Una solución σ de un sistema se dice mı́nimal si la suma |σ(x)| es mı́nima en el
x∈ Ω
conjunto de longitudes de las soluciones.
Definición 28
Dado un sistema de “word equations” sobre un alfabeto A, de conjunto de variables
Ω = {x1 , . . . , xn }, se llama exponente de periodicidad de una solución σ al máximo
exponente de periodicidad de las cadenas σ(xi ) para i = 1, . . . , n.
51
x b
a y
siendo la longitud de las lineas horizontales desconocida en cada caso, excepto, las co-
rrespondientes a las constantes que son siempre de longitud uno. Las lineas verticales se
llamaran fronteras.
La ecuación posee solución si existe una forma consistente de superponer ambos lados
de la igualdad de manera que los trozos (representados mediante segmentos horizontales)
entre las fronteras coincidan.
En general, existen muchas posibilidades para hacer las superposiciones. Para la ecuación
dada
xaby = ybax
x b x b
a y a y
y a y a
b x b x
Nota 12
Dibujamos los sı́mbolos en distintos niveles para destacar las fronteras de cada uno.
En la siguiente etapa, se eliminan los sı́mbolos que coinciden desde la izquierda hasta
la derecha. Por ejemplo, en la representación
x b
a y
y a
b x
52
podemos reemplazar y = xa en el otro suceso de y, para obtener
b a b a
x x
=⇒ =⇒ xa = ax
a a
b x b x
El número de veces que aparece una variable puede aumentar después del reemplaza-
miento.
x b
a y
y a
b x
Este proceso puede entrar en un bucle infinito. En uno de los ejemplos anteriores, se
llega a ax = xa.
53
Por estos motivos es necesario un estudio más elaborado de la representación.
Empezamos construyendo, para cada “word equation”, una representación como la
anterior. Es conveniente, para evitar que el número de ocurrencias de una variable aumente
con los reemplazamientos, trabajar con un sistema equivalente de ecuaciones en el cual
cada variable aparece no más de dos veces en cada ecuación.
Nota 13
Siempre es posible pasar de un sistema de “word equations” dado a otro equivalente donde
todas las variables ocurren a lo sumo dos veces.
Ejemplo 25
Sea la ecuación bxyx = yaxz.
Las variables de esta ecuación son
para evitar que la variable x aparezca tres veces. Ahora, todas las variables suceden no
más de dos veces en cada ecuación. Una posible representación de este sistema equivalente,
con fronteras ordenadas, vendrı́a dada como sigue:
b y
x1 x1 x1
Notar que ambas ecuaciones pueden ser representada en la misma gráfica de la siguiente
forma:
54
b y
x1 x1
x2
y x2
a z
1 2 3 4 5 6 7
Además, resulta conveniente tener exactamente dos copias de cada variable en la repre-
sentación. En este caso, tenemos que añadir una copia de la variable z. Ası́, la repre-
sentación final del sistema viene dada por
b y
x1 x1
x2
z
y x2
a z
1 2 3 4 5 6 7
Introducimos los conceptos utilizados por Makanin [16, 13, 24] para poder comprender
dicho algoritmo.
Definición 29
Sea (BD, ≤) un conjunto finito de números naturales que denominaremos conjunto de
fronteras.
Se llama base a una tupla
bs = (t, (e1 , . . . , en ))
55
Definición 30
Una base bs = (t, Ebs ) ∈ BS se dice constante si t ∈ A. En otro caso, es decir, si t ∈ Ω se
dirá base variable.
Definición 31
Sea bs ∈ BS, cualquiera.
Se llama frontera izquierda de la base bs al primer elemento en Ebs .
Se denotará Izq(bs).
Se llama frontera derecha de la base bs al último elemento en Ebs .
Se denotará Der(bs).
Nota 14
Las letras i, j,. . . se usarán para denotar las fronteras.
Ejemplo 26
Sea BD = {1, 2, 3, 4, 5, 6}, A = {a, b} y Ω = {x, y, z}.
Consideramos las bases
Resulta que bs1 es una base constante con Izq(bs1 ) = 1 y Der(bs1 ) = 7, mientras que bs2
es una base variable con Izq(bs2 ) = 1 y Der(bs2 ) = 6.
Definición 32
Se llama ecuación generalizada (EG) a la tupla (A, Ω, BD, BS) tal que
1. Para cada x ∈ Ω hay exactamente dos bases, llamadas duales y denotadas por x y
x̄, respectivamente.
Además, las secuencias de fronteras asociadas, Ex y Ex̄ , deben tener la misma lon-
gitud.
Ejemplo 27
Sea A = {a, b} y Ω = {x, y}.
Se tiene la siguiente ecuación generalizada:
56
x y
a b
b a
y x
1 2 3 4 5 6 7
BS = {(x, (1, 3)), (x, (5, 7)), (y, (4, 6)), (y, (2, 4)), (a, (3, 4)), (a, (4, 5)), (b, (6, 7)), (b, (1, 2))}.
Definición 33
Se llama columna de una EG a un par (i, j) de fronteras tal que i ≤ j.
Para todo i, la columna (i, i) se dice vacı́a y la columna (i, i+1) se dice indescomponible.
Dada una base bs, cualquiera. Se define
Definición 34
Una EG se dice que está resuelta si todas sus bases variables son vacı́as.
Definición 35
Se llama unificador de una EG a una función σ que asigna a cada columna indescomponible
de la EG una cadena ω ∈ A ∪ Ω (extendida por concatenación a todas las columnas no
vacı́as de la EG) verificando las siguientes propiedades:
σ(col(bs)) = a
Nota 15
Si ej ∈ Ex entonces ēj ∈ Ex̄ .
57
Veamos algunas de las propiedades que verifica el unificador σ de una EG.
Lema 1
Si existe unificador de la EG entonces el sistema asociado L(EG, a) es resoluble para cada
constante a ∈ A.
58
Definición 37
Una EG se dice que es admisible si su sistema asociado L(EG, a) es resoluble para cada
a ∈ A.
Para finalizar esta sección veremos que cualquier “word equation” se puede escribir
como un conjunto finito de ecuaciones generalizadas.
Lema 2
Dada E una “word equation”, existe un algoritmo GEN que proporciona un conjunto finito
de ecuaciones generalizadas GEN(E) verificando las siguientes propiedades:
1. E tiene un unificador con exponente de periocidad p sı́ y sólo si alguna EG ∈ GEN (E)
posee un unificador estricto con exponente de periocidad p.
2. Para cada EG ∈ GEN (E), toda frontera es la frontera derecha o izquierda de una
base.
Además, toda secuencia de fronteras contiene exactamente a estas dos fronteras.
Ejemplo 28
Sean A = {a, b} y Ω = {x, y, z}.
La “word equation” E ≡ (bxyx, yaxz) tiene asociado el conjunto finito de ecuaciones
generalizadas GEN(E).
Antes de determinar este conjunto GEN(E) notar que es conveniente trabajar con un
sistema equivalente de ecuaciones en el que cada variable ocurre no más de dos veces en
cada ecuación. Esto siempre es posible, basta con redefinir las variables.
En este caso, la ecuación E es equivalente al sistema
A = {a, b}
Ω̃ = {x1 , x2 , y, z}
59
BD = {1, . . . , 7}
BS = {(b, (1, 2)), (a, (3, 4)), (x1 , (2, 3)), (x1 , (5, 7)), (y, (3, 5)),
(y, (1, 3)), (x2 , (4, 6)), (x2 (5, 7)), (z, (6, 7)), (z, (6, 7))}
b y
x1 x1
x2
z
y x2
a z
1 2 3 4 5 6 7
x b
a y
y a
b x
1 2 3 4 5 6 7 8
60
El conjunto de bases viene dado por
BS = {(x, (1, 5)), (x, (4, 8)), (y, (7, 8)), (y, (1, 2)), (a, (5, 6)), (a, (3, 4)), (b, (2, 3)), (b, (6, 7))}
Las variables situadas más a la izquierda son x e y, pero la más grande es x. Ası́ que,
tomamos x como variable portadora y al intentar trasladar toda su columna, (1, 5), a
la posición de su dual nos encontramos con dificultades en cuanto a la identificación de
nuevas fronteras. Dichas dificultades motivan las siguientes definiciones:
Definición 38
Se llama portadora de la EG a la base de variable no vacı́a con frontera izquierda más
pequeña.
Si hay más de una, se toma la que tiene mayor frontera derecha.
Si todavı́a hay más de una candidata, se elige una al azar entre estas.
Se denotará por xc la portadora de la EG. Sus fronteras serán lc = Izq(xc ) y rc = Der(xc ).
Se define la frontera crı́tica de la EG como sigue
min{Izq(y) : rc ∈ col(y)} si {Izq(y) : rc ∈ col(y)} 6= ∅
cr =
r si {Izq(y) : rc ∈ col(y)} = ∅
c
Definición 39
Dada bs una base cualquiera de EG tal que bs no es portadora.
Se dice que bs es superfluo si col(bs) = (i, i) < lc .
Se dice que bs es transporte si lc ≤ Izq(bs) < cr o bien col(bs) = (cr , cr ).
En otro caso, la base bs se dice fija.
Nota 16
Todas las bases variables con Izq(x) < lc son vacias como consecuencia de la definición
de base portadora. Además, cada base, excepto la portadora, es exactamente superflua,
transporte o fija, dependiendo de la región que ocupe por debajo de su frontera derecha
en el diagrama.
b1 lc cr rc bm
superfluo transporte
(col(b1 ) < lc ) (lc ≤ Izq(bs) < cr ) fijo fijo
61
Ejemplo 30
1. En este diagrama
x b
a y
y a
b x
1 2 3 4 5 6
la variable portadora es y.
Para esta variable, lc = 1 y rc = 3. Por lo tanto,
2. En el siguiente diagrama
x b
a y
y a
b x
1 2 3 4 5 6 7 8
la variable portadora es x.
Para esta variable, lc = 1 y rc = 5. Por lo tanto,
Hemos obtenido un método para determinar las bases que deberı́amos mover, las bases
transporte. Ahora, vamos a estudiar hacı́a donde se deben trasladar estas bases.
Definición 40
Se llama impresión de una EG a una ordenación lineal ≤ en el conjunto
BD ∪ {itr : i ∈ [lc , rc ]}
62
verificando las siguientes propiedades:
etr
i = ēi para algún ei ∈ Ex ⇒ tr(Ex ) = Ēx
4. Si (c, (i, j)) es una base constante, entonces i, j son consecutivos en el orden ≤.
Además, itr y j tr tambien son consecutivos cuando i, j ∈ [lc , rc ].
Es decir, las constantes se conservan.
Nota 17
Para cada frontera i ∈ [lc , rc ] denotamos por itr al nuevo lugar que ocupa la frontera i tras
el transporte. En general,
Una vez realizada la clasificación de las bases y una impresión de la EG, es decir, una
guı́a de a donde vá cada frontera transportada, se dejan las bases fijas (intactas) y se
mueven todas las bases transporte. De esta forma estamos reemplazando igualdades por
igualdades de izquierda a derecha.
Por lo tanto, el algoritmo de Makanin se guı́a mediante la variable portadora y su dual.
Ejemplo 31
Consideramos la siguiente EG:
u
x̄c
xc ū
y
ȳ
1 2 3 4 5 6 7 8
donde BS = {(u, (1, 3)), (ū, (6, 8)), (xc , (1, 5)), (x̄c , (5, 8)), (y, (3, 5, 7)), (ȳ, (2, 4, 5))}
63
xc es la variable portadora tal que lc = 1 y rc = 5.
Calculamos la frontera crı́tica,
cr = min{Izq(y) : rc ∈ col(y)} = 3
Por lo tanto, lc cr rc
u
x̄c
xc ū
y
ȳ
1 2 3 4 5 6 7 8
Ec = Ec ∩ {i ∈ BD : cr = 3 ≤ i} = {3, 4, 5}
Ēc = Ēc ∩ {i ∈ BD : ctr
r = 7 ≤ i} = {7, 8}
lc cr rc
u
x̄c
xc ū
y
ȳ
1 2 3 4 5 6 7 8
64
lc cr rc
u
x̄c
xc ū
y
ȳ
1 2 3 4 5 6 7 4tr 8
Ya sólo queda por transportar u y ȳ. Como las variable y y su dual tienen un segmento
en común, se pierde parte de la información al transportar ȳ. Teniendo en cuenta que
obtenemos la gráfica
lc cr rc
x̄c
u
xc ū
y
ȳ
1 2 3 4 5 6 7 4tr 8
1. La raiz de T (E) es E.
3. Para cada nodo EG (distinto de la raiz), el conjunto de sus hijos es un número finito
de ecuaciones generalizadas, T RAN S(EG).
65
Teorema 2
Sea E una “word equation”.
E tiene un unificador si y sólo si T (E) tiene un nodo etiquetado con una ecuación gener-
alizada resoluble.
Examinar todos los nodos del árbol T (E) para averiguar si E tiene solución.
Nota 18
En general, el árbol de Makanin asociado a una “word equation” puede ser infinito. Sin
embargo está demostrado que existe un número finito kE que acota el número de nodos
que hay que visitar. Si no se encuentra solución tras la visita de dichos kE nodos, se puede
concluir que no existe solución. kE es de carácter doblemente exponencial en la longitud
de la ecuación E.
Para finalizar este capı́tulo vamos a exponer algunos resultados conocidos para casos
particular de sistemas de “word equations”.
Definición 42
Un sistema de “word equations” se dice cuadrático si cada variable aparece a lo sumo dos
veces en el sistema.
Hablaremos de sistemas cuadráticos para referirnos a los sistemas de “word equations” de
tipo cuadrático.
El algoritmo más sencillo que los resuelve usa un espacio lineal no determinı́stico. En la
primera etapa se comprueba qué variables pueden ser reemplazadas por la palabra vacı́a,
de modo que podemos suponer que las ecuaciones son de la forma
x... = y...
66
Repetimos el proceso sucesivamente.
Aunque el tamaño del sistema cuadrático nunca decrece, la longitud de una solución
mı́nima decrece en cada etapa. Por lo tanto, el algoritmo no determinı́stico encontrará una
solución, si la hay.
Teorema 3
Sea |A| ≥ 2.
El problema de decidir la existencia de solución de una “word equation” cuadrática es
NP duro.
Demostración 2
Consideramos un problema 3 SAT dado por la función
F = C0 ∧ · · · ∧ Cm−1
xj para j = 0, . . . , 3m − 1
ci di = a3m−1
v = X̃i1 = · · · = X̃ik
67
y el conjunto de posiciones {j1 , . . . , jn } talque
ṽ = X̃j1 = · · · = X̃jn
yv zv = b
ci di = a3m−1
yv zv = b
tiene solución.
Pero, cualquier sistema de k “word equations”, con k ≥ 1
L1 = R1 , . . . , Lk = Rk
68
Destacar que es posible reducir un problema de tipo 3 SAT a un sistema de “word
equations”, de forma análoga al esquema utilizado en la anterior demostración.
Demostración 3
Consideramos un problema 3 SAT dado por la función
F = C0 ∧ · · · ∧ Cm−1
ci , di para i = 0, . . . , m − 1
yv zv = 1
ci di = 11
donde
yv si X̃j = v
vj =
z si X̃j = ṽ
v
69
ci di = 11
yv zv = 1
Definición 43
Dado un sistema S de n “word equations” sobre un alfabeto A y con variables en el
conjunto Ω = {x1 , . . . , xm }.
Se llama l sistema de “word equations” al problema de determinar si existe una solución
de S
σ : (A ∪ Ω)∗ −→ A∗
Demostración 4
Es fácil ver que l SW ES está en NP.
Tomando como cota l = 2, se obtiene el resultado de forma análoga a como se probó la
proposición 2, pero en este caso se pueden suprimir del sistema equivalente a F las ecua-
ciones de la forma ci di = 11 para cada i = 0, . . . , m − 1.
En consecuencia 3 SAT se reduce ha 2 SW ES.
Nota 19
Nuestro trabajo se centrará en la búsqueda de solución de los problemas l SW ES sobre
el alfabeto binario A = {0, 1}.
70
Capı́tulo 5
5.1. Introducción
S = { L1 = R1 , . . . , Ln = Rn }
71
longuitud menor o igual que l sobre el alfabeto A.
Definimos un nuevo sı́mbolo B, que llamaremos sı́mbolo blanco, de modo que, todas las
variables del problema l SW ES se pueden codificar como cadenas de longitud exactamente
igual a l sobre el nuevo alfabeto B = {0, 1, B} de la siguiente forma:
para cada i = 1, . . . , m, sea αi la codificación de la variable xi sobre B, esta codificación
es una cadena formada por sı́mbolos de B que se lee de izquierda a derecha y cada vez que
se encuentra el sı́mbolo blanco B se pasa al siguiente sı́mbolo sin hacer nada.
Ejemplo 32
Las cadenas sobre B = {0, 1, B} dadas por
α1 = 01BB0B011BBB
α2 = BB01BB0BB0BB
α3 = 111B11BB0
se leen como
β1 = 010011
β2 = 0100
β3 = 111110
α1 = 01B011BBB
α2 = B01BB0B1BB1
α3 = 0101B1BB
α4 = BB0B1B0B1B1B
01011
Por lo tanto, una misma variable candidata a formar parte de la solución del problema
puede tener distintas codificaciones. Ası́ que, con el fin de unificar la codificación de las
variables y para poder simplificar los procesos de cruce y mutación que estudiaremos más
72
tarde, reordenaremos de la siguiente forma las codificaciones:
recorriendo de izquierda a derecha la codificación desplazamos los sı́mbolos B al final de
la cadena.
Con esta reordenación conseguimos construir un representante de todas las posibles
codificaciones de una misma variable.
Ejemplo 34
Sea la codificación dada por
0B10B00B1BB1B001
0100011001BBBBBB
Nota 20
La cadena formada sólo por sı́mbolos blancos representa la cadena vacia, Λ.
Una vez codificadas las variables del problema, definimos un individuo como la con-
catenación de las cadenas αi para i = 1, . . . , m que se obtienen al codificar las m variables
x1 , . . . , xm .
Ejemplo 35
Supongamos que tenemos que codificar 4 variables de longitud menor o igual a 6 sobre el
alfabeto binario A. Sean
α1 = B01B10
α2 = BB1BB0
α3 = 11BB1B
α1 = 0110BB
α2 = 10BBBB
α3 = 111BBB
I = α1 α2 α3 = 0110BB
| {z } 10BBBB
| {z } 111BBB
| {z }
α1 α2 α3
73
Nota 21
No tiene sentido reordenar las cadenas que representan individuos de la población, pues
perderı́amos la información de las variables que componen esas posibles soluciones del
problema.
Para finalizar esta sección, queremos destacar que con esta codificación de los indivi-
duos conseguimos que todos tengan la misma longitud, m · l. Además, todas las variables
son codificadas como cadenas de longitud igual a l, aunque la longitud real de la variable
que se representa es menor o igual que l, pues el sı́mbolo B no aporta nada al valor de las
variables. Por lo tanto, buscamos soluciones en un espacio de búsqueda de tamaño
à l !m
X
2i = (2l+1 − 1)m
i=0
Trabajaremos con poblaciones de tamaño fijo, tp. Aunque el algoritmo que diseñaremos
permitirá al usuario elegir el tamaño de la población con el que quiere resolver el problema,
uno de nuestro primeros objetivos será determinar el tamaño de la población más adecuado
para la resolución de los problemas l SW ES.
Una vez fijado el tamaño tp, la población inicial será generada de forma aleatoria.
Para la implementación de este proceso proponemos dos métodos.
Método 1.
αi = βi β̄i
I = α1 · · · αm
Ejemplo 36
Generamos una población de tamaño tp = 3 para resolver un problema 4 SW ES
con dos variables. (l = 4)
74
Empezamos definiendo el primer individuo de la población inicial, I1 .
Para i = 1 elegimos al azar la longitud de la subcadena β1 , sea lr (1) = 2 ∈ {0, 1, . . . , 4}.
Construimos aleatorimente β1 = 01. Definimos β̄1 = BB.
Se obtiene la cadena α1 = β1 β̄1 = 01BB.
Para i = 2 elegimos al azar la longitud de la subcadena β2 , sea lr (2) = 4 ∈ {0, 1, . . . , 4}.
Construimos aleatoriamente β2 = 0110. Definimos β̄2 = Λ.
Se obtiene la cadena α2 = β2 β̄2 = 0110Λ = 0110.
Por lo tanto, se tiene que
I1 = α1 α2 = 01BB0110
I2 = α1 α2 = 1BBBBBBB
Método 2.
75
alfabeto B y luego reordenamos dicha cadena para que todos los sı́mbolos blancos
estén situados al final de la misma. Finalmente, definimos el individuo
I = α1 · · · αm
Ejemplo 37
Generamos una población de tamaño tp = 3 para resolver un problema 4 SW ES
con dos variables. (l = 4)
Empezamos definiendo el primer individuo de la población inicial, I1 .
Para i = 1 construimos aleatorimente la cadena α1 = B1B0, después de la reorde-
nación se tiene que α1 = 10BB.
Para i = 2 construimos aleatoriamente la cadena α2 = BB1B, después de la reorde-
nación se tiene que α2 = 1BBB.
Por lo tanto,
I1 = α1 α2 = 10BB1BBB
76
5.4. Evaluación de los Individuos
Este es un paso muy importante en el diseño del algoritmo genético, pues tenemos
que encontrar una función fitness sencilla, es decir, con poco coste a la hora de evaluar
los individuos, y que al mismo tiempo nos permita guiar el proceso de búsqueda de las
soluciones de la forma más eficiente posible.
Un individuo I = α1 · · · αm es solución del problema l SW ES si al sustituir las sub-
cadenas αi por las variables xi , para i = 1, . . . , m, en el sistema de “word equations” se
obtienen identidades.
Ejemplo 38
Consideramos el problema 3 SW ES dado por el sistema
01x1 1 = x2 1x1
x1 01x2 = 10x2 1
I1 = 11B01B
I2 = 1BB01B
Veamos si alguno de los individuos de esta población es solución del problema. Empezamos
sustituyendo el individuo I1 .
Como,
α1 = 11B - x1 = 11
I1 = 11B01B -
α2 = 01B - x2 = 01
resulta que
01x1 1 = x2 1x1 - 01111 = 01111
x1 01x2 = 10x2 1 - 110101 6= 10011
Es decir, I1 no es solución.
Ahora, comprobamos si I2 es solución.
Como,
α1 = 1BB - x1 = 1
I2 = 1BB01B -
α2 = 01B - x2 = 01
77
resulta que
01x1 1 = x2 1x1 - 0111 = 0111
x1 01x2 = 10x2 1 - 10101 6= 10011
I2 tampoco es solución.
Observamos que aunque ninguno de los dos individuos de la población son solución, ambos
hacen que se verifique la primera de las ecuaciones del sistema. Sin embargo, parece estar
más proximo a la solución el individuo I2 pues sólo dos sı́mbolos de la segunda ecuación
del sistema no coinciden.
Este ejemplo, nos sugiere definir el fitness asociado a un individuo como el número
de sı́mbolos que no coinciden al sustituir dicho individuo en el sistema. De esta forma,
nuestro objetivo será minimizar el valor de la función fitness, es decir, conseguir que nigún
sı́mbolo sea distinto del correspondiente situado en el otro lado de la ecuación.
Definición 44
Sea S = {L1 = R1 , . . . , Ln = Rn } un l SW ES.
Se define el fitness asociado a un individuo I como el valor dado por
n
X
f (I) = (max{lk , rk } − ck )
k=1
siendo lk = |Lk (I)|, rk = |Rk (I)| y ck el número de sı́mbolos que coinciden al sustituir el
individuo I en la k ecuación del sistema, para cada k = 1, . . . , n.
Nota 22
Al sustituir en cada ecuación Lk = Rk el individuo I, obtenemos dos cadenas Lk (I) y
Rk (I) sobre el alfabeto A cuyas longitudes hemos denotado por lk y rk , respectivamente.
El individuo I será solución del sistema si Lk (I) = Rk (I) para cada k = 1, . . . , n.
Ejemplo 39
Volviendo al sistema del anterior ejemplo
01x1 1 = x2 1x1
x1 01x2 = 10x2 1
I1 = 11B01B
I2 = 1BB01B
78
Veamos quien es el fitness asociado a cada uno de estos individuos:
Al sustituir I1 en el sistema se obtiene
Como L1 (I1 ) = R1 (I1 ), todos los sı́mbolos del lado izquierdo de la ecuación coinciden con
los del lado derecho, por lo tanto, c1 = 5. Luego, f1 (I1 ) = max{l1 , r1 } − c1 = 5 − 5 = 0.
En la segunda ecuación resulta que L2 (I1 ) 6= R2 (I1 ). Contamos los sı́mbolos que ocupando
la misma posición en ambas cadenas coinciden.
L2 (I1 ) = 1 1 01 01
R2 (I1 ) = 1 0 01 1
Como L1 (I2 ) = R1 (I2 ) todos los sı́mbolos del lado izquierdo de la ecuación coinciden con
los del lado derecho, por lo tanto, c1 = 4. Luego, f1 (I2 ) = max{l1 , r1 } − c4 = 4 − 4 = 0.
En la segunda ecuación resulta que L2 (I2 ) 6= R2 (I1 ). Contamos los sı́mbolos que ocupando
la misma posición en ambas cadenas coinciden.
L2 (I2 ) = 10 10 1
R2 (I2 ) = 10 01 1
79
Se obtiene que c2 = 3. Luego, f2 (I2 ) = max{l2 , r2 } − c2 = max{5, 5} − 3 = 5 − 3 = 2.
Por lo tanto,
2
X 2
X
f (I2 ) = fk (I2 ) = (max{lk , rk } − ck ) = 0 + 2 = 2
k=1 k=1
Como el fitness asociado a I2 es menor que el asociado a I1 podemos concluir que es mejor
candidata a solución la cadena I2 .
Nota 23
Cuando sustituimos un individuo en una ecuación obtenemos dos cadenas sobre el alfabeto
A, las correspondientes al lado derecho e izquierdo de la ecuación, que no tienen por que
tener la misma longitud. Una condición necesaria para que ambas cadenas coincidan es
que tengan la misma longitud, por eso a la hora de calcular el fitness no sólo contamos
los sı́mbolos que ocupando las mismas posiciones en ambas cadenas no coinciden sino que
también contamos los sı́mbolos que hacen que una cadena tenga mayor longitud, es decir,
los sı́mbolos situados entre la posición min{lk , rk } + 1 y max{lk , rk }.
Selección
80
Individuo fitness
I1 2
I2 12
I3 5
I4 7
sum = 2 + 12 + 5 + 7 = 26
P
Individuo fitness f^
itness fe(Ii )/ 4j=1 fe(Ij )
I1 2 24 24/78 = 0,31
I2 12 14 14/78 = 0,18
I3 5 21 21/78 = 0,27
I4 7 19 19/78 = 0,24
Cruce
I1 = α11 · · · αm
1
I2 = α12 · · · αm
2
se define el operador de cruce como un proceso que cruza cada subcadena αi1 = βi1 β̄i1
con la subcadena αi2 = βi2 β̄i2 , para i = 1, . . . , m, en dos etapas, obteniendose un
81
nuevo individuo.
Recordar que cada subcadena αi sobre el alfabeto B = {0, 1, B} está formada por
dos subcadenas βi y β̄i siendo βi una cadena de longitud menor o igual que l sobre
el alfabeto A = {0, 1} y β̄i una cadena de sı́mbolos blancos.
En la primera etapa, se aplica un cruce uniforme como sigue:
Ejemplo 41
Vamos a aplicar la primera etapa del cruce a las subcadenas
αi1 = 011101 BB
| {z } |{z}
βi1 β̄i1
αi2 |{z } BBBB
= 1101 | {z }
βi2 β̄i2
Calculamos la posición
αi (1, 4) = 0101
1. Elegimos una posición q ∈ {k, . . . , l}, siendo l la longitud de las cadenas αi1 y
αi2 , para i = 1, . . . , m.
82
2. Si una de las dos cadenas αi1 (k + 1, l) ó αi2 (k + 1, l) contiene algun sı́mbolo
distinto de B, definimos αi (k + 1, q) con las q − k primeras posiciones de esa
cadena y completamos la subcadena αi con l − q sı́mbolos blancos, es decir,
αi (q + 1, l) = B l−q .
En otro caso, se define αi (k + 1, l) = B l−k
Nota 24
Si q = k entonces αi = (k + 1, l) = B l−k
Ejemplo 42
En el ejemplo anterior aplicamos la primera etapa del cruce a las subcadenas
αi1 = 011101BB
αi2 = 1101BBBB
Obtuvimos αi (1, 4) = 0101. Ahora aplicamos la segunda etapa del cruce para definir
αi (5, 8). Para ello, tenemos que eligir una posición entre 4 y 8, sea q = 7.
Como αi1 (5, 8) = 01BB tiene sı́mbolos distintos del blanco, definimos αi (k+1, q) = αi (5, 7)
con los q − k = 3 primeros sı́mbolos de αi1 (5, 8) = 01BB, es decir, αi (5, 7) = 01B.
Finalmente, completamos la cadena αi con l − q = 1 sı́mbolos blancos.
Hemos construido la subcadena
αi = 010101BB
Repitiendo este proceso para cada par de subcadenas αi1 y αi2 conseguimos definir
un nuevo individuo a partir de los individuos I1 e I2 .
Mutación
83
Recordar que la subcadena αi toma valores en el alfabeto B. Ası́ pues, tras el proceso
de mutación es necesario reordenar de nuevo para situar los sı́mbolos blancos al final.
Hemos definido todas los elementos necesarios para el diseño del algoritmo genético
simple. En el apendice A se encuentra el código de este algoritmo escrito en el lenguaje
C++.
Veamos con un sencillo ejemplo su funcionamiento.
Ejemplo 43
Consideramos el problema 3 SW ES dado por las ecuaciones
x2 x1 = 10x2
x2 10x1 = 1x1 0x1
Población inicial
84
α14 = BB1 - α14 = 1BB
- I40 = 1BB10B
α24 = 1B0 - α24 = 10B
I10 = 01B11B
I20 = 0111BB
I30 = 1010BB
I40 = 1BB10B
Individuo P0 fitness f^
itness P (Ii )
Individuo P1 fitness
I11 01B11B 3
··· ··· ···
85
Tenemos que generar otros tres individuos mediante los operadores genéticos para com-
pletar la población P1 .
Generación de I21 :
Selección
Cruce
Mutación
Generación de I31 :
Selección
86
Cruce
Mutación
Repitiendo este proceso generamos los otros individuos de la población. Tras la evaluación
de los nuevos individuos se obtine la siguiente tabla para la población P1 ,
Individuo P0 fitness
I11 01B11B 3
I21 01B01B 4
I31 1BB11B 5
I41 01B10B 0
Como uno de los individuos de la nueva población tiene fitness 0, el algoritmo ha finalizado.
La solución propuesta es
x1 = 01
x2 = 10
87
Capı́tulo 6
2. Generar las variables como cadenas de longitud menor o igual que lmax sobre el
alfabeto A.
3. Para cada variable generada, recorrer el sistema buscando una subcadena que coinci-
da con la variable. Si la encuentro, sustituyo con probabilidad p la subcadena por la
letra que representa a la variable y lo sigo recorriendo en busca de otra coincidencia.
Sin embargo, esta idea tan sencilla no nos garantiza que, al final, el sistema generado
contenga todas las variables pues, por ejemplo, una variable puede ser generada como una
cadena sobre A que no es subcadena en ninguna de las ecuaciones del sistema.
Logicamente, fijado un número de ecuaciones, n, y un número de variables, m, nuestro
interés es construir un sistema de n “word equations” sobre el alfabeto A que contenga
88
exactamente m variables, x1 , . . . , xm . Por lo tanto, nos vemos obligados a modificar esta
primera idea y construimos un algoritmo con los siguientes pasos:
3. Una vez que se han generado todas las variables, recorremos el sistema en busca de
coincidencias para cada variable xi , i = 1, . . . , m. Si se encuentra una subcadena en el
sistema que coincida con la variable xi , se cambia con probabilidad p la subcadena
por la letra que representa a la variable. Con este paso pretendemos aumentar el
número de veces que aparece una variable en el sistema.
Nota 25
A medida que se van generando las variables, el sistema de identidades sobre el alfabeto
A se convierte en un sistema de ecuaciones sobre el conjunto A ∪ {x1 , . . . , xm }.
El paso crı́tico de este algoritmo se encuentra al definir las variables del sistema. In-
tentaremos explicar un poco más este paso. El algoritmo que diseñamos necesita, además
del número de ecuaciones y el número de variables, dos cotas le y lmax . La primera de ellas,
le , indica la longitud máxima de las cadenas que generamos sobre A para construir las
identidades (paso 1). La segunda cota, indica la longitud máxima de las variables. Por lo
tanto, una vez que se ha elegido el lado de la ecuación donde se vá a definir la variable xi ,
se selecciona al azar una posición q de la misma y se cuentan los sı́mbolos (consecutivos)
del alfabeto A que hay a la derecha de q. Si denotamos por lq al número de sı́mbolos del
alfabeto A que hay a la derecha de q, entonces la variable xi se define como un subcadena
89
de longitud lr ∈ {0, min{lmax , lq }} que coincide con el trozo de subcadena de la ecuación
que vá de q a q + lr .
Notar que si lr = 0, entonces la variable xi es la palabra vacı́a.
Nota 26
En general, el problema(n m lmax ) denotará un sistema de n “word equations” con m
variables, de modo que cada variable (al menos en una solución del sistema) tiene longitud
menor o igual que lmax .
b) Si depués de recorrer la ecuación para cada variable ambos lados siguen siendo
iguales, sustituimos dicha ecuación por una nueva identidad sobre el alfabeto
A y volvemos al paso a).
90
Capı́tulo 7
Primeros Resultados
Experimentales
7.1. Introducción
2. La longitud máxima de las variables (l). Ası́, cada individuo estará constituido por
subcadenas de longitud l sobre el alfabeto B.
Nota 27
Con el fin de comparar los resultados obtenidos hemos acotado el número de evaluaciones
que puede realizar el algoritmo para resolver cada problema.
Llamaremos Media Eval. al número medio de evaluaciones que fueron necesarias para
encontrar solución en las pruebas exitosas de las cincuenta realizadas.
Llamaremos Éxito al número de veces que se encuentra solución para un problema. Se
expresará en tanto por cien.
91
7.2. Tamaño de Población
Resolvemos el Problema15-12-4
Tamaño del espacio de búsqueda: aprox. 260
tp Método l Mutación NMax Eval. Exito Media Eval.
2 1 5 60 % 150000 22 % 106887
2 2 5 60 % 150000 34 % 107556
3 1 5 60 % 150000 12 % 108542
3 2 5 60 % 150000 6% 109582
4 1 5 60 % 150000 2% 88213
4 2 5 60 % 150000 0% 0
6 1 5 60 % 150000 0% 0
6 2 5 60 % 150000 0% 0
8 1 5 60 % 150000 0% 0
8 2 5 60 % 150000 0% 0
10 1 5 60 % 150000 0% 0
10 2 5 60 % 150000 0% 0
Nota 28
Siempre encuentra la misma solución y la mayorı́a de las variables que la forman son la
cadena vacı́a, Λ.
92
Resolvemos el Problema25-8-5
Tamaño del espacio de búsqueda: aprox. 248
tp Método l Mutación NMax Eval. Exito Media Eval.
2 1 5 60 % 150000 88 % 27667.5
2 2 5 60 % 150000 94 % 22222.3
3 1 5 60 % 150000 86 % 23132.5
3 2 5 60 % 150000 74 % 29488.7
4 1 5 60 % 150000 70 % 26295.2
4 2 5 60 % 150000 70 % 23354.7
6 1 5 60 % 150000 62 % 48727
6 2 5 60 % 150000 64 % 48273.5
8 1 5 60 % 150000 62 % 65029.6
8 2 5 60 % 150000 56 % 75479.5
10 1 5 60 % 150000 40 % 87881.9
10 2 5 60 % 150000 32 % 95393.1
Otra vez los mejores resultados se obtienen para tamaño de población igual a dos.
Tampoco parece que sea determinante la elección del método que genera la población
inicial.
2 88 % 27667.5 2 94 % 22222.3
3 86 % 23132.5 3 74 % 29488.7
4 70 % 26295.2 4 70 % 23354.7
Nota 29
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
93
Resolvemos el Problema10-3-3
Tamaño del espacio de búsqueda: aprox. 212
tp Método l Mutación NMax Eval. Exito Media Eval.
Problema aparentemente sencillo que nos permite comprobar que mayor tamaño de
población no mejora los resultados pero sı́ produce un aumento en el número de evalua-
ciones, por ejemplo, pasamos de 1261 evaluaciones para una población tp = 10 a tan sólo
223 evaluaciones para una población tp = 2.
Parece que el método 2 reduce el número de evaluaciones pero no es una diferencia lo
suficientemente grande como para decantarnos por este método en lugar del método 1.
Nota 30
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
94
Resolvemos el Problema10-5-2
Tamaño del espacio de búsqueda: aprox. 215
tp Método l Mutación NMax Eval. Exito Media Eval.
Nota 31
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
95
Resolvemos el Problema12-6-4
Tamaño del espacio de búsqueda: aprox. 230
tp Método l Mutación NMax Eval. Exito Media Eval.
Como en los dos casos anteriores el problema12-6-4 ha resultado ser sencillo y el número
de evaluaciones aumenta a medida que crece el tamaño de la población.
Nota 32
Encuentra distintas soluciones.
96
Resolvemos el Problema5-3-2
Tamaño del espacio de búsqueda: aprox. 29
tp Método l Mutación NMax Eval. Exito Media Eval.
Nota 33
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
97
Conclusión 1
Después de este primer contacto con el algoritmo genético resulta evidente que el tamaño
de población más adecuado es tp = 2 pues a medida que crece el número de individuos de
la población disminuye la probabilidad de éxito y aumenta el número de evaluaciones.
Sin embargo, no estamos en condiciones de afirmar que uno de los dos métodos propues-
tos para la generación de la población inicial sea mejor que el otro. Por eso, seguiremos
realizando los experimentos con los dos métodos.
Nota 34
En los sucesivos experimentos tomaremos siempre tamaño de población tp = 2 y acotare-
mos los procesos por 1.5 millones de evaluaciones.
98
7.3. Probabilidad de mutación
Resolvemos el Problema10-15-5
Tamaño del espacio de búsqueda: aprox. 290
tp Método l Mutación NMax Eval. Exito Media Eval.
2 1 5 20 % 1.5e+06 0% 0
2 2 5 20 % 1.5e+06 0% 0
2 1 5 40 % 1.5e+06 2% 1.06558e+06
2 2 5 40 % 1.5e+06 0% 0
2 1 5 70 % 1.5e+06 0% 0
2 2 5 70 % 1.5e+06 2% 1.12725e+06
2 1 5 80 % 1.5e+06 2% 1.37572e+06
2 2 5 80 % 1.5e+06 0% 0
2 1 5 90 % 1.5e+06 2% 801145
2 2 5 90 % 1.5e+06 2% 1.0302e+06
Nota 35
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
99
Resolvemos el Problema10-5-1
Tamaño del espacio de búsqueda: aprox. 210
tp Método l Mutación NMax Eval. Exito Media Eval.
Nota 36
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
100
Resolvemos el Problema10-8-5
Tamaño del espacio de búsqueda: aprox. 248
tp Método l Mutación NMax Eval. Exito Media Eval.
2 1 5 20 % 1.5e+06 98 % 381874
2 2 5 20 % 1.5e+06 94 % 304587
2 1 5 40 % 1.5e+06 98 % 203427
2 2 5 40 % 1.5e+06 100 % 180120
2 1 5 90 % 1.5e+06 98 % 90263.3
2 2 5 90 % 1.5e+06 100 % 93544.5
Nota 37
Encuentra distintas soluciones.
Una de las variables del problema puede tomar distintos valores, el resto de las variables
siempre toman el mismo valor.
101
Resolvemos el Problema25-8-3
Tamaño del espacio de búsqueda: aprox. 232
tp Método l Mutación NMax Eval. Exito Media Eval.
Nota 38
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
102
Resolvemos el Problema25-8-5
Tamaño del espacio de búsqueda: aprox. 248
tp Método l Mutación NMax Eval. Exito Media Eval.
De nuevo, el éxito es del 100 % para todos los experimentos realizados con este prob-
lema, pero el número de evaluaciones mejora para valores de la probabilidad de mutación
entre el 70 % y el 100 %.
Nota 39
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
103
Resolvemos el Problema5-15-3
Tamaño del espacio de búsqueda: aprox. 260
tp Método l Mutación NMax Eval. Exito Media Eval.
2 1 5 20 % 1.5e+06 4% 881354
2 2 5 20 % 1.5e+06 0% 0
2 1 5 40 % 1.5e+06 4% 750816
2 2 5 40 % 1.5e+06 0% 0
2 1 5 70 % 1.5e+06 2% 91868
2 2 5 70 % 1.5e+06 10 % 273665
2 1 5 80 % 1.5e+06 8% 681722
2 2 5 80 % 1.5e+06 0% 0
2 1 5 90 % 1.5e+06 2% 374402
2 2 5 90 % 1.5e+06 10 % 511213
El algoritmo genético simple no siempre encuentra solución. Notar que el tamaño del
espacio de búsqueda es de aprox. 260 . A pesar de ello, los valores de probabilidad de
mutación entre el 70 % y el 100 % proporcionan los mejores resultados.
Nota 40
Encuentra distintas soluciones.
La gran mayorı́a de las variables, aproximádamente 10 de las 15, pueden tomar distintos
valores.
104
Resolvemos el Problema15-12-4
Tamaño del espacio de búsqueda: aprox. 260
tp Método l Mutación NMax Eval. Exito Media Eval.
2 1 5 20 % 1.5e+06 76 % 638268
2 2 5 20 % 1.5e+06 80 % 658522
2 1 5 40 % 1.5e+06 84 % 386301
2 2 5 40 % 1.5e+06 86 % 496717
2 1 5 70 % 1.5e+06 96 % 324814
2 2 5 70 % 1.5e+06 98 % 313743
2 1 5 80 % 1.5e+06 92 % 277741
2 2 5 80 % 1.5e+06 98 % 288551
Nota 41
Siempre encuentra la misma solución y coincide con la propuesta por Genero Problema.
La mayorı́a de las variables son la cadena vacia, Λ.
105
Conclusión 2
Resumen de los mejores resultados obtenidos:
Usando el método 1
Problema Esp. Búsq. Mutación Exito Media Eval.
Usando el método 2
Problema Esp. Búsq. Mutación Exito Media Eval.
Se de duce que los mejores resultados se obtienen con una probabilidad de mutación
comprendida entre el 70 % y el 100 %.
Aunque puede parecer que la probabilidad de mutación es muy alta, hemos obtenido
valores similares a los propuestos en la resolución de los problemas SAT , que en definitiva
es nuestra única referencia.
106
Capı́tulo 8
A partir del algoritmo genético simple, definido en el capı́tulo 5, vamos a construir dos
algoritmos evolutivos.
La codificación de los individuos, la generación de la población inicial, el fitness y
los operadores genéticos se definen de la misma forma. Además, seguiremos acotando la
resolución de los problemas por 1,5 millones de evaluaciones y buscaremos soluciones cuyas
variables sean de longitud menor o igual que cinco.
Como consecuencia de los primeros resultados experimentales, el alto valor que toma
la probabilidad de mutación y teniendo en cuenta los algoritmos evolutivos que fueron
propuestos para resolver SAT (ver capı́tulo 2), resulta interesante modificar nuestro al-
goritmo genético para obtener un algoritmo evolutivo que trabaje con una población de
tamaño tp = 1.
Este algoritmo evolutivo usará sólo el operador genético de mutación.
Si los resultados que proporcionan este algoritmo mejoran los del algoritmo genético
simple, seguiremos nuestro estudio con este nuevo algoritmo o bien intentaremos modificar
el operador de cruce para mejorar el algoritmo genético simple.
El esquema de funcionamiento de este algoritmo es el siguiente
107
Seudocódigo
I0 ← generar población inicial
I0 ← evaluar (I0 )
para k = 1 hasta NIter hacer
I1 ← copiar (I0 )
I1 ← mutar (I1 )
E1 ← evaluar (I1 )
I0 ← mejor individuo (I0 , I1 )
fin para
108
Resulta evidente que el AE no mejora los resultados obtenidos con el AGS. Por lo
tanto, el operador de cruce que hemos definido tiene influencia en la resolución de los
sistemas.
Búsqueda Local 1
109
Notar que hasta ahora lo único que hacı́amos era cambiar los sı́mbolos, pasando
de cero a uno o viceversa, pero la longitud de las cadenas βi , para i = 1, . . . , m
no cambiaba.
Para modificar la longitud de la cadena βi , para i = 1, . . . , m en una unidad,
procedemos como sigue:
Ejemplo 44
Sea βi β̄i = 0010BBB con |βi | = 4 y |β̄i | = 3.
Al disminuir la longitud de βi en una unidad se obtiene
βi β̄i = 001BBBB
Ejemplo 45
Sea βi β̄i = 0010BBB con |βi | = 4 y |β̄i | = 3.
Al aumentar la longitud de βi en una unidad se obtiene dos cadenas
00100BB
00101BB
110
Cuando terminamos de modificar las longitudes de todas las cadenas βi en bus-
ca de un individuo mejor, comprobamos si el fitness ha mejorado, en ese caso
se vuelve a el paso 1. Si no hay mejora, se termina el proceso de búsqueda local
1 aplicado al individuo I.
Búsqueda Local 2
Nota 42
Observese que aunque ambos procedimientos de búsqueda local puedan parecer iguales,
hay una importante diferencia:
mientras que en el proceso de búsqueda local 1 realizamos sucesivas veces (hasta que no
se produzca mejora) lo que hemos denominado búsqueda local clásica antes de tratar de
modificar las longitudes, en el proceso de búsqueda local 2 realizamos en cada iteración
una vez la búsqueda local clásica seguida de una posible modificación en una unidad de
las longitudes.
Hasta ahora hemos resuelto los problemas con ayuda de un algoritmo genético simple.
En esta sección vamos a estudiar los resultados obtenidos al añadir búsqueda local.
Se intentará establecer, si fuese posible, cuál de los dos métodos implementados para
el proceso de búsqueda local es mejor.
También resultará interesante determinar si la mutación sigue siendo importante cuan-
do se usa búsqueda local. Para ello iremos tomando distintos valores de probabilidad de
mutación.
111
Finalmente, compararemos los resultados obtenidos al aplicar un algoritmo genético
simple para resolver los problemas l SW ES y los resultados obtenidos al utilizar un A.E.
con búsqueda local.
Para poder comparar los resultados seguimos manteniendo tamaño de pobalción tp = 2,
longitud máxima de las variables que forman los individuos igual a 5 y acotamos la ejecu-
ción del algoritmo por 1.5 millones de evaluaciones.
Resolvemos el Problema10-3-3
Tamaño del espacio de búsqueda: aprox. 218
Usando el método 1 para generar la población inicial se obtuvo
Parece que la probabilidad de mutación no influye sobre los resultados. Sin embargo,
si queda reflejado la superioridad de la búsqueda local 2 frente a la 1.
Nota 43
Siempre encuentra la misma solución.
112
Resolvemos el Problema10-8-5
Tamaño del espacio de búsqueda: aprox. 248
Usando el método 1 para generar la población inicial se obtuvo
Nota 44
Admite distintas soluciones.
Una de las variables del problema puede tomar distintos valores, el resto de las variables
siempre toman el mismo valor.
113
Resolvemos el Problema10-8-3
Tamaño del espacio de búsqueda: aprox. 248
Usando el método 1 para generar la población inicial se obtuvo
De nuevo hay que destacar la diferencia que existe entre los métodos de búsqueda local
implementados.
Nota 45
Siempre encuentra la misma solución.
114
Resolvemos el Problema10-15-5
Tamaño del espacio de búsqueda: aprox. 290
Usando el método 1 para generar la población inicial se obtuvo
Nota 46
Siempre encuentra la misma solución.
115
Resolvemos el Problema10-15-3
Tamaño del espacio de búsqueda: aprox. 290
Usando el método 1 para generar la población inicial se obtuvo
2 5 20 % 44 % 611542 76 % 338663
2 5 70 % 50 % 652274 94 % 327947
2 5 90 % 68 % 642407 98 % 362663
2 5 100 % 56 % 583024 92 % 264417
2 5 20 % 38 % 646377 72 % 614781
2 5 70 % 48 % 616960 94 % 424924
2 5 90 % 34 % 643584 86 % 401649
2 5 100 % 64 % 573071 92 % 413873
2 90 % 98 % 362663 2 70 % 94 % 424924
2 70 % 94 % 327947 2 100 % 92 % 413873
Nota 47
Admite distintas soluciones.
Existen dos variables del problema que puede tomar distintos valores, el resto de las
variables siempre toman el mismo valor.
116
Resolvemos el Problema15-12-4
Tamaño del espacio de búsqueda: aprox. 272
Usando el método 1 para generar la población inicial se obtuvo
La búsqueda local resulta ser un proceso tan potente que permite en muchas ocasiones
encontrar solución aplicandolo unicamente a la población inicial, es decir, no se llega a
usar el algoritmo genético simple.
Nota 48
Siempre encuentra la misma solución.
La mayorı́a de las variables son la cadena vacia, Λ.
117
Resolvemos el Problema15-7-5
Tamaño del espacio de búsqueda: aprox. 242
Usando el método 1 para generar la población inicial se obtuvo
Nota 49
Admite distintas soluciones.
Existen dos variables del problema que puede tomar distintos valores, el resto de las
variables siempre toman el mismo valor.
118
Resolvemos el Problema25-8-3
Tamaño del espacio de búsqueda: aprox. 248
Usando el método 1 para generar la población inicial se obtuvo
Nota 50
Siempre encuentra la misma solución.
119
Resolvemos el Problema25-8-5
Tamaño del espacio de búsqueda: aprox. 248
Usando el método 1 para generar la población inicial se obtuvo
Nota 51
Siempre encuentra la misma solución.
120
Resolvemos el Problema5-15-3
Tamaño del espacio de búsqueda: aprox. 290
Usando el método 1 para generar la población inicial se obtuvo
2 5 20 % 94 % 535684 88 % 311136
2 5 70 % 96 % 299938 96 % 171128
2 5 90 % 94 % 246925 100 % 192842
2 5 100 % 94 % 317776 98 % 246269
2 5 20 % 62 % 541543 96 % 391371
2 5 70 % 94 % 415857 94 % 284990
2 5 90 % 88 % 341641 94 % 222077
2 5 100 % 92 % 316503 96 % 218227
Nota 52
Admite distintas soluciones.
121
Conclusión 3
Resumen de los mejores resultados obtenidos:
Usando el método 1
Problema Búsq. L. Mutación Exito Media Eval.
Usando el método 2
Problema Búsq. L. Mutación Exito Media Eval.
122
Hemos podido obsevar que la búsqueda local resulta decisiva en la primera etapa, cuan-
do se genera la población inicial. Antes de empezar a trabajar con el algoritmo genético,
la población inicial es sometida a un proceso de búsqueda local y, como consecuencia,
esta población experimenta una mejora considerable. Pero, una vez iniciado el algoritmo
genético, el efecto que tiene la búsqueda local sobre las nuevas poblaciones generadas no es
significativo. Por ese motivo, creemos que es importante mantener valores de probabilidad
de mutación entre 70 % y el 100 %.
Para concluir esta sección comparamos algunos de los resultados obtenidos al aplicar
el algoritmo genético simple (AGS) y el algoritmo genético con búsqueda local (AE).
Como ya sabemos que la búsqueda local 2 es mejor que la 1, tomamos como refe-
rencia los resultados obtenidos con busqueda local 2 para compararlos con los resultados
obtenidos sin búsqueda local.
Se tienen las siguientes tablas
Usando el método 1
Problema Mutación Éxito(AGS) Éxito(AE) Media Eval.(AGS) Media Eval.(AE)
123
Usando el método 2
Problema Mutación Éxito(AGS) Éxito(AE) Media Eval.(AGS) Media Eval.(AE)
Conclusión 4
La búsqueda local mejora la probabilidad de exito y reduce considerablemente el número
de evaluaciones necesarias para encontrar una solución del problema.
124
Capı́tulo 9
Experimento final
Resolvemos el Problema15-25-5
Tamaño del espacio de búsqueda: aprox. 2150
2 2 5 70 % 92 % 414500
2 2 5 80 % 98 % 384799
2 2 5 90 % 96 % 359897
2 2 5 100 % 86 % 417172
2 2 5 70 % 98 % 475580
2 2 5 80 % 96 % 424660
2 2 5 90 % 90 % 409549
2 2 5 100 % 90 % 421117
125
Mientras que con el método 1 los mejores resultados se obtienes con probabilidad
de mutación 80 % y 90 %, con el método 2 a medida que disminuye la probabilidad de
mutación mejoran los resultados, esto nos lleva a pensar en intentar resolver el problema
con menor probabilidad de mutación. Aunque según la experiencia no esperamos que haya
mejora, pues hemos establecido la probabilidad de mutación más adecuada entre el 70 %
y el 100 %.
Nota 53
Admite distintas soluciones.
Existen dos variables del problema que puede tomar distintos valores, el resto de las
variables siempre toman el mismo valor.
Resolvemos el Problema25-23-4
Tamaño del espacio de búsqueda: aprox. 2138
2 2 5 70 % 68 % 375905
2 2 5 80 % 78 % 549016
2 2 5 90 % 78 % 593530
2 2 5 100 % 76 % 601812
2 2 5 70 % 74 % 530816
2 2 5 80 % 72 % 690505
2 2 5 90 % 70 % 663918
2 2 5 100 % 70 % 519235
Nota 54
Siempre encuentra la misma solución.
126
Para finalizar, en la siguiente tabla se comparan los resultados obtenidos al resolver
algunos problemas en distintos espacios de búsqueda con el algoritmo genético simple
(AGS) y con el A.E. Búsqueda Local (AE).
Conclusión 5
El algoritmo evolutivo que proponemos para resolver los problemas l SW ES usa los o-
peradores genéticos definidos en el capı́tulo 5 y aplica búqueda local 2 a cada una de las
poblaciones generadas.
127
Apéndice A
// //////////////////////////////////////////////////////////// //
// / / //
// / Un Algoritmo Genético para Resolver el problema l_SWES / //
// / / //
// //////////////////////////////////////////////////////////// //
fstream fsol("solucion.dat",ios::out);
128
void Genera_PobIni(vector<vector<vector<int> > > &PobIni,
vector<vector<int> > &lReVsol,
vector<vector<vector<int> > > &AuxPob,
vector<vector<int> > &AuxlRsol,
const int &TamPob, const int &m_var,
const int &lMaxVsol, const int &Metodo);
129
vector<vector<int> > &AuxPob,
vector<int> &lReVsolIzq, vector<int> &lReVsolDer,
vector<int> &AuxlRsol, vector<vector<int> > &PobIniIzq,
vector<vector<int> > &PobIniDer);
int main(void)
{
string problema;
int TamPob, lMaxVsol, NMaxIter, ProMut, Metodo;
int n_ec, m_var;
int haysol, muto;
int MejorFit, Sumfit, PadreIzq, PadreDer;
int i, j, k, iter;
vector<int> l_ec;
vector<vector<int> > Sist;
vector<vector<vector<int> > > PobIni;
vector<vector<int> > lReVsol;
vector<vector<vector<int> > > AuxPob; //vector auxiliar
vector<vector<int> > AuxlRsol; //vector auxiliar
vector<int> fitness;
vector<int> AuxIzq; //Sólo se utiliza en la función evalua
vector<int> AuxDer; //Sólo se utiliaza en la función evalua
randomize();
130
Simplifica(n_ec, l_ec, Sist);
fitness.resize(TamPob);
haysol= 0;
131
// * Cruce *
Cruce(m_var, lMaxVsol, AuxPob[k], lReVsol[PadreIzq], lReVsol[PadreDer],
AuxlRsol[k], PobIni[PadreIzq], PobIni[PadreDer]);
// * Mutación *
if(ProMut!=0)
{
muto = rand() %100;
if(muto< ProMut) // * Muto la solusión k_esima *
Mutacion(m_var, lMaxVsol, muto, AuxPob[k], AuxlRsol[k]);
}//fin if(ProMut!=0)
}//fin for(k)
fitness[0]= MejorFit;
for(k= 1; k<TamPob; k++)
{
Evalua(n_ec, l_ec, Sist, lReVsol[k],PobIni[k],AuxIzq,
AuxDer, fitness[k], haysol);
}//fin for(k)
132
for(k= 0; k< TamPob; k++) { for(i= 0; i< m_var; i++) {
for(j= 0;j< lMaxVsol; j++) fsol<<PobIni[k][i][j]; fsol<<" ";}//fin
fsol<<endl; fsol<<"Con fitness "<<fitness[k]<<endl; }//fin for(k)
}//fin for(iter)
if(haysol == 1)
{
fsol<<"El programa ha encontrado solucion con una poblacion de "<<endl;
fsol<<"tama~
no "<<TamPob<<" y longitud máxima de las variables "<<endl;
fsol<<"igual a "<<lMaxVsol<<" ."<<endl;
fsol<<"La probabilidad de mutacion utiliza fue "<<ProMut<<" ."<<endl;
fsol<<"La solucion propuesta tras "<<iter<<" iteraciones es: "<<endl;
k=0;
while(fitness[k] !=0) k= k + 1;
for(i= 0; i< m_var; i++)
{
fsol<<"x"<<i<<" = ";
if(lReVsol[k][i] == 0) fsol<<"la palabra vacia."<<endl;
else
{
for(j= 0;j< lReVsol[k][i]; j++) fsol<<PobIni[k][i][j]<<" ";
fsol<<endl;
}//fin else
}//fin for(i)
}//fin if(haysol==1)
if(haysol == 0)
{
fsol<<"El programa NO ha encontrado solucion."<<endl;
fsol<<"Los datos propuestos fueron: "<<endl;
fsol<<"Tama~
no de poblacion igual a "<<TamPob<<" ."<<endl;
133
fsol<<"Longitud máxima de las variables igual a "<<lMaxVsol<<" ."<<endl;
fsol<<"La probabilidad de mutacion utiliza fue "<<ProMut<<" ."<<endl;
}//fin if(haysol==0)
}//fin programa
134
do{
cout<<"Numero maximo de iteraciones que desea realizar : "<<endl;
cin>>NMaxIter;
}while(NMaxIter<0);
do{
cout<<"Cual es la probabilidad de mutacion que desea utilizar?"<<endl;
cout<<"Indique esta probabilidad en porcentaje de 100"<<endl;
cin>> ProMut;
cout<<"Recuerde que se trata de un valor entero entre cero y 100."<<endl;
cout<<endl<<endl;
}while(ProMut>100 || ProMut<0);
cout<<"Eliga el metodo que desea utilizar para generar la poblacion"<<endl;
cout<<"inicial."<<endl<<endl;
do{
cout<<"Pulse 1 si quiere fijar la longitud real de la variable y "<<endl;
cout<<"luego generar la variable con simbolos del alfabeto {0,1}."<<endl;
cout<<endl;
cout<<"Pulse 2 si quiere generar la variable en {0,1,2} y luego "<<endl;
cout<<"calcular la longitud real de la variable."<<endl<<endl;
cout<<"Pulse 3 si desea recibir mas informacion sobre los metodos"<<endl;
cout<<"usados en la generacion de la poblacion inicial."<<endl<<endl;
cin>> Metodo;
if(Metodo == 3)
{
cout<<"El metodo-1 elige la longitud real de la variable que va a"<<endl;
cout<<"generar entre cero (que corresponde a la palabra vacia) y "<<endl;
cout<<"la longitud maxima propuesta. Una vez fijada la longitud, "<<endl;
cout<<"genera la variable como una cadena de ceros y unos. "<<endl<<endl;
cout<<"El metodo-2 genera la variable como una cadena de simbolos"<<endl;
cout<<"pertenecientes al conjunto {0,1,2} de longitud la longitud"<<endl;
cout<<"maxima propuesta. Despues reordena esta cadena, colocando"<<endl;
cout<<"todos los doses al final de la misma (pues representan el "<<endl;
135
cout<<"simbolo vacio). Finalmente, calcula el numero de ceros y "<<endl;
cout<<"unos que aparecen en la cadena y que corresponde a la "<<endl;
cout<<"longitud real de la variable generada."<<endl<<endl;
cout<<"Que metodo desea utilizar?"<<endl;
cin>> Metodo;
}//fin if
}while(Metodo<1 || Metodo>2);
}//fin Pedir_Datos
136
}//fin while
if(coincidencia!=0)
{
l_ec[i]= l_ec[i]-coincidencia;
for(int j= 0; j< l_ec[i]; j++)
Sist[i][j]= Sist[i][j+coincidencia];
Sist[i].resize(l_ec[i]);
l_ec[i+1]= l_ec[i+1]-coincidencia;
for(int j= 0; j< l_ec[i+1]; j++)
Sist[i+1][j]= Sist[i+1][j+coincidencia];
Sist[i+1].resize(l_ec[i+1]);
}//fin if
coincidencia= 0; columnas= 1; minimo= min (l_ec[i],l_ec[i+1]);
while(columnas<= minimo &&
Sist[i][l_ec[i]-columnas] == Sist[i+1][l_ec[i+1]-columnas])
{
coincidencia= coincidencia +1;
columnas= columnas +1;
}//fin while
if(coincidencia!=0)
{
l_ec[i]= l_ec[i] -coincidencia; Sist[i].resize(l_ec[i]);
l_ec[i+1]= l_ec[i+1]-coincidencia; Sist[i+1].resize(l_ec[i+1]);
}//fin if
}//fin for(i)
}//fin Simplifica
137
{
int longitud;
PobIni.resize(TamPob);
lReVsol.resize(TamPob);
AuxPob.resize(TamPob); //vector auxiliar
AuxlRsol.resize(TamPob); //vector auxiliar
for(int k= 0; k< TamPob; k++)
{
PobIni[k].resize(m_var);
lReVsol[k].resize(m_var);
AuxPob[k].resize(m_var); //vector auxiliar
AuxlRsol[k].resize(m_var); //vector auxiliar
for(int i= 0; i< m_var; i++)
{
PobIni[k][i].resize(lMaxVsol);
if(Metodo == 1)
{
longitud= lMaxVsol +1;
lReVsol[k][i]= rand() % longitud;
for(int j= 0; j< lReVsol[k][i]; j++) PobIni[k][i][j]= rand() % 2;
for(int j= lReVsol[k][i]; j< lMaxVsol; j++) PobIni[k][i][j]= 2;
}//fin if(Metodo==1)
if(Metodo == 2)
{
lReVsol[k][i]= lMaxVsol;
for(int j= 0; j< lMaxVsol; j++) PobIni[k][i][j] = rand() % 3;
reordeno(lMaxVsol, PobIni[k][i],lReVsol[k][i]);
}//fin if(Metodo==2)
}//fin for(i)
}//fin for(k)
}//fin Genera_PobIni
138
void reordeno(const int &l, vector<int> &v,int &lReVsol)
{
// Reordeno la variable y calculo la longitud real de la misma
int columna;
for(int j= 0; j< l-1; j++)
if(v[j] == 2)
{
columna= j+1;
while(v[columna] == 2 && columna< l-1) columna = columna +1;
if(v[columna]!= 2)
{
v[j]= v[columna];
v[columna]= 2;
}//fin if
}//if(v[j] == 2)
for(int j= 0; j< l; j++)
if(v[j] == 2) lReVsol= lReVsol -1;
}//fin reordeno
139
AuxDer.resize(lAuxDer);
sustituyo(Sist[2*i], lAuxIzq, AuxIzq, lReVsol, PobIni);
sustituyo(Sist[2*i+1], lAuxDer, AuxDer, lReVsol, PobIni);
minimo = min(lAuxIzq,lAuxDer);
for(int j= 0;j< minimo; j++)
if(AuxIzq[j] != AuxDer[j]) coincidencia= coincidencia+1;
coincidencia= coincidencia + abs(lAuxIzq-lAuxDer);
}//fin for(i)
fitness= coincidencia;
if(fitness == 0) haysol= 1;
}//fin Evaluacion
140
{
lAux=lAux+lVsol[variable]-1;
Aux.resize(lAux);
for(l= 0; l< lVsol[variable]; l++) Aux[j+l] = PobIni[variable][l];
auxiliar = auxiliar - lVsol[variable] + 1;
j=j+lVsol[variable]-1;
}
}//fin else
}//fin sustituyo
141
}//fin if(minimo == 0)
}//fin if(MejorFit == fitness[k])
}//fin for(k)
for(int i= 0; i< m_var; i++)
{
AuxPob[i].resize(lMaxVsol);
AuxlRsol[i]= lReVsol[variable][i];
for(int j= 0; j< lMaxVsol; j++) AuxPob[i][j]= PobIni[variable][i][j];
}//fin for(i)
}//fin Mejor_Sol
142
}
else
{
limInf = limInf + fitness[i];
limSup = limSup + fitness[i+1];
}
}
}//fin eligo_padre
143
for(int j= 0; j< columna; j++)
{
AuxPob[i][minimo+j]= PobIniDer[i][minimo+j];
if(AuxPob[i][minimo+j]!= 2) AuxlRsol[i]= AuxlRsol[i] +1;
}//fin for(j)
for(int j= columna; j< longitud; j++) AuxPob[i][minimo+j]= 2;
}//fin if
else
{
for(int j= 0; j< columna; j++)
{
AuxPob[i][minimo+j]= PobIniIzq[i][minimo+j];
if(AuxPob[i][minimo+j]!= 2) AuxlRsol[i] = AuxlRsol[i] +1;
}//fin for(j)
for(int j= columna; j< longitud; j++) AuxPob[i][minimo+j] = 2;
}//fin else
}//fin for(i)
}//fin cruce
144
Apéndice B
// //////////////////////////////////////////////////////////// //
// / / //
// / Un Algoritmo que Genera Sistemas de ‘‘Word Ecuations’’ / //
// / / //
// //////////////////////////////////////////////////////////// //
145
void Def_variable(const int &n_ec, const int &m_var,
const int &lmax_var, vector<int> &l_ec,
vector<vector<int> > &Ec, vector<int> &l_var,
vector<vector<int> > &Var, int &contador);
int main(void)
{
string sistema;
string soluciones;
int i, j, k, l, m;
int probabilidad;
int n_ec, lmax_ec, m_var, lmax_var;
int indice, posicion, auxiliar, contador, coincidencia, coinciden;
146
int SumaLong;
randomize();
fstream fprob(sistema.c_str(),ios::out);
fstream fsol(soluciones.c_str(),ios::out);
Ec.resize(2*n_ec);
Var.resize(m_var);
l_ec.resize(2*n_ec);
l_var.resize(m_var);
147
recorro_ec(contador, k, l_ec[i], lmax_var, l_var[k],
Var[k], Ec[i]);
if(contador <= 0)
{
fprob<<"El programa ha fracasado."<<endl;
fprob<<"No hemos podido generar un sistema de"<<endl;
fprob<<n_ec<<" ecuaciones con "<<m_var<<" variables."<<endl;
indice = k;
for(l= indice; l< m_var; l++)
{
l_var[l]= 0;
Var[l].resize(l_var[l]);
}//fin for(l)
}//fin if
if(contador >= 0)
{
fprob<<n_ec<<endl;
fprob<<m_var<<endl;
for(i= 0; i< 2*n_ec; i++)
{
fprob<<l_ec[i]<<" ";
for(j= 0; j<l_ec[i]; j++) fprob<< Ec[i][j]<<" ";
fprob<<endl;
}//fin for(i)
fsol<<"las soluciones son :"<<endl;
148
for(i= 0; i< m_var; i++)
{
if(l_var[i] == 0) fsol<<"2";
else
for(j= 0; j< l_var[i]; j++) fsol<<Var[i][j]<<" ";
fsol<<endl;
}//fin for(i)
}//fin if(contador >= 0)
}//fin programa
149
cout<<"Indique el numero de variables(>0): "<<endl;
cin>> m_var;
cout<<endl;
}while ( m_var <= 0 );
do{
cout<<"Indique la longitud maxima(>0) de las variables: "<<endl;
cin>> lmax_var;
cout<<endl;
}while ( lmax_var <= 0 );
}//fin void Pedir_Datos
150
limSup = sum;
l_ec = 0;
for(int j= 0; j< lmax_ec && l_ec == 0; j++)
if(limInf<= aux && aux< limSup) l_ec = j +1;
else
{
sum= sum +1;
limInf= limSup;
limSup= limSup +sum;
}//fin else
}//fin void ruleta
151
l_var[k] = rand() % auxiliar;
Var[k].resize(l_var[k]);
if(l_var[k]==0) insertar( k, posicion, l_ec[indice], Ec[indice]);
else
{
auxiliar = 0;
for(int j= posicion; j< posicion +l_var[k]; j++)
{
Var[k][auxiliar]= Ec[indice][j];
auxiliar= auxiliar +1;
}//fin for(j)
sustituir(k, posicion, l_ec[indice], l_var[k], Ec[indice]);
}//else
contador = contador -l_var[k];
}//fin for(k)
}//fin void Def_variable
152
}// fin sustituir
153
if(Ec[l] != Var[auxiliar]) coincidencia = 0;
else auxiliar = auxiliar + 1;
}//fin else
if(coincidencia == 1)
{
// * Cambio con probabilidad l_var[k]/lmax_var *
probabilidad = rand() % lmax_var;
probabilidad = probabilidad + 1;
if(probabilidad <= l_var)
{
sustituir( k, posicion, l_ec, l_var, Ec);
contador = contador - l_var;
}//fin if(probabilidad <= l_var)
}//fin if(coincidencia == 1)
}//fin else
}//fin recorro_ec
154
cont_der = 0;
for(int j= 0; j< l_ecder; j++)
if(Ecder[j]!=0 && Ecder[j]!=1) cont_der = cont_der +1;
if(cont_der == 0)
for(int k= 0; k< m_var && contador> 0; k++)
recorro_ec(cont_der, k, l_ecder, lmax_var, l_var[k],Var[k], Ecder);
if(l_ecizq == l_ecder)
{
coinciden= 1;
for(int j= 0; j< l_ecizq && coinciden == 1; j++)
if(Ecizq[j]!=Ecder[j]) coinciden=0;
if(coinciden == 1) // * defino una nueva ecuacion *
{
Genero_Cadenas(SumaLong,lmax_ec,Ecizq,Ecder,l_ecizq,l_ecder);
contador= 2*l_ecizq;
for(int k= 0; k< m_var && contador> 0; k++)
{
recorro_ec(contador, k, l_ecizq, lmax_var, l_var[k],
Var[k], Ecizq);
recorro_ec(contador, k, l_ecder, lmax_var, l_var[k],
Var[k], Ecder);
}//fin for(k)
}//fin if(coinciden == 1)
}//fin if(l_ecizq == l_ecder)
155
for(int i= 0; i< 2*n_ec - 1; i+= 2)
{
coincidencia= 0; columnas= 0; minimo= min (l_ec[i],l_ec[i+1]);
while(Ec[i][columnas]== Ec[i+1][columnas] && columnas< minimo)
{
coincidencia= coincidencia +1; columnas= columnas +1;
}//fin while
if(coincidencia!=0)
{
l_ec[i]= l_ec[i]-coincidencia;
for(int j= 0; j< l_ec[i]; j++)
Ec[i][j]= Ec[i][j+coincidencia];
Ec[i].resize(l_ec[i]);
l_ec[i+1]= l_ec[i+1]-coincidencia;
for(int j= 0; j< l_ec[i+1]; j++)
Ec[i+1][j]= Ec[i+1][j+coincidencia];
Ec[i+1].resize(l_ec[i+1]);
}//fin if
coincidencia= 0; columnas= 1; minimo= min (l_ec[i],l_ec[i+1]);
while(columnas<= minimo &&
Ec[i][l_ec[i]-columnas] == Ec[i+1][l_ec[i+1]-columnas])
{
coincidencia= coincidencia +1;
columnas= columnas +1;
}//fin while
if(coincidencia!=0)
{
l_ec[i]= l_ec[i] -coincidencia; Ec[i].resize(l_ec[i]);
l_ec[i+1]= l_ec[i+1]-coincidencia; Ec[i+1].resize(l_ec[i+1]);
}//fin if
}//fin for(i)
}//fin Simplifica
156
Apéndice C
x1 x13 x4 x7 = x1 x2 x11 x6
x13 x4 x4 x1 x1 x1 x11 = x1 x4 1x6 x1 x13 x4
x1 x6 x5 x1 = 0x1 x1 x10
x1 1 = x11
x11 x8 10x6 x9 x12 x13 = 0x2 1x4 x1 0x1 x15 x13
x1 x4 x1 0x5 0x2 x1 x6 = x11 x6 1x4 x6 x1 x12 x13
1x1 x4 x1 1x4 0 = x2 x8 1x1 x3 x4 x12 0
1x2 x13 x6 x1 10 = x4 0x1 x8 0x2 0x4 x13
0x4 x3 10x2 x6 = x8 x11 x8 x3 1x1 x12 0x1
x5 x6 x1 x1 x13 = x2 x5 x14 x7 0
157
C.2. El problema 10-15-5
158
C.4. El problema 10-5-1
x3 = Λ x4 = Λ
x5 = 1 x6 = Λ x7 = 0
x4 1x4 = x6 1
x4 0x4 010x4 1x4 1x4 = x5 x4 0x4 1011
0x5 0 = x5 0x4 0x6
1x6 = x4 1
x4 x6 111 = 111x4
x7 1x4 = x5 1
x6 11x5 = 110
x4 = Λ
x6 0x5 x5 0x4 x6 00 = 0x7 x7 x7 x5 x5
x3 x7 = x6 100
159
La solución propuesta es: x3 = 10 x4 = Λ
x5 = 0 x6 = Λ x7 = 0
160
C.8. El problema 12-6-4
x5 01x8 = x5 0x7 10
111 = 1x7 11
x4 1x8 101x8 1x8 = 1010x4 x7 10x4 1x8
x7 11x5 00 = 11x5 00
x8 11x3 10 = 0x4 11x3 x4 10
101x8 0110x4 11 = 1010011011
x8 0x4 1 = 0x8 1
1x6 x7 01x4 100 = 1x6 x4 x7 0x6
x7 x8 11x7 0x3 1 = 0110x3 1
x4 x6 1 = x6 1
0x4 x7 10x4 x7 1001 = 01x4 01001
000x3 = 0x8 0x3
11x5 x13 x3 x9 x12 x3 x10 x13 = 1x6 11x5 0x9 x12 1x9 0
0x7 0000 = 00x3 x9 000
1x13 0x3 x12 0x12 x13 x5 11 = x10 1x5 x6 x12 x8 011x9 0x12 x3 x5 x12
x4 x4 0 = x5 0x6 100x5 100
x6 11x4 11x3 x4 x3 00x12 = x6 1x9 x12 x4 1x12 0x12 0x5 x7 x8
x6 x10 1x13 0x4 x7 0x8 = x6 x10 x12 x3 x10 x14 10x3 x14 0x4 x5 0x9 0x3 0x5 x7 1
x9 10x12 x5 x13 x4 = x7 x13 1x12 0x4
x6 x5 0x4 x14 0x3 x12 = x3 x8 001
0x4 x7 1x9 1x6 0x5 0 = x14 00x6 10x3 1x1 41x9 00
x5 0x3 01x3 0 = 0x3 x4
x4 1x6 1x3 x14 01x6 x7 1x10 x12 = x4 1x7 1x14 0x12 x12 1
161
x5 0x11 00 = 011x7 x14 1x6 0x5 00
x10 011 = 0x12 x5 1
1x9 1x13 0x14 11 = 1x10 x141x3 x13 x3 0x14 1x9 1
x12 x12 x4 x5 0x3 x14 1x7 x12 x4 = x12 10x12 00x9 1x3 1x4
162
C.11. El problema 15-7-5
163
C.12. El problema 25-23-4
x9 x13 x7 x14 x9 x3 0x7 x5 x13 x19 x25 = x9 x7 x6 x23 0x9 x5 x25 x5 x9 x4 1x9
x22 x7 x7 x3 x13 x3 x9 x6 x9 x13 x4 x22 = x22 x4 x4 x16 x21 x3 x9 x13 x4 x18 x6 0
0x7 0x14 0x21 x4 0 = x24 010x15 x10 x25 x7 x13 x5 x22
x5 x10 10x4 x7 x22 x12 x3 = x13 01x4 x20 x22 x9
x22 1x24 x25 x3 x16 x3 x9 = x9 x14 0x3 x25 x3 x3
1x4 x3 = x4 x4 x3
x21 x9 x4 x14 x3 x7 x4 x3 x4 x7 x9 = x10 x23 1x18 x12 x3 x4 x19 1x3 x6 x22
x6 0x9 = 1x15 x22 x9
x18 x22 x18 x13 = x16 x10 x25 1
1x10 x18 x3 0x6 x24 0x10 x19 x21 x3 = x5 1x3 x3 x4 x4 x9 x13 x22 0
1x9 1 = x23 1x17
x7 1x22 x14 x25 1x16 x15 x3 x15 = x8 x7 x18 x10 x15 x3 x4 0x9 x4
x7 x24 00x5 x4 x22 x6 x9 x8 x14 x16 = x7 x10 0x22 x13 0x8 x7 x4 x10 0x5 x13 x9 0
x3 x3 x6 x4 0x14 x5 x15 = x3 x11 x4 0x6
x6 x7 x4 = x4 x4 x4 x21
x6 x9 x9 x18 x4 x7 x6 x4 1x4 x5 x14 x4 x25 = x14 x4 x3 0x5 1x5 x7 x4 x5 x7 x5 x21 x13 x4 x4 x21 0
x15 x4 x4 = x5 x10 x14 x5 x7 x13
x5 1x5 x9 x21 = x15 x25 x7
x21 = x15
x21 x3 x6 x25 x7 = x7 x18 x9 x13 x10 x7 x17
x7 x4 x9 x4 10x19 x15 x16 x15 x4 x18 = x13 x4 0x4 x13 0x4 00x7 x5 x13 0
x7 x5 0x14 x4 x6 = x24 x5 x24 1x22 x6 x13 x4
0x7 x9 x7 x18 x4 0x6 x5 x7 x5 x7 x5 x7 x6 = 0x7 x9 x21 x25 1x18 x15 x5 x6 x12 x4 x14
x4 x3 x5 x13 x10 x12 x12 x3 x3 0x7 = x7 x9 x10 0x7 x4 x4 x6 x16 x25 x9 x22 x14
x21 x22 x15 = x4 x9 x13
164
C.13. El problema 25-8-3
x7 0 = x6 x8 x5 00
1x3 x3 x10 x7 x4 x3 x9 x9 = 1x8 x3 1x3 x3 x4 0x3 x3
x9 = 0
11x4 x8 x3 x6 1x8 x5 0 = x6 x10 x10 x3 x10 x10 x3 x3 x10 0x6 0
x3 x5 x9 1x3 x3 0 = x3 x8 1x7 x8
x10 1x10 x3 x10 x10 x3 x7 x5 x8 x3 x10 x8 = x10 11x4 x9 0x3 x3 x8 1x3
1x4 01x8 x9 x3 x3 = 1x4 01x3 x8 x3 x9
1x6 1x3 x3 x10 x8 = 1x10 x7 1x3
x5 1x8 = x6 1x3
x6 x8 x6 0x4 x4 x10 x10 x4 1 = 0x3 x3 1x6 1x4 x10 1x5 x4 x10
x7 x6 10x5 1x3 1x6 x8 x3 0x3 x9 1x9 = x9 x9 x10 x9 101x3 x3 x5 x7 0x10 x9
x9 x10 x9 x3 1x8 = x3 1x3 x8 1x3
11x4 0x7 x3 0x10 0 = x10 1x4 0x3 0x7 x10 x3
11x3 x8 x10 = 11x8 x3 1
1x3 01x3 = x10 x8 x3 x10 x5 0
0x8 0x10 x4 x10 x7 x10 x9 1 = 0x9 x3 1x4 x10 x7 1x3 1
x8 x3 11x3 11x10 x10 = x8 x3 x10 x5 x10 x4 1x5 x6 1
x1 0x8 x7 = x10 x3 x7
x10 x10 x9 0x3 = 1x5 x6 x10 0x7
x9 = 0
x4 1x7 1 = x3 x10 11x7 1
x10 x8 x3 x5 0x8 x3 x3 x4 = x10 x7 0x3 x9 x9 x3 x10 x10
x7 1x4 1 = x3 x3 1x4 x10
x8 x7 0x5 0 = 0x5 x6 x9 x3 x6 x7
101x5 x7 10x9 x3 = 1x3 1x7 1x5 0x5 0x8
165
C.14. El problema 25-8-5
1x3 x5 0 = x6 x9 0x10
x4 01000x4 000x4 01110 = 0x10 00x9 11x4 0
1x8 = x6 0
11x8 1x3 0 = 1x6 01x3 0
1x9 0x4 100 = 1000x4 1x4 0x10
x8 110x3 11 = x8 x4 110x3 11
x7 111x6 = x7 1111x4 110
00x10 x4 001 = 00100001
0101x4 x6 01x4 1x4 1 = 0101x6 0111
x10 00 = 10000
001x4 0 = 0010
0x6 0x6 1000 = 0x6 01x7 00
1x4 10x10 x10 111 = x7 x4 0x10 111
x4 1 = 1
x9 000 = 000x4 1x4 000
1011110x5 1 = 101x6 x5 1
110x4 101001 = x7 1001
11011111x6 = 110x4 11111111x4 0
x4 1x7 00000 = x6 10x4 00000
111111x4 10 = 1111x6
x10 x4 001x3 011 = x4 10x4 x9 x3 011
00001x3 1x4 11 = 00001x3 111
x4 000 = 000
x4 0x10 00x9 x9 = 0x10 000x4 001x9
0001x4 00 = 000x10
166
C.15. El problema 5-15-3
10 = x3 x4
x5 1 = 0x3 1x3
x3 011001 = 011001x3
x3 0 = x5
x5 = x3 0
x3 = Λ
x4 = 10
x5 = 0
167
Apéndice D
// //////////////////////////////////////////////////////////// //
// / / //
// / Un Algoritmo Evolutivo para Resolver el problema l_SWES / //
// / / //
// / (SÓLO MUTACIÓN) / //
// / / //
// //////////////////////////////////////////////////////////// //
fstream fsol;
168
void Simplifica(const int &n_ec, vector<int> &l_ec,
vector<vector<int> > &Sist);
int main()
{
string problema;
int lMaxVsol, NMaxIter, Metodo, Npruebas;
int n_ec, m_var;
int fitness, AuxFit, haysol;
int i, j, k, iter, npru;
vector<int> l_ec;
169
vector<vector<int> > Sist;
vector<vector<int> > PobIni;
vector<int> lReVsol;
vector<vector<int> > AuxPob; //vector auxiliar
vector<int> AuxlRsol; //vector auxiliar
vector<int> AuxIzq; //Sólo se utiliza en la función evalua
vector<int> AuxDer; //Sólo se utiliaza en la función evalua
randomize();
PobIni.resize(m_var);
lReVsol.resize(m_var);
AuxPob.resize(m_var); //vector auxiliar
AuxlRsol.resize(m_var); //vector auxiliar
haysol= 0;
170
for(i= 0; i< m_var; i++)
{AuxlRsol[i]= lReVsol[i];
for(j= 0;j< lMaxVsol; j++) AuxPob[i][j]= PobIni[i][j];
}//fin for(i)
if(haysol == 1)
{
fsol<<"El programa ha encontrado solucion con longitud máxima "<<endl;
fsol<<"de las variables igual a "<<lMaxVsol<<" ."<<endl;
171
fsol<<"Para generar la poblacion inicial se uso el metodo_"<<Metodo<<endl;
fsol<<"La solucion propuesta tras "<<iter<<" iteraciones es: "<<endl;
for(i= 0; i< m_var; i++)
{
fsol<<"x"<<i<<" = ";
if(lReVsol[i] == 0) fsol<<"la palabra vacia."<<endl;
else
{for(j= 0;j< lReVsol[i]; j++) fsol<<PobIni[i][j]<<" ";
fsol<<endl;}//fin else
}//fin for(i)
}//fin if(haysol==1)
if(haysol == 0)
{
fsol<<"El programa NO ha encontrado solucion."<<endl;
fsol<<"Los datos propuestos fueron: "<<endl;
fsol<<"Longitud máxima de las variables igual a "<<lMaxVsol<<" ."<<endl;
fsol<<"Para generar la población inicial se uso el metodo_"<<Metodo<<endl;
fsol<<"La candidata a solución generada tras "<<iter<<" iteraciones es:"<<endl;
for(i= 0; i< m_var; i++)
{for(j= 0;j< lMaxVsol; j++) fsol<<PobIni[i][j];
fsol<<" ";}//fin for(i)
fsol<<" ";
fsol<<"Con fitness "<<fitness<<endl;
}//fin if(haysol==0)
}//fin programa
172
do{
cout<<"Escriba la longitud maxima(>0) de las candidatas a solucion:"<<endl;
cin>> lMaxVsol;
}while(lMaxVsol<=0);
do{
cout<<"Numero maximo de iteraciones que desea realizar : "<<endl;
cin>>NMaxIter;
}while(NMaxIter<0);
cout<<"Eliga el metodo que desea utilizar para generar la poblacion"<<endl;
cout<<"inicial."<<endl<<endl;
do{
cout<<"Pulse 1 si quiere fijar la longitud real de la variable y "<<endl;
cout<<"luego generar la variable con simbolos del alfabeto {0,1}."<<endl;
cout<<endl;
cout<<"Pulse 2 si quiere generar la variable en {0,1,2} y luego "<<endl;
cout<<"calcular la longitud real de la variable."<<endl<<endl;
cout<<"Pulse 3 si desea recibir mas informacion sobre los metodos"<<endl;
cout<<"usados en la generacion de la poblacion inicial."<<endl<<endl;
cin>> Metodo;
if(Metodo == 3)
{
cout<<"El metodo-1 elige la longitud real de la variable que va a"<<endl;
cout<<"generar entre cero (que corresponde a la palabra vacia) y "<<endl;
cout<<"la longitud maxima propuesta. Una vez fijada la longitud, "<<endl;
cout<<"genera la variable como una cadena de ceros y unos. "<<endl<<endl;
cout<<"El metodo-2 genera la variable como una cadena de simbolos"<<endl;
cout<<"pertenecientes al conjunto {0,1,2} de longitud la longitud"<<endl;
cout<<"maxima propuesta. Despues reordena esta cadena, colocando"<<endl;
cout<<"todos los doses al final de la misma (pues representan el "<<endl;
cout<<"simbolo vacio). Finalmente, calcula el numero de ceros y "<<endl;
cout<<"unos que aparecen en la cadena y que corresponde a la "<<endl;
cout<<"longitud real de la variable generada."<<endl<<endl;
173
cout<<"Que metodo desea utilizar?"<<endl;
cin>> Metodo;
}//fin if
}while(Metodo<1 || Metodo>2);
}//fin Pedir_Datos
174
Sist[i][j]= Sist[i][j+coincidencia];
Sist[i].resize(l_ec[i]);
l_ec[i+1]= l_ec[i+1]-coincidencia;
for(int j= 0; j< l_ec[i+1]; j++)
Sist[i+1][j]= Sist[i+1][j+coincidencia];
Sist[i+1].resize(l_ec[i+1]);
}//fin if
coincidencia= 0; columnas= 1; minimo= min (l_ec[i],l_ec[i+1]);
while(columnas<= minimo &&
Sist[i][l_ec[i]-columnas] == Sist[i+1][l_ec[i+1]-columnas])
{coincidencia= coincidencia +1;
columnas= columnas +1;
}//fin while
if(coincidencia!=0)
{l_ec[i]= l_ec[i] -coincidencia; Sist[i].resize(l_ec[i]);
l_ec[i+1]= l_ec[i+1]-coincidencia; Sist[i+1].resize(l_ec[i+1]);
}//fin if
}//fin for(i)
}//fin Simplifica
175
for(int j= 0; j< lReVsol[i]; j++) PobIni[i][j]= rand() % 2;
for(int j= lReVsol[i]; j< lMaxVsol; j++) PobIni[i][j]= 2;
}//fin if(Metodo==1)
if(Metodo == 2)
{lReVsol[i]= lMaxVsol;
for(int j= 0; j< lMaxVsol; j++) PobIni[i][j] = rand() % 3;
reordeno(lMaxVsol, PobIni[i], lReVsol[i]);
}//fin if(Metodo==2)
}//fin for(i)
}//fin Genera_PobIni
176
if(fitness == 0) haysol= 1;
}//fin Evaluacion
177
int muto;
for(int i= 0; i< m_var; i++)
{
for(int j= 0; j< lMaxVsol; j++)
{muto= rand() % lMaxVsol;
if(muto == 0) AuxPob[i][j]= rand() % 3;}//fin for (j)
AuxlRsol[i]= lMaxVsol;
reordeno(lMaxVsol, AuxPob[i],AuxlRsol[i]);
}//fin for(i)
}//fin Mutación
178
Apéndice E
// //////////////////////////////////////////////////////////// //
// / / //
// / Un Algoritmo Evolutivo para Resolver el problema l_SWES / //
// / / //
// / (BÚSQUEDA LOCAL) / //
// / / //
// //////////////////////////////////////////////////////////// //
fstream fsol("solucion.dat",ios::out);
179
void Simplifica(const int &n_ec, vector<int> &l_ec,
vector<vector<int> > &Sist);
180
vector<vector<int> > &AuxPob,
vector<int> &lReVsolIzq, vector<int> &lReVsolDer,
vector<int> &AuxlRsol, vector<vector<int> > &PobIniIzq,
vector<vector<int> > &PobIniDer);
int main(void)
{
string problema;
int TamPob, lMaxVsol, NMaxIter, ProMut, Metodo, Busqueda;
int n_ec, m_var;
int haysol, muto;
int MejorFit, Sumfit, PadreIzq, PadreDer;
int i, j, k, iter;
int cont_uno, cont_dos;
181
int prueba; prueba=0;
vector<int> l_ec;
vector<vector<int> > Sist;
vector<vector<vector<int> > > PobIni;
vector<vector<int> > lReVsol;
vector<vector<vector<int> > > AuxPob; //vector auxiliar
vector<vector<int> > AuxlRsol; //vector auxiliar
vector<int> fitness;
vector<int> AuxIzq; //Sólo se utiliza en la función evalua
vector<int> AuxDer; //Sólo se utiliaza en la función evalua
cont_uno = 0; cont_dos = 0;
randomize();
Genera_PobIni(PobIni,lReVsol,AuxPob,AuxlRsol,TamPob,m_var,lMaxVsol,Metodo);
fitness.resize(TamPob);
haysol= 0;
182
fsol<<"La poblacion inicial generada es: "<<endl; for(k= 0;
k<TamPob; k++) { for(i= 0; i< m_var; i++) { for(j= 0;j< lMaxVsol;
j++) fsol<<PobIni[k][i][j]; fsol<<" "; }//fin for(i) fsol<<" ";
fsol<<"Con fitness "<<fitness[k]<<endl; }//fin for(k)
if(Busqueda != 0)
for(k= 0; k<TamPob; k++)
if(Busqueda == 1)
Busqueda_loc_A(m_var, lReVsol[k], lMaxVsol, n_ec, l_ec, Sist,
AuxIzq, AuxDer, PobIni[k], fitness[k],
haysol, cont_uno, cont_dos, prueba);
else
Busqueda_loc_B(m_var, lReVsol[k], lMaxVsol, n_ec, l_ec, Sist,
AuxIzq, AuxDer, PobIni[k], fitness[k],
haysol, cont_uno,prueba);
183
PadreIzq = rand() % Sumfit;
eligo_padre(TamPob, PadreIzq, fitness);
PadreDer = rand() % Sumfit;
eligo_padre(TamPob, PadreDer, fitness);
// * Cruce *
Cruce(m_var, lMaxVsol, AuxPob[k], lReVsol[PadreIzq], lReVsol[PadreDer],
AuxlRsol[k], PobIni[PadreIzq], PobIni[PadreDer]);
// * Mutación *
if(ProMut!=0)
{
muto = rand() %100;
if(muto< ProMut) // * Muto la solusión k_esima *
Mutacion(m_var, lMaxVsol, muto, AuxPob[k], AuxlRsol[k]);
}//fin if(ProMut!=0)
}//fin for(k)
fitness[0]= MejorFit;
for(k= 1; k<TamPob; k++)
Evalua(n_ec, l_ec, Sist, lReVsol[k],PobIni[k],AuxIzq, AuxDer,
fitness[k] , haysol, prueba);
if(Busqueda != 0)
for(k= 0; k<TamPob; k++)
if(Busqueda == 1)
184
Busqueda_loc_A(m_var, lReVsol[k], lMaxVsol, n_ec, l_ec, Sist,
AuxIzq, AuxDer, PobIni[k], fitness[k],
haysol, cont_uno, cont_dos, prueba);
else
Busqueda_loc_B(m_var, lReVsol[k], lMaxVsol, n_ec, l_ec, Sist,
AuxIzq, AuxDer, PobIni[k], fitness[k],
haysol, cont_uno,prueba);
}//fin for(iter)
if(haysol == 1)
{
fsol<<"El programa ha encontrado solucion con una poblacion de "<<endl;
fsol<<"tama~
no "<<TamPob<<" y longitud máxima de las variables "<<endl;
fsol<<"igual a "<<lMaxVsol<<" ."<<endl;
fsol<<"La probabilidad de mutacion utiliza fue "<<ProMut<<" ."<<endl;
fsol<<"Para generar la poblacion inicial se uso el metodo_"<<Metodo<<endl;
fsol<<"La solucion propuesta tras "<<iter<<" iteraciones es: "<<endl;
k=0;
while(fitness[k] !=0) k= k + 1;
for(i= 0; i< m_var; i++)
{
fsol<<"x"<<i<<" = ";
if(lReVsol[k][i] == 0) fsol<<"la palabra vacia."<<endl;
else
{
for(j= 0;j< lReVsol[k][i]; j++) fsol<<PobIni[k][i][j]<<" ";
fsol<<endl;
}//fin else
}//fin for(i)
}//fin if(haysol==1)
if(haysol == 0)
185
{
fsol<<"El programa NO ha encontrado solucion."<<endl;
fsol<<"Los datos propuestos fueron: "<<endl;
fsol<<"Tama~
no de poblacion igual a "<<TamPob<<" ."<<endl;
fsol<<"Longitud máxima de las variables igual a "<<lMaxVsol<<" ."<<endl;
fsol<<"La probabilidad de mutacion utilizada fue "<<ProMut<<" ."<<endl;
fsol<<"Para generar la población inicial se uso el metodo_"<<Metodo<<endl;
}//fin if(haysol==0)
fsol<<"La poblacion generada tras "<<iter<<" iteraciones es: "<<endl;
for(k= 0; k< TamPob; k++)
{
for(i= 0; i< m_var; i++)
{
for(j= 0;j< lMaxVsol; j++) fsol<<PobIni[k][i][j];
fsol<<" ";
}//fin for(i)
fsol<<" ";
fsol<<"Con fitness "<<fitness[k]<<endl;
}//fin for(k)
if(Busqueda != 0)
{
float media;
media = iter +1;
media = cont_uno/media;
fsol<<"contador_uno = "<<cont_uno<<" en media = "<<media<<endl;
if(Busqueda == 1)
{
media = iter +1;
media = cont_dos/media;
fsol<<"contador_dos = "<<cont_dos<<" en media = "<<media<<endl;
}//fin if
186
fsol<<"Busqueda= "<<Busqueda<<endl;
}//fin if(Busqueda != 0)
fsol<<"El numero de evaluaciones es "<<prueba<<endl;
}//fin programa
187
cout<<"Pulse 1 si quiere fijar la longitud real de la variable y "<<endl;
cout<<"luego generar la variable con simbolos del alfabeto {0,1}."<<endl;
cout<<endl;
cout<<"Pulse 2 si quiere generar la variable en {0,1,2} y luego "<<endl;
cout<<"calcular la longitud real de la variable."<<endl<<endl;
cout<<"Pulse 3 si desea recibir mas informacion sobre los metodos"<<endl;
cout<<"usados en la generacion de la poblacion inicial."<<endl<<endl;
cin>> Metodo;
if(Metodo == 3)
{
cout<<"El metodo-1 elige la longitud real de la variable que va a"<<endl;
cout<<"generar entre cero (que corresponde a la palabra vacia) y "<<endl;
cout<<"la longitud maxima propuesta. Una vez fijada la longitud, "<<endl;
cout<<"genera la variable como una cadena de ceros y unos. "<<endl<<endl;
cout<<"El metodo-2 genera la variable como una cadena de simbolos"<<endl;
cout<<"pertenecientes al conjunto {0,1,2} de longitud la longitud"<<endl;
cout<<"maxima propuesta. Despues reordena esta cadena, colocando"<<endl;
cout<<"todos los doses al final de la misma (pues representan el "<<endl;
cout<<"simbolo vacio). Finalmente, calcula el numero de ceros y "<<endl;
cout<<"unos que aparecen en la cadena y que corresponde a la "<<endl;
cout<<"longitud real de la variable generada."<<endl<<endl;
cout<<"Que metodo desea utilizar?"<<endl;
cin>> Metodo;
}//fin if
}while(Metodo<1 || Metodo>2);
do{
cout<<"Si no desea aplicar busqueda local pulse 0, "<<endl;
cout<<"en otro caso pulse 1 o 2 dependiendo del tipo de busqueda"<<endl;
cout<<"que desea utilizar."<<endl;
cout<<"Si desea recibir informacion acerca de los metodos usados"<<endl;
cout<<"pulse 3."<<endl;
cin>> Busqueda;
188
if(Busqueda == 3)
{
cout<<"El tipo de busqueda_1 aplica la busqueda local clasica a "<<endl;
cout<<"cada solucion hasta que no mejora y luego cambia la "<<endl;
cout<<"longitud de las variables en una unidad. Si hay mejora"<<endl;
cout<<"repite el proceso."<<endl;
cout<<"Mientras que la busqueda_2 aplica a cada variable de una "<<endl;
cout<<"solucion la busqueda local y el cambio de longitud. Si al"<<endl;
cout<<"final hay mejora se repite el proceso."<<endl;
cout<<"Que tipo de busqueda local desea aplicar?"<<endl;
cin>> Busqueda;
}//fin if
}while(Busqueda<0 || Busqueda>2);
}//fin Pedir_Datos
189
for(int i= 0; i< 2*n_ec - 1; i+= 2)
{
coincidencia= 0; columnas= 0; minimo= min (l_ec[i],l_ec[i+1]);
while(Sist[i][columnas]== Sist[i+1][columnas] && columnas< minimo)
{
coincidencia= coincidencia +1; columnas= columnas +1;
}//fin while
if(coincidencia!=0)
{
l_ec[i]= l_ec[i]-coincidencia;
for(int j= 0; j< l_ec[i]; j++)
Sist[i][j]= Sist[i][j+coincidencia];
Sist[i].resize(l_ec[i]);
l_ec[i+1]= l_ec[i+1]-coincidencia;
for(int j= 0; j< l_ec[i+1]; j++)
Sist[i+1][j]= Sist[i+1][j+coincidencia];
Sist[i+1].resize(l_ec[i+1]);
}//fin if
coincidencia= 0; columnas= 1; minimo= min (l_ec[i],l_ec[i+1]);
while(columnas<= minimo &&
Sist[i][l_ec[i]-columnas] == Sist[i+1][l_ec[i+1]-columnas])
{
coincidencia= coincidencia +1;
columnas= columnas +1;
}//fin while
if(coincidencia!=0)
{
l_ec[i]= l_ec[i] -coincidencia; Sist[i].resize(l_ec[i]);
l_ec[i+1]= l_ec[i+1]-coincidencia; Sist[i+1].resize(l_ec[i+1]);
}//fin if
}//fin for(i)
}//fin Simplifica
190
void Genera_PobIni(vector<vector<vector<int> > > &PobIni,
vector<vector<int> > &lReVsol,
vector<vector<vector<int> > > &AuxPob,
vector<vector<int> > &AuxlRsol, const int &TamPob,
const int &m_var, const int &lMaxVsol, const int &Metodo)
{
int longitud;
PobIni.resize(TamPob);
lReVsol.resize(TamPob);
AuxPob.resize(TamPob); //vector auxiliar
AuxlRsol.resize(TamPob); //vector auxiliar
for(int k= 0; k< TamPob; k++)
{
PobIni[k].resize(m_var);
lReVsol[k].resize(m_var);
AuxPob[k].resize(m_var); //vector auxiliar
AuxlRsol[k].resize(m_var); //vector auxiliar
for(int i= 0; i< m_var; i++)
{
PobIni[k][i].resize(lMaxVsol);
if(Metodo == 1)
{
longitud= lMaxVsol +1;
lReVsol[k][i]= rand() % longitud;
for(int j= 0; j< lReVsol[k][i]; j++) PobIni[k][i][j]= rand() % 2;
for(int j= lReVsol[k][i]; j< lMaxVsol; j++) PobIni[k][i][j]= 2;
}//fin if(Metodo==1)
if(Metodo == 2)
{
lReVsol[k][i]= lMaxVsol;
for(int j= 0; j< lMaxVsol; j++) PobIni[k][i][j] = rand() % 3;
191
reordeno(lMaxVsol, PobIni[k][i],lReVsol[k][i]);
}//fin if(Metodo==2)
}//fin for(i)
}//fin for(k)
}//fin Genera_PobIni
192
prueba=prueba+1;
coincidencia = 0;
for(int i= 0; i<n_ec; i++)
{
lAuxIzq= l_ec[2*i];
lAuxDer= l_ec[2*i+1];
AuxIzq.resize(lAuxIzq);
AuxDer.resize(lAuxDer);
sustituyo(Sist[2*i], lAuxIzq, AuxIzq, lReVsol, PobIni);
sustituyo(Sist[2*i+1], lAuxDer, AuxDer, lReVsol, PobIni);
minimo = min(lAuxIzq,lAuxDer);
for(int j= 0;j< minimo; j++)
if(AuxIzq[j] != AuxDer[j]) coincidencia= coincidencia+1;
coincidencia= coincidencia + abs(lAuxIzq-lAuxDer);
}//fin for(i)
fitness= coincidencia;
if(fitness == 0) haysol= 1;
}//fin Evaluacion
193
{
lAux=lAux-1;
Aux.resize(lAux);
auxiliar=auxiliar+1;
j=j-1;
}
else
{
lAux=lAux+lVsol[variable]-1;
Aux.resize(lAux);
for(l= 0; l< lVsol[variable]; l++) Aux[j+l] = PobIni[variable][l];
auxiliar = auxiliar - lVsol[variable] + 1;
j=j+lVsol[variable]-1;
}
}//fin else
}//fin sustituyo
194
}//fin if(fitness[k]< MejorFit)
if(MejorFit == fitness[k])
{
minimo= rand() % 2;
if(minimo == 0)
{
MejorFit= fitness[k];
variable= k;
}//fin if(minimo == 0)
}//fin if(MejorFit == fitness[k])
}//fin for(k)
for(int i= 0; i< m_var; i++)
{
AuxPob[i].resize(lMaxVsol);
AuxlRsol[i]= lReVsol[variable][i];
for(int j= 0; j< lMaxVsol; j++) AuxPob[i][j]= PobIni[variable][i][j];
}//fin for(i)
}//fin Mejor_Sol
195
limInf = 0;
limSup = fitness[0];
for(int i= 0; i<TamPob && coinciden == 0; i++)
{
if(limInf <= Padre && Padre < limSup)
{
Padre = i;
coinciden = 1;
}
else
{
limInf = limInf + fitness[i];
limSup = limSup + fitness[i+1];
}
}
}//fin eligo_padre
196
if(columna == 0) AuxPob[i][j]= PobIniIzq[i][j];
else AuxPob[i][j]= PobIniDer[i][j];
}//fin for(j)
longitud= lMaxVsol - minimo;
columna= longitud +1;
columna= rand() % columna;
if(lReVsolIzq[i]< lReVsolDer[i])
{
for(int j= 0; j< columna; j++)
{
AuxPob[i][minimo+j]= PobIniDer[i][minimo+j];
if(AuxPob[i][minimo+j]!= 2) AuxlRsol[i]= AuxlRsol[i] +1;
}//fin for(j)
for(int j= columna; j< longitud; j++) AuxPob[i][minimo+j]= 2;
}//fin if
else
{
for(int j= 0; j< columna; j++)
{
AuxPob[i][minimo+j]= PobIniIzq[i][minimo+j];
if(AuxPob[i][minimo+j]!= 2) AuxlRsol[i] = AuxlRsol[i] +1;
}//fin for(j)
for(int j= columna; j< longitud; j++) AuxPob[i][minimo+j] = 2;
}//fin else
}//fin for(i)
}//fin cruce
197
{
muto= rand() % lMaxVsol;
if(muto == 0) AuxPob[i][j]= rand() % 3;
}//fin for (j)
AuxlRsol[i]= lMaxVsol;
reordeno(lMaxVsol, AuxPob[i],AuxlRsol[i]);
}//fin for(i)
}//fin Mutacion
198
if(fitness >= MejorFit)
{
fitness = MejorFit;
if(PobIni[i][j] == 1) PobIni[i][j] = 0;
else PobIni[i][j] = 1;
}
else mejoro = 1;
}//fin for(j)
}//fin for(i)
}while(mejoro == 1 && fitness != 0);
199
lReVsol[i] = columna +1;
Evalua(n_ec,l_ec,Sist,lReVsol,PobIni,AuxIzq,AuxDer,fitness,
haysol,prueba);
if(MejorFit <= fitness)
{
fitness = MejorFit;
PobIni[i][columna] = vder;
if(vder == 2) lReVsol[i] = columna;
}
else repito = 1;
}//fin if(columna < lMaxVsol)
200
}
else lReVsol[i] = columna;
}//fin if
else repito = 1;
}//fin if if(lReVsol[i] > 0 && columna > 1)
}//fin for(i)
}while(repito == 1 && fitness != 0);
}//fin Busqueda_loc_A
201
if(PobIni[i][j] == 1) PobIni[i][j] = 0;
else PobIni[i][j] = 1;
}
else repito = 1;
}//fin for(j)
202
else repito = 1;
}//fin if(columna < lMaxVsol)
203
Bibliografı́a
[1] Abdulrab, H.: Résolution d’equations sur les mots: étude et implementation LIPs
de l’algoritme de Makanin.
[2] Alonso, C.L., Drubi, F., and Montaña, J.L.: An Evolutionary Algorithm for Sol-
ving Word Equation Systems.
[3] Bäck, T., Eiben, A., and Vink, M.: A superior evolutionary algorithm for 3-SAT.
[4] Eiben, A., and van der Hauw, J.: Solving 3-SAT with adaptative genetic algo-
rithms.
[5] Goldberg, D. E.: Genetic Algorithms in Search, Optimization & Machine Lear-
ning.
[6] Gottlieb, J., and Voss, N.: Improving the performance of evolutionary algorithms
for the satisfiability problem by refening functions.
Proceedings of the Fifth International Conference on Parallel Problem Solving from Nature.
Lecture Notes in Computer Science, Volumen 1498, pages 755 − 764, Springer, Berlin, Ger-
many. 1998
204
[7] Gottlieb, J., and Voss, N.: Representations, fitness functions and genetic oper-
ators for the satisfiability problem.
Proceedings of Artificial Evolution. Lecture Notes in Computer Science, Volumen 1363, pages
55 − 68, Springer, Berlin, Germany. 1998
[8] Gottlieb, J., Marchiori, E., and Rossi, C.: Evolutionary Algorithms for the Sa-
tisfiability Problem.
[10] Hao, J.-K.: A clausal genetic representation and its evolutionary procedures for
satisfiatibility problems.
Proceedings of the International Conference on Artificial Neural Nets and Genetic Algorithms,
pages 289 − 292, Springer, Vienna, Austria. 1995
[15] Lentin, J.: Equations in free monoids, in automata languages and programming.
[16] Makanin, G.S.: The problem of solvability of equations in a free semigroup, Math.
205
[17] Marchiori, E. and Rossi, C.: A flipping genetic algorithm for hard 3-SAT pro-
blems.
Proceedings of Genetic and Evolutionary Computation Conference, pages 393 − 400, Morgan
Kaufmann, San Francisco, California. 1999
[18] McAllester, D., selman, B., and Kautz, H.: Evidence for invariants in local
search.
In Proceedings of the National Conference on Artificial Intelligent, pages 321 − 326, AAAI
Press, Menlo Park, California. 1997
[20] Plotkin, G. D.: Building in equational theories, Mach. pages 73 − 90, 1972
[22] Rossi, C., Marchiori, E., and Kok, J.: An adaptive evolutionary algorithm for the
satisfiability problem.
Proceedings of ACM Symposium on Applied Computing, pages 463 − 469, ACM, New York.
2000
[23] Selman, B., Kautz, H., and Cohen, B.: Noise strategies for improving local search.
In Proceedings of the Twelfth National Conference on Artificial Intelligent, pages 337 − 343,
AAAI Press, Menlo Park, California. 1994
1972
206