43
Introducción a la Programación Tema 16. Algoritmos de Aproximación 1. Introducción.......................................................................................................................... 2 2. Programación Lineal Entera ................................................................................................. 3 2.1 Un catálogo de problemas ............................................................................................ 4 2.2 Algunas técnicas útiles en los modelos de Programación Lineal Entera..................... 16 2.3 Complejidad de los problemas de Programación Lineal Entera ................................. 19 2.4 Programación Lineal Entera. Detalles de Implementación ......................................... 19 3. Algoritmos aleatorios y optimización ................................................................................ 20 3.1 Introducción ................................................................................................................ 20 3.2 Problemas de optimización ......................................................................................... 21 3.3 Algoritmos probabilísticos........................................................................................... 23 4. Un catálogo de tipos de cromosomas ................................................................................ 24 4.1 ValuesInRangeChromosome<E> ................................................................................. 25 4.1.1 BinaryChromosome ................................................................................................. 25 4.1.2 RangeChromosome ................................................................................................. 27 4.1.3 RealChromosome .................................................................................................... 27 4.2 IndexChromosome ...................................................................................................... 28 4.2.1 IndexSubListChromosome....................................................................................... 28 4.2.2 IndexPermutationChromosome.............................................................................. 29 4.2.3 IndexPermutationSubListChromosome .................................................................. 30 4.3 ExpressionChromosome.............................................................................................. 30 4.4 ListIntegerChromosome .............................................................................................. 31 5. Algoritmos Genéticos ......................................................................................................... 32 6. Algoritmos Genéticos detalles de implementación .......................................................... 33 6.1 Parámetros de un Algoritmo Genético ....................................................................... 35 7. Ejemplos de algoritmos genéticos ..................................................................................... 36 7.1 Problema de la Mochila .............................................................................................. 36 7.2 Problema de las Reinas: .............................................................................................. 37 7.3 Problema de los Anuncios ........................................................................................... 38 7.4 Problema de regresión ................................................................................................ 38 7.5 Problema de extremo de una función ........................................................................ 38 8. Algoritmos de Simulated Annealing .................................................................................. 39

Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

Embed Size (px)

Citation preview

Page 1: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

Introducción a la Programación

Tema 16. Algoritmos de Aproximación

1. Introducción .......................................................................................................................... 2

2. Programación Lineal Entera ................................................................................................. 3

2.1 Un catálogo de problemas ............................................................................................ 4

2.2 Algunas técnicas útiles en los modelos de Programación Lineal Entera..................... 16

2.3 Complejidad de los problemas de Programación Lineal Entera ................................. 19

2.4 Programación Lineal Entera. Detalles de Implementación ......................................... 19

3. Algoritmos aleatorios y optimización ................................................................................ 20

3.1 Introducción ................................................................................................................ 20

3.2 Problemas de optimización ......................................................................................... 21

3.3 Algoritmos probabilísticos ........................................................................................... 23

4. Un catálogo de tipos de cromosomas ................................................................................ 24

4.1 ValuesInRangeChromosome<E> ................................................................................. 25

4.1.1 BinaryChromosome ................................................................................................. 25

4.1.2 RangeChromosome ................................................................................................. 27

4.1.3 RealChromosome .................................................................................................... 27

4.2 IndexChromosome ...................................................................................................... 28

4.2.1 IndexSubListChromosome ....................................................................................... 28

4.2.2 IndexPermutationChromosome .............................................................................. 29

4.2.3 IndexPermutationSubListChromosome .................................................................. 30

4.3 ExpressionChromosome .............................................................................................. 30

4.4 ListIntegerChromosome .............................................................................................. 31

5. Algoritmos Genéticos ......................................................................................................... 32

6. Algoritmos Genéticos detalles de implementación .......................................................... 33

6.1 Parámetros de un Algoritmo Genético ....................................................................... 35

7. Ejemplos de algoritmos genéticos ..................................................................................... 36

7.1 Problema de la Mochila .............................................................................................. 36

7.2 Problema de las Reinas: .............................................................................................. 37

7.3 Problema de los Anuncios ........................................................................................... 38

7.4 Problema de regresión ................................................................................................ 38

7.5 Problema de extremo de una función ........................................................................ 38

8. Algoritmos de Simulated Annealing .................................................................................. 39

Page 2: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

2 Introducción a la Programación

8.1 Busqueda Tabú ............................................................................................................ 41

9. Detalles de implementación de los Algoritmos de Simulated Annealing ........................ 42

1. Introducción

En los capítulos anteriores hemos visto distintos tipos de algoritmos recursivos: Divide y

Vencerás, Programación Dinámica y algoritmos de Vuelta Atrás con sus diferentes variantes. Son

algoritmos que usan una búsqueda exhaustiva. Para el caso de problemas de optimización son

capaces de encontrar, si existe, la solución exacta. Pero en algunos casos la complejidad del

algoritmo es demasiado alta y debemos buscar otro tipo de algoritmos que encuentren

soluciones subóptimas cercanas a la óptima pero con un menor coste de ejecución. Llamaremos

a este tipo Algoritmos de Aproximación. En este tema veremos Algoritmos Iterativos de

Aproximación que serán de dos tipos: Simulated Annealing y Algoritmos Genéticos. Los dos son

algoritmos iterativos. Junto a ellos podemos considerar los algoritmos Voraces que también son

en general algoritmos iterativos de aproximación pero que vemos en otro capítulo.

En este capítulo veremos en primer lugar la Programación Lineal Entera que es una técnica para

encontrar soluciones exactas a algunos problemas de optimización o aproximadas relajando

algunas de las restricciones impuestas.

Los algoritmos de aproximación son adecuados para resolver problemas de optimización. Este

tipo de problemas viene definido por un conjunto de restricciones y una función objetivo que

calcula un valor para cada una de las posibles soluciones. En un problema de optimización

buscamos la solución, que cumpliendo las restricciones del problema, minimice (o maximice) el

valor de la función objetivo.

En general, como iremos viendo con ejemplos, los problemas que no son de optimización pero

buscan una o varias soluciones que cumplan las restricciones del problema (o solamente la

existencia de alguna de ellas) pueden transformarse en problemas de optimización.

En los algoritmos de aproximación diseñamos un estado cuyos valores representarán las

posibles soluciones del problema. La función objetivo se evaluará sobre cada una de las

instancias del estado diseñado. Existirá, además, una función que aplicada a cada estado nos

indique si representa una solución válida o no. Si el estado representa una solución válida

diremos que es un estado válido. En otro caso es un estado inválido. Dispondremos también

otra función que calculará la solución asociada a los estados válidos.

Los algoritmos de aproximación que veremos son iterativos. Usan una condición de parada para

decidir cuando terminan.

Las estrategias que estudiaremos son: Simulated Annealing y Algoritmos Genéticos. En la

primera se diseñan un conjunto de alternativas posibles, también podemos llamarlas

Page 3: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

3 16. Algoritmos iterativos de aproximación

operadores, para cada estado, se escoge aleatoriamente una alternativa de entre las posibles,

y se pasa al estado siguiente. Si se acepta se continua. Si no se acepta se vuelve al estado

anterior. Es necesario definir una condición de aceptación del estado siguiente. Los Algoritmos

Genéticos emulan los mecanismos de la evolución. Codifican los estados posibles en distintas

formas y usan, como en la evolución operadores (similares a las alternativas anteriores) de cruce

y mutación. Los algoritmos Simulated Annealing y Genéticos son algoritmos aleatorios en en

sentido de que escogen alternativas a al azar.

Los dos tipos de algoritmos son algoritmos de aproximación: es decir sólo son capaces de

encontrar soluciones subóptimas. Es decir soluciones cercanas a la óptima aunque en algunos

algoritmos de este tipo es posible demostrar que alcanzan la solución óptima. En muchos casos

es posible demostrar que un algoritmo de aproximación encuentra la solución óptima. En otros

casos que encuentra una solución cercana al óptimo en un factor 𝜌. Diremos que es un algoritmo

𝜌-aproximado. Con esto queremos decir exactamente que si tenemos un algoritmo de

aproximación de minimización 𝜌-aproximado que encuentra una solución 𝑠 y 𝑠𝑜𝑝 es la solución

óptima entonces 𝑠 ∈ [𝑠𝑜𝑝, 𝜌𝑠𝑜𝑝] con 𝜌 ≥ 1. Si 𝜌 = 1 el algoritmo de aproximación es exacto.

Para el caso de maximización existe una definición similar con 𝑠 ∈ [ 𝜌𝑠𝑜𝑝, 𝑠𝑜𝑝] y 𝜌 ≤ 1.

2. Programación Lineal Entera

Esta técnica consiste en modelar un problema, normalmente de optimización, en un conjunto

de restricciones lineales sobre variables de tipo real más una función objetivo a maximizar o

minimizar. A este problema transformado los llamaremos Problema de Programación Lineal. El

problema modelado así puede ser resuelto de forma muy eficiente por el conocido Algoritmo

del Simplex que puede resolver el problema en tiempo polinomial en la gran mayoría de los

casos.

El problema de programación lineal puede ser completado con otras restricciones como:

Algunas variables toman valores enteros

Algunas variables toman valores binarios

Dado un conjunto de variables sólo 𝑘 de ellas pueden tomar, en la solución, valores

distintos de cero.

Un problema de Programación Lineal con restricciones del tipo anterior lo denominaremos

Problema de Programación Lineal Entera. Esta metodología tiene un mayor poder expresivo que

la Programación Lineal pero su complejidad computacional es más alta que polinomial. Si

eliminamos las restricciones de tipo entero y binario obtenemos un Problema de Progrmación

Lineal eficiente de resolver pero que no es exactamente igual al original. Al problema resultante

se le llama relajación lineal del primero y su solución es una aproximación del mismo.

Para resolver estos problemas se usa una mezcla de relajación lineal más algoritmos de vuelta

atrás. El problema relajado linealmente, como hemos comentado, puede resolverse muy

Page 4: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

4 Introducción a la Programación

eficientemente en tiempo polinomial mediante el algoritmo del Simplex pero con él sólo

obtendremos una aproximación a la solución del problema de Programación Lineal Entera. Para

resolver este primero se encuentra, mediante el algoritmo del Simplex, la solución de la

relajación lineal que es aproximada y posteriormente, mediante vuelta atrás, el valor optimo

entero o binario y que respete las restricciones adicionales. Los algoritmos que resuelven los

problemas de Programación Lineal Entera tienen comlejidades superiores a las polinomiales.

Aquí, por el momento estamos interesados en los problemas de modelado mediante

Progrmación Lineal Entera asumiendo que disponemos de los algoritmos necesarios para

encontrar la solución. Para concretar un Problema de Programación Lineal Entera se compone

de:

Un conjunto de variables reales

Un conjunto de varibles pueden tomar valores enteros

Unconjunto de variables pueden tomar valores binarios

Una función objetivo compuesto como una combinación lineal de las varaibles

Un conjunto de restricciones (mayor, menor, igual, mayor o igual, menor o igual) entre

combinaciones lineales de variables

Adicionalmente se pueden añadir otro tipo de variables libres, semicontinuas y restricciones SOS

que veremos más adelante. Veamos ejemplos y detalles de este tipo de modelos.

2.1 Un catálogo de problemas

Veamos aquí un catálogo de problemas que pueden ser resueltos mediante modelos de

Programación Lineal Entera o Mixta.

Problemas de redes de flujo

De forma compacta los problemas de redes de flujo se pueden modelar, como hemos visto en

capítulos anteriores, como grafos dirigidos con un conjunto de vértices fuente (𝐹), un conjunto

de vértices sumidero (𝑆), y un conjunto de restricciones sobre los flujos producidos, los

consumidos, lso flujos circulantes por los vértices y por las aristas. Asumamos que 𝑉 es el

conjunto de vértices, 𝐹 el conjunto de vértices fuente, 𝑆 el conjunto de vértices sumidero, 𝑉 −

𝐹 ∪ 𝑆 el conjunto de vértices intermedios, 𝐸 el conjunto de aristas, 𝑤𝑗 el costo unitario asociado

al paso del flujo por la 𝑗 ∈ 𝐸, el costo unitario asociado a la producción o consumo o paso de

una unidad por el vértices 𝑖 ∈ 𝑉 lo representaremos por 𝑤𝑖, a las cotas superiores e inferiores

en vértices y aristas los representamos respectivamente por 𝑏𝑖𝑢, 𝑏𝑖

𝑑 , 𝑏𝑗𝑢, 𝑏𝑗

𝑑, el flujo creado en

vértices fuente o consumido en vértices sumidero 𝑥𝑖 y el flujo por una arista 𝑦𝑗. Las ecuaciones

resultantes son:

Page 5: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

5 16. Algoritmos iterativos de aproximación

min ∑ 𝑤𝑖𝑥𝑖 +

𝑖∈𝑉

∑ 𝑤𝑗𝑦𝑗

𝑗∈𝐸

𝑥𝑖 = ∑ 𝑦𝑘, 𝑖 ∈ 𝐹

𝑘:𝑂𝑢𝑡(𝑖)

∑ 𝑦𝑘 = 𝑥𝑖 , 𝑖 ∈ 𝑆

𝑘:𝐼𝑛(𝑖)

∑ 𝑦𝑘

𝑘∈:𝑛(𝑖)

= ∑ 𝑦𝑘, 𝑖 ∈ 𝑉 − 𝐹⋃𝑆

𝑘:𝑂𝑢𝑡(𝑖)

𝑏𝑖𝑑 ≤ 𝑥𝑖 ≤ 𝑏𝑖

𝑢, 𝑖 ∈ 𝐹⋃𝑆

𝑏𝑗𝑑 ≤ 𝑦𝑗 ≤ 𝑏𝑗

𝑢, 𝑗 ∈ 𝐸

𝑏𝑖𝑢 ≤ ∑ 𝑦𝑘

𝑘:𝐼𝑛(𝑖)

≤ 𝑏𝑖𝑢, 𝑖 ∈ 𝑉 − 𝐹⋃𝑆

Tal como como lo hemos enunciado tenemos un Problema de Programación Lineal.

Problema de la Mochila

Como ejemplo tomemos el problema de la Mochila que iremos resolviendo de varias formas. El

problema de la Mochila parte de un multiconjunto de objetos 𝑀 = (𝐿𝑜, 𝑚), dónde 𝐿𝑜 es una

lista de objetos de tamaño 𝑛 y 𝑚 una alista de enteros del mismo tamaño dónde 𝑚𝑖 indica el

número de repeticiones del objeto en la posición 𝑖. A su vez cada objeto 𝑜𝑏𝑖 de la lista es de la

forma 𝑜𝑏𝑖 = (𝑤𝑖 , 𝑣𝑖) dónde 𝑤𝑖, 𝑣𝑖 son, respectivamente su peso y su valor unitario. Además

la mochila tiene una capacidad 𝐶. El problema busca ubicar en la mochila el máximo número

unidades de cada objeto que quepan en la mochila para que el valor de los mismos sea máximo.

Si 𝑥𝑖 es el número de unidades del objeto 𝑖 en la mochila el problema puede enunciarse como

un problema de Programación Lineal de la forma:

max ∑ 𝑥𝑖𝑣𝑖

𝑛−1

𝑖=0

∑ 𝑥𝑖𝑤𝑖

𝑛−1

𝑖=0

≤ 𝐶

𝑥𝑖 ≤ 𝑚𝑖, 𝑖 ∈ [0, 𝑛 − 1]

𝑖𝑛𝑡 𝑥𝑖, 𝑖 ∈ [0, 𝑛 − 1]

El primer enunciado muestra el objetivo a maximizar. El segundo las restricciones de la

capacidad de la mochila. El tercero las debidas al número máximo de unidades disponibles de

cada objeto. El último enunciado indica que las variables 𝑥𝑖 toman valores en los enteros. Sin

este enunciado las varaibles tomarían valores reales.

Problema de la Asignación

Page 6: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

6 Introducción a la Programación

En este problema tenemos una lista de agentes 𝐿 y una lista de tareas 𝑇 ambas del mismo

tamaño 𝑛. El coste de que el agente 𝑖 realice la tarea 𝑗 sea 𝑐𝑖𝑗 . Se pretende asignar a cada agente

una tarea y sólo una de tal forma que se ejecuten todas las tareas con el coste mínimo.

Asumimos las variables binarias 𝑥𝑖𝑗 toman valor 1 si el agente 𝑖 ejecuta la tarea 𝑗 y cero si no la

ejecuta. El problema puede ser planteado de la forma:

min ∑ 𝑥𝑖𝑗 𝑐𝑖𝑗

𝑛−1,𝑛−1

𝑖=0,𝑗=0

∑ 𝑥𝑖𝑗 = 1, 𝑖 ∈ [0, 𝑛 − 1]

𝑛−1

𝑗=0

∑ 𝑥𝑖𝑗 = 1, 𝑗 ∈ [0, 𝑛 − 1]

𝑛−1

𝑖=0

𝑏𝑖𝑛 𝑥𝑖𝑗, 𝑖 ∈ [0, 𝑛 − 1], 𝑗 ∈ [0, 𝑛 − 1]

Ahora las variables son binarias, toman valores cero y uno y, de nuevo, tenemos un Problema

de Programación Lineal Entera. El primer conjunto de restricciones indica que cada agente 𝑖

tiene que realizar una tarea y sólo una. El segundo conjunto de restricciones indica que cada la

tarea 𝑗 tiene que ser realizada por un agente y sólo uno.

Inversión de capital

El problema se puede encunciar de la siguiente forma: Supongamos que deseamos invertir una

cantidad total 𝑇. Tenemos identificadas 𝑛 oportunidades de inversión. Cada oportunidad de

inversión requiere de una cantidad 𝑐𝑖 y se espera un resultado con valor actual 𝑣𝑖 con 𝑖 ∈ [0, 𝑛).

¿Que las inversiones debemos realizar con el fin de maximizar el valor actual total?

El problema anterior, de una forma abstracta, es similar al Problema de la Mochila visto

anteriormente. Ahora vamos a considerar algunas restricciones adicionales que podríamos

querer añadir. Por ejemplo, consideremos limitaciones del tipo siguiente:

1. Sólo podemos hacer 2 inversiones como máximo.

2. Si se hace la inversión 𝑟 la 𝑠 también se debe hacer.

3. Si se hace la inversión 𝑢 la 𝑣 no se puede hacer y viceversa.

Asumiendo que las variables binarias 𝑥𝑖 toman valor 1 si se realiza la inversión 𝑖 y cero en caso

contrario podemos modlear el problema como:

Page 7: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

7 16. Algoritmos iterativos de aproximación

max ∑ 𝑥𝑖𝑣𝑖

𝑛−1

𝑖=0

∑ 𝑥𝑖𝑐𝑖 ≤ 𝑇

𝑛−1

𝑖=0

∑ 𝑥𝑖 ≤ 2

𝑛−1

𝑖=0

𝑥𝑟 − 𝑥𝑠 ≤ 0𝑥𝑢 + 𝑥𝑣 ≤ 1

𝑏𝑖𝑛 𝑖, 𝑖 ∈ [0, 𝑛)

La restricción 𝑥𝑟 − 𝑥𝑠 ≤ 0, asumiendo que las variables toman valores binarios tiene como

soluciones posibles para (𝑥𝑟, 𝑥𝑠) los pares {(0,0), (0,1), (1,1)} y por lo tanto si 𝑥𝑟 = 1 implica

que 𝑥𝑠 = 1.

La restricción 𝑥𝑢 + 𝑥𝑣 ≤ 1, asumiendo que las variables toman valores binarios tiene como

soluciones posibles para (𝑥𝑟, 𝑥𝑠) los pares {(0,0), (0,1), (1,0)} y por lo tanto se escoge una de

las dos inversiones o ninguna pero no las dos a la vez.

Recubrimiento de conjuntos (Set Covering)

Dado un conjunto de elementos 𝑈 de elementos 𝑒𝑖 , 𝑖 ∈ [0, 𝑛 − 1), (llamado el universo) y un

conjunto 𝑆 de 𝑚 conjuntos 𝑠𝑗, cuya unión es igual al universo, y un peso 𝑤𝑖 ≥ 0 asociado a cada

conjunto, el problema de cobertura conjunto es identificar el subconjunto más pequeño de 𝑆

cuya unión es igual al universo 𝑈. Por ejemplo, considere si el universo es 𝑈 = {1,2,3,4,5} y el

conjunto 𝑆 = {{1,2,3}, {2,4}, {3,4}, {4,5}}, todos ellos con peso 1, podemos comprobar que la

unión de todos elo conjunto en 𝑆 es 𝑈 y que podemos cubrir la totalidad de los elementos con

los conjuntos {{1,2,3}, {4,5}}.

El problema puede ser modelado mendiante un Problema de Programación Lineal Entera

considerando las variables binarias 𝑥𝑗, 𝑗 ∈ [0, 𝑚) que tomarán el valor 1 si el conjunto 𝑠𝑗 es

escogido.

min ∑ 𝑤𝑗𝑥𝑗

𝑚−1

𝑗=0

(∑ 𝑥𝑗) ≥ 1, 𝑖 ∈ [0, 𝑛)𝑗:𝜑(𝑖)

𝑏𝑖𝑛 𝑥𝑗 , 𝑗 ∈ [0, 𝑚)

Siendo 𝜑(𝑖) = {𝑗: 𝑒𝑖 ∈ 𝑠𝑗}, es decir el conjunto de índices de conjuntos que incluyen al elemento

𝑒𝑖. Hay una restricción por cada elemento. Esto garantiza que ese elemento estará en alguno

de los subconjuntos elegidos.

El Problema es equivalente al conocido como Hitting Set parte de un grafo bipartito con vértices

de tipos 𝑉1, 𝑉2 y se pretende encontrar un subconjunto mínimo de los vértices en 𝑉1 tal que

Page 8: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

8 Introducción a la Programación

incluyan a todos los 𝑉2 entre sus vecinos. El problema es equivalente al del Recubrimiento de

Conjuntos (Set Cover) anterior. Para ello escojamos como vértices en 𝑉1 los conjuntos en 𝑆,

como vértices en 𝑉2 los elementos en 𝑈 y añadiendo unan arista de un vértices en 𝑉1 a otro en

𝑉2 si el correspondiente conjunto incluye al elemento.

El Problema del Recubrimiento de Vértices (Vertex Cover) de un grafo consiste en buscar un

subconjunto mínimo de vértices tal que cada arista del conjunto es incidente al menos a uno de

los vértices escogidos. Construyendo un nuevo grafo con vértices 𝑉1 que asociados a los vértices

del grafo original y vértices 𝑉2 a sus aristas e incluyendo en el nuevo grafo una arista por cada

incidencia de arista y vértice en el grafo original vemos que este problema es equivalente al

Hitting Set visto antes y por lo tanto también equivalente al Set Cover. En concreto siendo 𝐸 el

conjunto de aristas, considerando las variables binarias 𝑥𝑗, 𝑗 ∈ [0, 𝑚) que tomarán el valor 1 si

el conjunto 𝑣𝑗 es escogido, el Problema del Vetex Cover puede ser formulado como:

min ∑ 𝑤𝑗𝑥𝑗

𝑚−1

𝑗=0

𝑥𝑢 + 𝑥𝑣 ≥ 1, (𝑢, 𝑣) ∈ 𝐸

𝑏𝑖𝑛 𝑥𝑗, 𝑗 ∈ [0, 𝑚)

Donde por (𝑢, 𝑣) ∈ 𝐸 queremos representar el cojunto de aristas del grafo y para cada arista

su respectivos extremos.

El problema del Recubrimiento Mínimo de Aristas consiste en encontrar un subconjunto mínimo

de aristas que tal que cada vértice del grafo sea incidente con alguna de las escogidas. Este

problema, como podemos ver, tabién puede ser considerado como un caso particular de Set

Cover.

Problema de las estaciones de bomberos

Para ilustrar este modelo, consideremos el siguiente problema de localización: Una ciudad está

considerando la ubicación de sus estaciones de bomberos. La ciudad se compone de n barrios.

Cada barrio es vecino de otros barrios y la relación de vecindad se puede representar mediante

un grafo no dirigido cuyos vértices representan los barrios y existe una arista entre dos barrios

si son vecinos. Una estación de bomberos se puede colocar en cualquier barrio y es capaz de

gestionar los incendios, tanto para de barrio y como de cualquier barrio vecino. El objetivo es

minimizar el número de estaciones de bomberos.

Este problema podemos considerarlo como un ejemplo de Set Cover considerando los barrios

como elementos del conjunto 𝑈 y cada conjunto de vecinos de un vértice, más él mismo, como

uno de los conjuntos. Si los índices de los vecinos de 𝑣𝑗, incluyendo él mismo, los representamos

por 𝑁(𝑗) y las variables binarias 𝑥𝑗, 𝑗 ∈ [0, 𝑚), que tomarán el valor 1 si el vértice 𝑣𝑗 es

escogido, el problema de las estaciones de bomberos puede ser formulado como:

Page 9: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

9 16. Algoritmos iterativos de aproximación

min ∑ 𝑥𝑗

𝑚−1

𝑗=0

(∑ 𝑥𝑗) ≥ 1, 𝑖 ∈ [0, 𝑚)𝑗:𝑁(𝑖)

𝑏𝑖𝑛 𝑥𝑗 , 𝑗 ∈ [0, 𝑚)

Problema de la aerolínea (emparejamiento de tripulaciones)

El problema parte de un grafo dirigido, dónde cada vértice representa un aeropuerto y arista

un vuelo que está marcado con la hora de salida y llegada. El objetivo que se busca es asignar

tripulaciones a los vuelos con el objetivo de minimizar una función de coste dada.

Definimos un emparejamiento de vuelos como una serie de vuelos que podrían ser atendidos

por una sola tripulación. Esto significa que la hora de salida de un vuelo de la serie de un

aeropuerto debe ser posterior a la hora de llegada del vuelo anterior al mismo aeropuerto.

Suponemos que cada tripulación debe dar servicio al menos a dos vuelos, de modo que cada

emparejamiento contiene al menos dos vuelos y que podemos asignar varias tripulaciones a un

vuelo, si es necesario, con el fin de transportar una tripulación a otro aeropuerto.

El costo de una tripulación es proporcional al intervalo de tiempo entre la primera hora de salida

y la última vez llegada +5 horas.

Un enfoque del problema es construir en primer lugar un grafo de conexiones cuyos vértices son

los vuelos y existen aristas entre vuelos que pueden formar un emparejamiento. El grafo

resultante no tiene ciclos y se puede se construir en el tiempo 𝑂(𝑛). Cada emparejamiento

buscado es un subcamino del grafo obtenido de longitud al menos dos y su coste es el intervalo

de tiempo entre la primera hora de salida y la última llegada más 5 horas. Todos los

emparejamientos posibles se pueden enumerar.

La solución del problema viene dada por un subconjunto de los emparejamientos posibles que

cubra todos los vuelos y tenga coste mínimo y asignar a cada emparejamiento una tripulación.

Un vuelo puede estar en varios emparejamientos. Si un vuelo está en varios emparejamientos

elegidos tendrá asignadas varias tripulaciones una tendrá la responsabilidad del vuelo y las

demás serán simplemente transportandas.

Este problema es un caso particular de recubrimiento de conjuntos visto arriba.

Al problema se le pueden añadir restricciones adicionales como la longitud máxima de un

emparejamiento, un tiempo mínimo entre un vuelo y el siguiente, etc. Estas se pueden tener en

cuenta filtrando la lista original de emparejamientos permitidos.

Problema de Empaquetado en Contenedores (Bin_Packing)

Page 10: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

10 Introducción a la Programación

El problema se formula de la siguiente manera: Dado un conjunto de contenedores S de tamaño

V y una lista de n elementos con tamaños ai encontrar el mínimo número de contenedores

necesarios para empaquetar todos los elementos.

Escogiendo las variables binarias xij que toman valor 1 si el elemento j es empaquetado en el

bin i y las variables yj tomando el valor 1 si el contenedor j es usado el problema puede ser

formulado como:

min ∑ 𝑦𝑗

𝑛−1

𝑗=0

∑ 𝑎𝑗𝑥𝑖𝑗 ≤ 𝑉𝑦𝑖 , 𝑖 = 0, … , 𝑛 − 1

𝑛−1

𝑗=0

∑ 𝑥𝑖𝑗 = 1, 𝑗 = 0, … , 𝑛 − 1

𝑛−1

𝑖=0

𝑏𝑖𝑛 𝑦𝑗, 𝑥𝑖𝑗, 𝑖, 𝑗 = 0, … , 𝑛 − 1

Coloreado de Grafos

El Problema de Coloreado de Grafos consiste en buscar el mínimo número de colores tal que

dando un color a cada vértice sea distinto el color asociado a dos vértices vecinos. Para

modelarlo como un Problema de Programación Lineal Entera partimos de las variables binarias

𝑦𝑘 , 𝑘 ∈ [0, 𝑛), que tomarán el valor 1 si el color 𝑘 es usado y 𝑛 es el número de vértices del

grafo. Además introducimos las variables binarias 𝑥𝑖𝑘 que serán 1 si el vértice 𝑖 se le asigna el

color 𝑘. El modelo del problema es:

min ∑ 𝑦𝑘

𝑛−1

𝑘=0

∑ 𝑥𝑖𝑘 = 1, 𝑖 = 0, … , 𝑛 − 1

𝑛−1

𝑘=0

𝑥𝑖𝑘 − 𝑦𝑘 ≤ 0, 𝑖, 𝑘 = 0, … , 𝑛 − 1

𝑥𝑖𝑘 + 𝑥𝑗𝑘 ≤ 1, (𝑖, 𝑗) ∈ 𝐸, 𝑘 = 0, … , 𝑛 − 1

𝑏𝑖𝑛 𝑥𝑖𝑘 , 𝑦𝑘 , 𝑖, 𝑘 = 0, … , 𝑛 − 1

Las restricción (1) garantiza que cada vértice tiene color y solo uno. Las restricción (2) el vértice

𝑖 recibe de color 𝑘. La restricción (3) que si los vértices 𝑖, 𝑗 son vecinos no pueden tener el mismo

color.

La restricción 𝑎 − 𝑏 ≤ 0, asumiendo que las variables toman valores binarios tiene como

soluciones posibles para (𝑎, 𝑏) los pares {(0,0), (0,1), (1,1)} y por lo tanto si 𝑎 = 1 implica que

𝑏 = 1.

Page 11: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

11 16. Algoritmos iterativos de aproximación

La restricción 𝑎 + 𝑏 ≤ 1, asumiendo que las variables toman valores binarios tiene como

soluciones posibles para (𝑎, 𝑏) los pares {(0,0), (0,1), (1,0)} y por lo tanto una de las dos

variables toma valor 1 o ninguna de de ellas pero no las dos a la vez.

Problema del Viajante

EL Problema del Viajante (o TSP sus siglas en inglés responde a la siguiente pregunta: Dada una

lista de ciudades y las distancias entre cada par de ellas, ¿cuál es la ruta más corta posible que

visita cada ciudad exactamente una vez y regresa a la ciudad origen? Este problema se

representa en general coomo un grafo no dirigido con pesos en las aristas y vértices que

representan las ciudades.

Este problema se puede ser formular como uno de Progrmación Lineal Entera. Para ello sean

las variables binarias 𝑥𝑖𝑗 , 𝑖, 𝑗 = 0, … , 𝑛, siendo 𝑛 + 1 el número de vértices del grafo, que

tomarán el valor 1 si el camino incluye la arista que va de 𝑖 a 𝑗 y 0 en otro caso. Sea 𝑐𝑖𝑗 la distancia

desde la ciudad 𝑖 a la ciudad 𝑗. Sean, además, las variables enteras 𝑢𝑖. Entonces el modelo de

programación lineal entera puede ser escrito como:

𝑚𝑖𝑛 ∑ ∑ 𝑐𝑖𝑗𝑥𝑖𝑗

𝑛

𝑗=0,𝑗≠𝑖

𝑛

𝑖=0

∑ 𝑥𝑖𝑗 = 1, 𝑗 = 0, … , 𝑛

𝑛

𝑖=0,𝑖≠𝑗

∑ 𝑥𝑖𝑗 = 1, 𝑖 = 0, … , 𝑛

𝑛

𝑗=0,𝑗≠𝑖

𝑢𝑖 − 𝑢𝑗 + 𝑛𝑥𝑖𝑗 ≤ 𝑛 − 1, 1 ≤ 𝑖 ≠ 𝑗 ≤ 𝑛

𝑏𝑖𝑛 𝑥𝑖𝑗 , 𝑖, 𝑗 = 0, … , 𝑛

𝑖𝑛𝑡 𝑢𝑖, 𝑖 = 0, … , 𝑛

El problema se simplifica eliminando las variables 𝑥𝑖𝑗 para las que no exista una arista en el grafo.

El primer y segundo conjunto de igualdades aseguran que para cada ciudad en el camino elegido

hay una y una soal ciudad anterior y otra posterior. Siempre que existan valores para las

variables enteras ui la última restricción obliga a que un solo camino cubra todas las ciudades y

no dos o más caminos disjuntos.

Para justificar la última restricción mostramos que para cada recorrido que cubre todas las

ciudades hay valores de las variables ui que satisfacen las restricciones. En un recorrido solución

etiquetemos la primera ciudad con 0. Sea ui = t si la ciudad 𝑖 es visitada en el paso 𝑡 (i, t =

1,2, … n). Por tanto 𝑢𝑖 − 𝑢𝑗 ≤ 𝑛 − 1 dado que 𝑢𝑖 no puede ser mayor que 𝑛 y 𝑢𝑗 no puede ser

menor que 1. La última restricción se satisface siempre que 𝑥𝑖𝑗 = 0 como se puede comprobar.

Si 𝑥𝑖𝑗 = 1 también se cumple ya que 𝑢𝑖 − 𝑢𝑗 + 𝑛𝑥𝑖𝑗 = 𝑡 − (𝑡 + 1) + 𝑛 = 𝑛 − 1.

Page 12: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

12 Introducción a la Programación

Por otra parte la última restricción asegura que las aristas elegidas forman una única secuencia

de ciudades y no varias secuencias disjuntas. Para ello es sufiente mostrar que cada solución

pasa por la ciudad 0. En efecto sumando las desigualdades 𝑢𝑖 − 𝑢𝑗 + 𝑛𝑥𝑖𝑗 ≤ 𝑛 − 1 a lo largo de

una subruta cerrada de 𝑘 pasos que no pase por la ciudad 0 (por lo tanto 𝑥𝑖𝑗 = 1) resulta 𝑛𝑘 ≤

(𝑛 − 1)𝑘 que es una contradicción.

Problema de las Reinas

El problema consiste en colocar 𝑛 reinas en un tablero de ajedrez 𝑛 × 𝑛 de tal manera que

ninguna de ellas amenace a ninguna de las demás. Una reina amenaza a los cuadrados de la

misma fila, de la misma columna y de las mismas diagonales. Las filas y columnas toman valores

en 0. . 𝑛 − 1.

Escogiendo las variables binarias 𝑥𝑖𝑗 que toman valor 1 si ublicamos una reina en la casilla 𝑖, 𝑗 el

problema puede ser formulado como:

∑ 𝑥𝑖𝑗 = 1, 𝑗 = 0, … , 𝑛 − 1

𝑛−1

𝑖=0

∑ 𝑥𝑖𝑗 = 1, 𝑖 = 0, … , 𝑛 − 1

𝑛−1

𝑗=0

∑ 𝑥𝑖𝑗 ≤ 1, 𝑑1 = −(𝑛 − 1), … , 𝑛 − 1(𝑖,𝑗):𝜑1(𝑑1)

∑ 𝑥𝑖𝑗 ≤ 1, 𝑑2 = 0, … ,2𝑛 − 2

(𝑖,𝑗):𝜑2(𝑑2)

𝑏𝑖𝑛 𝑥𝑖𝑗 , 𝑖, 𝑗 = 0, … , 𝑛 − 1

Dónde 𝜑1(𝑑1), 𝜑2(𝑑2) son los conjuntos de casillas (pares de índices) asociados a la diagonal

principal 𝑑1 y a la diagonal secundaria 𝑑2 respectivamente. Con más detalle:

𝜑1(𝑑1) = {(𝑖, 𝑗)|𝑗 − 𝑖 = 𝑑1 ∧ 𝑖 ∈ [0. . 𝑛 − 1] ∧ 𝑗 ∈ [0. . 𝑛 − 1]}

𝜑2(𝑑2) = {(𝑖, 𝑗)|𝑗 + 𝑖 = 𝑑2 ∧ 𝑖 ∈ [0. . 𝑛 − 1] ∧ 𝑗 ∈ [0. . 𝑛 − 1]}

En este problema no se trata de encontrar un mínimo. Se trata de encontrar una solución y

puede haber muchas.

El problema puede ser modelado alternativamente usando las variables enteras 𝑥𝑖, 𝑖: [0, 𝑛 −

1] y las restricciones:

𝑎𝑙𝑙𝐷𝑖𝑓𝑓𝑒𝑟𝑒𝑛𝑡(𝑥0, … , 𝑥𝑛−1)

𝑎𝑙𝑙𝐷𝑖𝑓𝑓𝑒𝑟𝑒𝑛𝑡(𝑥0,𝑥1 − 1, … , 𝑥𝑛−1 − 𝑛 − 1)

𝑎𝑙𝑙𝐷𝑖𝑓𝑓𝑒𝑟𝑒𝑛𝑡(𝑥0,𝑥1 + 1, … , 𝑥𝑛−1 + 𝑛 − 1)

𝑥𝑖 < 𝑛, 𝑖: [0, 𝑛 − 1]𝑖𝑛𝑡 𝑥𝑖, 𝑖: [0, 𝑛 − 1]

Page 13: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

13 16. Algoritmos iterativos de aproximación

Veremos más adelante como implementar la restricción 𝑎𝑙𝑙𝐷𝑖𝑓𝑓𝑒𝑟𝑒𝑛𝑡(𝑥0, … , 𝑥𝑛−1).

Problema del Sudoku

El problema consiste en rellenar con los enteros [1. . 𝑛] las casillas de un tablero 𝑛 × 𝑛 de tal

manera que cada fila, cada columna y cada subtabla tenga todos los enteros [1. . 𝑛] y una sola

vez cada uno de ellos. Siendo 𝑛 = 𝑚𝑘 con 𝑘 el tamaño de cada subtabla, 𝑚 el número de

subtablas en una fila y 𝑚2 el número de subtablas. A su vez 𝑛 = 𝑓 ∗ 𝑐 con 𝑓, 𝑐 el número de filas

y columnas respectivamente. A cada casilla le podemos asignar las coordenadas 𝑖, 𝑗 que toman

valores en 0. . 𝑛 − 1, siendo la casilla (0,0) la inferior izquierda. A cada subtablas le asociamos

el índice 𝑡 que toma valores en 0. . 𝑛 − 1 y se cumple 𝑡 = (𝑗

𝑘) 𝑘 + 𝑖/𝑘 siendo / la división entera.

Por ejemplo para (𝑖, 𝑗) = (2,4), 𝑛 = 9, 𝑘 = 3 tenemos 𝑡 = (4

3) 3 +

2

3= 3. Concretemos el

problema para 𝑛 = 9.

Sea 𝜑(𝑡) = {(𝑖, 𝑗)|𝑡 = 𝑡 = (𝑗

𝑘) 𝑘 + 𝑖/𝑘} y escogiendo las variables binarias 𝑥𝑖𝑗𝑣 que toman

valor 1 si la casilla 𝑖, 𝑗 toma el valor 𝑣 el problema puede ser formulado como:

∑ 𝑥𝑖𝑗𝑣 = 1, 𝑗, 𝑣 = 0, … , 𝑛 − 1

𝑛−1

𝑖=0

∑ 𝑥𝑖𝑗𝑣 = 1, 𝑖, 𝑣 = 0, … , 𝑛 − 1

𝑛−1

𝑗=0

∑ 𝑥𝑖𝑗𝑣 = 1, 𝑡, 𝑣 = 0, … , 𝑛 − 1(𝑖,𝑗):𝜑(𝑡)

𝑏𝑖𝑛 𝑥𝑖𝑗𝑣 , 𝑖, 𝑗, 𝑣 = 0, … , 𝑛 − 1

La primera restricción indica que un valor 𝑣, sólo puede aparece una vez en la fila 𝑗. La segunda

restricción que un valor 𝑣 sólo puede aparece una vez en la columna 𝑖. La tercera restricción

indica que un valor 𝑣 sólo puede aparece una vez en la subtabla 𝑡.

En este problema no se trata de encontrar un mínimo. Se trata de encontrar una solución y

puede haber muchas.

Modelar el problema usando la restricción 𝑎𝑙𝑙𝐷𝑖𝑓𝑓𝑒𝑟𝑒𝑛𝑡(𝑥0, … , 𝑥𝑛−1) se deja como ejercicio.

Problema de Tareas y Procesadores

El problema se formula de la siguiente manera: Dado una lista de 𝑚 tareas con duraciones 𝑑𝑗 y

un conjunto de 𝑛 procesadores buscar la asignación de tareas a procesadores tal que el tiempo

toal de ejecución sea mínimo.

Escogiendo las variables binarias 𝑥𝑖𝑗 que toman valor 1 si la tarea 𝑗 es asignada al procesador 𝑖

el problema puede ser formulado como:

Page 14: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

14 Introducción a la Programación

min 𝑇

∑ 𝑑𝑗𝑥𝑖𝑗 ≤ 𝑇, 𝑖 = 0, … , 𝑛 − 1

𝑚−1

𝑗=0

∑ 𝑥𝑖𝑗 = 1, 𝑗 = 0, … , 𝑚 − 1

𝑛−1

𝑖=0

𝑏𝑖𝑛 𝑥𝑖𝑗, 𝑖 = 0, … , 𝑛 − 1, 𝑗 = 0, … , 𝑚 − 1

Planificación

El problema se define por un conjunto tareas 𝑗: {1. . 𝑛}, y un conjunto de medios (máquinas)

𝑖: {1. . 𝑚}. Cada tarea 𝑗 tiene que ser asignada a una máquina 𝑖 dónde consume un tiempo de

procesamiento 𝑝𝑖𝑗 y recursos a una tasa de 𝑐𝑖𝑗. Cada tarea tiene una fecha de lanzamiento 𝑟𝑗 y

un tiempo de finalización 𝑑𝑗. Además cada tarea j asignada a la máquina i debe comenzar en un

tiempo 𝑠𝑗 tal que, cumpliendo las restricciones anteriores, la tasa de consumo de recursos en la

máquina i nunca sea mayor que 𝐶𝑖 en cualquier punto del tiempo. Para modelar el problema

discretizamos el tiempo, definimos la variable 𝑡: {0. . 𝑁} y las variables binarias 𝑥𝑖𝑗𝑡 que tomarán

valor 1 si la tarea 𝑗 comienza a ejecutarse en la máquina 𝑖 en el tiempo t.

Este es un problema complejo con muchas variantes del cual sólo daremos aquí algunas ideas.

Como hemos dicho antes se debe cumplir una primera restricción que es:

𝑠𝑗 ≥ 𝑟𝑗, 𝑗: [1. . 𝑛]

Una segunda restricción es que las tareas acaben antes de tiempo de finalización indicado. Pero

esta restricción la vamos a considerar como una restricción blanda. Es decir, vamos a quitarla

como restricción y establecer como objetivo minimizar la demora total. Es decir, la suma de los

tiempos en que se ha sobrepasado el tiempo de finalización para cada tarea. Usaremos las

variables 𝑇𝑗 ≥ 0 que deben cumplir:

𝑇𝑗 ≥ 𝑠𝑗 + 𝑝′𝑗 − 𝑑𝑗, 𝑗: 1. . 𝑛

Dónde 𝑝′𝑗 es el tiempo de ejecución de la tarea 𝑗 asumiendo conocía la máquina en la que se

ejecutará. Que podemos reescribir como:

𝑇𝑗 ≥ ∑ (𝑡 + 𝑝𝑖𝑗)𝑥𝑖𝑗𝑡

𝑖:1..𝑚

− 𝑑𝑗, 𝑗: 1. . 𝑛, 𝑡: 1. . 𝑁

Para comprender lo anterior debemos tener en cuenta que cada tarea 𝑗 empieza en un único

punto del tiempo 𝑡 en la máquina 𝑖 y por lo tanto la variable 𝑥𝑖𝑗𝑡 toma el valor 1 sólo para esa

combinación de valores para una tarea dada. Por lo tanto:

Page 15: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

15 16. Algoritmos iterativos de aproximación

𝑠𝑗 = ∑ 𝑡𝑥𝑖𝑗𝑡

𝑖:1..𝑚

, 𝑗: 1. . 𝑛, 𝑡: 1. . 𝑁

𝑝′𝑗 = ∑ 𝑝𝑖𝑗𝑥𝑖𝑗𝑡

𝑖:1..𝑚

, 𝑗: 1. . 𝑛, 𝑡: 1. . 𝑁

Ahora la función objetivo es 𝑔(𝑥, 𝑠) = ∑ 𝑇𝑗𝑗 .

Un segundo objetivo podría ser minimizar el número de tareas que acaban tarde. Para ello

usamos las variables binarias 𝐿𝑗 que deben ser 1 si la tarea 𝑗 acaba tarde. Es decir si 𝑠𝑗 + 𝑝𝑖𝑗 >

𝑑𝑗. Por lo tanto debemos incluir entre las restricciones la implicación 𝑠𝑗 + 𝑝𝑖𝑗 > 𝑑𝑗 → 𝐿𝑗 = 1.

Esto se puede conseguir mediante:

𝑁𝐿𝑗 ≥ ∑ (𝑡 + 𝑝𝑖𝑗)𝑥𝑖𝑗𝑡

𝑖:1..𝑚

− 𝑑𝑗, 𝑗: 1. . 𝑛, 𝑡: 1. . 𝑁

La suma de las variables 𝐿𝑗 será el objetivo a minimizar. Es decir 𝑔(𝑥, 𝑠) = ∑ 𝐿𝑗𝑗 .

Sumando sobre los subconjuntos apropiados de estas variables podemos establecer las

restricciones del problema.

min ∑ 𝑇𝑗

𝑗:1..𝑛

𝑇𝑗 ≥ ∑ (𝑡 + 𝑝𝑖𝑗)𝑥𝑖𝑗𝑡

𝑖:1..𝑚

− 𝑑𝑗 , 𝑗: 1. . 𝑛, 𝑡: 1. . 𝑁

∑ ∑ 𝑥𝑖𝑗𝑡 = 1, 𝑗: 1. . 𝑛𝑁

𝑡=1

𝑚

𝑖=1

∑ ∑ 𝑐𝑖𝑗𝑥𝑖𝑗𝑠

𝑠:𝑇𝑖𝑗𝑡𝑗:1..𝑛

≤ 𝐶𝑖, 𝑖: 1. . 𝑚, 𝑡: 1. . 𝑁

𝑥𝑖𝑗𝑡 = 0, 𝑗: 1. . 𝑛, 𝑖: 1. . 𝑚, 𝑡: 𝑇

𝑏𝑖𝑛 𝑥𝑖𝑗𝑡 , 𝑗: 1. . 𝑛, 𝑖: 1. . 𝑚, 𝑡: 1. . 𝑁

Siendo 𝑇𝑖𝑗𝑡 = {𝑡′: 1. . 𝑁|𝑡 − 𝑝𝑖𝑗 < 𝑡′ ≤ 𝑡}, 𝑇 = {𝑡′: 1. . 𝑁|𝑡′ < 𝑟𝑗 ∨ 𝑡′ > 𝑁 − 𝑝𝑖𝑗}. Como

podemos ver 𝑇𝑖𝑗𝑡 es la ventana de tiempo anterior a 𝑡 en los cuales la tarea 𝑗 puede haber

empezado a ejecutarse en la máquina 𝑖. Y 𝑇 en el conjunto que incluye los instantes de tiempo

en los cuales la tarea no puede empezar, ya que son anteriores al tiempo de lanzamiento rj, o

que acabarían después del horizonte de tiempo especificado.

Como hemos dicho las variables 𝑇𝑗 representan el tiempo en que la tarea 𝑗 ha superado el

establecido para finalizar 𝑑𝑗. La primera restricción establece eso. La segunda indica que una

tarea empieza en un único instante del tiempo en una máquina dada. La tercera que los recursos

necesarios en la máquina 𝑖 son menores que los disponibles en cada instante del tiempo. La

cuarta que cada tarea no puede empezar antes de 𝑟𝑗 o después de 𝑁 − 𝑝𝑖𝑗 .

O para minimizar el número de tareas que acaban tarde sustituimos la función objetivo y la

primera restricción por:

Page 16: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

16 Introducción a la Programación

min ∑ 𝐿𝑗

𝑗:1..𝑛

𝑁𝐿𝑗 ≥ ∑ (𝑡 + 𝑝𝑖𝑗)𝑥𝑖𝑗𝑡

𝑖:1..𝑚

− 𝑑𝑗, 𝑗: 1. . 𝑛, 𝑡: 1. . 𝑁

Y declaramos las variables 𝐿𝑗 como binarias.

La máquina en la que se ejecuta una tarea 𝑗 podemos asociarla a la variable 𝑦𝑗 de la forma:

𝑦𝑗 = ∑ 𝑖𝑥𝑖𝑗𝑡

𝑖,𝑡

La restricción de que dos tareas 𝑞, 𝑘 sean asignadas a la máquina 𝑖 y exista una precedencia

entre ambas puede modelarse mediante las restricciones:

𝑦𝑞 = 𝑦𝑘

𝑠𝑞 + 𝑝𝑖𝑞 ≤ 𝑠𝑘 , 𝑖: [1. . 𝑚]

2.2 Algunas técnicas útiles en los modelos de Programación Lineal Entera

Aquí recogemos algunas técnicas conocidas para construir modelos de Programación Lineal

Entera.

Valor absoluto

El valor absoluto de una variable |𝑥| puede ser eliminado en un modelo de Programación Lineal

Entera, con las nuevas variables y restricciones:

𝑥 = 𝑎 − 𝑏|𝑥| = 𝑎 + 𝑏

Eso es adecuado asumiendo que una de las dos variables (𝑎, 𝑏), que tienen que ser ambas mayor

o igual que cero, debe ser cero.

Para conseguirlo, y asumiendo que 𝐿 ≤ 𝑥 ≤ 𝑈, 𝐿 ≤ 0 ≤ 𝑈, podemos escribir:

𝑥 = 𝑎 − 𝑏|𝑥| = 𝑎 + 𝑏

𝑎 ≤ 𝑈𝑦𝑏 ≤ |𝐿|(1 − 𝑦)

𝑏𝑖𝑛 𝑦

Podemos ver que si 𝑦 = 1 resulta 𝑎 ≤ 𝑈, 𝑏 = 0 y si 𝑦 = 0 entonces 𝑎 = 0, 𝑏 ≤ |𝐿|

Variables semicontinuas

Son variables que cumplen:

𝑥 = 0 ∨ 𝑎 ≤ 𝑥 ≤ 𝑏

Page 17: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

17 16. Algoritmos iterativos de aproximación

Pueden ser modeladas como:

𝑥 ≥ 𝑎𝑦𝑥 ≤ 𝑏𝑦𝑏𝑖𝑛 𝑦

Están disponibles directamente en entornos como LPSolve.

Special Ordered Sets

Restricciones de tipo 𝑘 son un tipo especial de restricciones entre una lista de n variables que

obligan a que justamente 𝑘 varaibles contiguas de las lista sean distintas de cero. Un caso

particular es para 𝑘 = 1.

Están disponibles en en entornos como LPSolve.

Restricciones combinadas con el operador or

Sean las 𝑚 restricciones como:

𝑔1(𝑥) ≥ 0…

𝑔𝑚(𝑥) ≥ 0

De las que queremos que se satisfagan algunas de ellas y liberar el resto. Esto lo podemos

modelar con las siguientes restricciones ampliadas:

𝑔1(𝑥) + 𝐿1(1 − 𝑦1) ≥ 0…

𝑔𝑚(𝑥) + 𝐿𝑚(1 − 𝑦𝑚) ≥ 0𝑦1 + ⋯ + 𝑦𝑚 ≥ 𝑘𝑏𝑖𝑛 𝑦𝑖 , 𝑖: [1, 𝑚]

Dónde 𝐿𝑖 es un valor positivo tal que -𝐿𝑖 es una cota inferior de la expresión 𝑔𝑖(𝑥) en el contexto

de todas las demás restricciones, es decir que 𝑔𝑖(𝑥) ≥ −𝐿𝑖 siempre es válido. Las variables 𝑦𝑖

son variables binarias que cuando toman valor 0 liberan la restricción correspondiente y cuando

toman valor 1 obligan a que se cumpla. Estableciendo restricciones adicional sobre la suma de

las 𝑦𝑖 podemos indicar cuantas restricciones deben satisfacerse o cuantas pueden quedar

liberadas. Con la última restricción indicamos que se deben satisfacer al menos 𝑘 de ellas.

Claramente si asociamos la misma variable binaria a varias restricciones éstas serán liberadas u

obligadas a que se cumplan a la vez.

Podemos, además, establecer relaciones lógicas entre las restricciones que se satisfacen. La

restricción adicional 𝑦𝑟 − 𝑦𝑠 ≤ 0, como vimos más arriba, hace que si 𝑦𝑟 = 1 entonces 𝑦𝑠 = 1.

Es decir que si se cumple 𝑔𝑟(𝑥) ≥ 0 también se debe cumplir 𝑔𝑠(𝑥) ≥ 0 y por lo tanto hay una

relación de implicación entre ambas. Si junto a la anterior añadimos 𝑦𝑠 − 𝑦𝑟 ≤ 0 entonces la

implicación se convierte en sí y sólo si. Es decir 𝑔𝑟(𝑥) ≥ 0, 𝑔𝑠(𝑥) ≥ 0 deben ser ambas

verdaderas o estar liberadas.

La restricción de doble implicación anterior puede ser usada para modelar variables indicadoras

que son variables binarias que toman el valor 1 si y sólo si alguna otra restricción se satisface.

Page 18: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

18 Introducción a la Programación

Variables indicadoras, asociadas a la restricción 𝑔𝑟(𝑥) ≥ 0, pueden modelararse con las ideas

anteriores haciendo que 𝑔𝑠(𝑥) ≥ 0 sea de la forma 𝑢 − 1 ≥ 0 y 𝑢 binaria.

La restricción adicional 𝑦𝑢 + 𝑦𝑣 ≤ 1 escoge una de las dos o ninguna pero no las dos a la vez.

Modelado del producto de variables

En algunos casos es interesante usar el producto de dos varaibles en los modelos que deber

estar formados por restricciones lineales. Veamos como hacerlo.

Si tenemos las variables binarias 𝑥1, 𝑥2 su producto, 𝑦 = 𝑥1𝑥2, puede ser sustituido por las

restricciones:

𝑦 ≤ 𝑥1

𝑦 ≤ 𝑥2

𝑦 ≥ 𝑥1 + 𝑥2 − 1𝑏𝑖𝑛 𝑦

Si tenemos la variable binaria 𝑥1 y la real 𝑥2 y asumiendo que 0 ≤ 𝑥2 ≤ 𝑢 entonces su producto,

𝑦 = 𝑥1𝑥2, puede ser sustituido por las restricciones:

𝑦 ≤ 𝑢𝑥1

𝑦 ≤ 𝑥2

𝑦 ≥ 𝑥2 − 𝑢(1 − 𝑥1)

Si ambas variables son reales, el producto también se puede siguiendo las ideas anteriores, pero

no lo vamos a ver aquí.

Modelo de la restricción allDifferent y permutaciones de un conjunto

Sean las variables 𝑖, 𝑖: [1. . 𝑛] que toma valores enteros en un conjunto finito de enteros 𝜑 tal

que |𝜑| = 𝑚 ≥ 𝑛 y queremos modelar la restricción:

𝑎𝑙𝑙𝐷𝑖𝑓𝑓𝑒𝑟𝑒𝑛𝑡(𝑥1, … , 𝑥𝑛, 𝜑) ≡ 𝑥1 ≠ 𝑥2 ≠ ⋯ ≠ 𝑥𝑛

Para ello usamos las variables binarias 𝑦𝑖𝑣 , 𝑖: [𝑖. . 𝑛], 𝑣: 𝜑 que toma el valor 1 si la variable 𝑥𝑖

toma el valor 𝑣. Las restricciones equivalentes son:

∑ 𝑦𝑖𝑣 ≤ 1, 𝑣: 𝜑

𝑛

𝑖=1

∑ 𝑦𝑖𝑣

𝑣:𝜑

= 1, 𝑖 = 1 … 𝑛

𝑥𝑖 = ∑ 𝑣𝑦𝑖𝑣

𝑣:𝜑

, 𝑖 = 1 … 𝑛

Page 19: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

19 16. Algoritmos iterativos de aproximación

La primera restricción indica que para cada valor puede haber una variable como máximo que

lo tenga. Si 𝑚 = 𝑛 entonces eta restrcción se convierte en una igualdad. La segunda restricción

indica que cada variable tiene un solo valor. La tercera indica que cada variable tiene el valor

entero adecuado. Un caso concreto es cuando 𝜑 = {𝑧|1 ≤ 𝑧 ≤ 𝑛}.

Podemos ver que cada uno de los valores posibles de la lista de variables (𝑥1, 𝑥2, … , 𝑥𝑛) es una

permutación de un subconjunto de 𝜑 o de 𝜑 completo si 𝑚 = 𝑛.

La tercera restricción también nos da pistas para modelar una variable entera que toma

solamente los valores en un conjunto 𝜑. Para ello es suficiente con usar variables binarias

𝑦𝑣 , 𝑣: 𝜑 que toma el valor 1 si la variable 𝑥 toma el valor 𝑣. Las restricciones asociadas son:

∑ 𝑦𝑣

𝑣:𝜑

= 1

𝑥 = ∑ 𝑣𝑦𝑣

𝑣:𝜑

2.3 Complejidad de los problemas de Programación Lineal Entera

La complejidad de los problemas de Programación Lineal y los de Programación Lineal Entera es

muy diferente.

Los problemas de Programación Lineal (PL) suelen resolverse por el algoritmo del Simplex que,

aunque no sea teóricamente polinómico en el caso peor, en la práctica se comporta como

polinómico en la mayoría de los casos de interés.

Si a las soluciones de un problema lineal les exigimos que sean enteras, nos encontramos con

un problema de Programación Lineal Entera (PLE). Este problema es NP-duro, concepto que no

abordaremos aquí, que indica que su complejidad es más alta que la polinomial y por lo tanto

hace imposible la obtención de soluciones exactas para problemas de tamaños grandes. Los

algoritmos que se utilizan para resolver este problema suelen comenzar relajando las

restricciones del problema para convertirlo en un Problema de Programación Lineal y

posteriormente utilizar técnicas de Ramifica y Poda para encontrar la solución entera exacta.

2.4 Programación Lineal Entera. Detalles de Implementación

Para resolver el problema disponemos de un algoritmo para buscar las soluciones:

AlgoritmoPLI. Que implementa un algoritmo de Programación Lineal Entera reutilizando

las librerías de LpSolve.

Algoritmos. La factoría anterior dispone de los métodos siguientes:

Page 20: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

20 Introducción a la Programación

public static AlgoritmoPLI createPLI(String fichero) {

return AlgoritmoPLI.create(fichero);

}

El segundo método toma un fichero de entrada escrito en el formato adecuado para ser

procesado por LpSolve e instancia un algoritmo para resolverlo. El formato de este tipo de

fichero puede verse en formato LpSolve.

Por lo tanto para resolver un problema debemos cosntruir el fichero que lo describe en primer

lugar. Para problemas de tamaño grande es conveniente generar el fichero automáticamente.

El código para generar el fichero que resuelve el problema de las Reinas puede encontrarse aquí.

El programa principal para este problema puede encontrarse aquí.

Para hacer más fácil el código el algoritmo AlgoritmoPLI proporciona algunos métodos para

generar el nombre de variables indexadas, sumatorios de ese tipo de variables, etc. Algunos

métodos son:

AlgoritmoPLI create(String fichero);

String getName(int i);

List<String> getNames();

Integer getNumVar();

Double getObjetivo();

Double[] getSolucion();

String getVariable(String name, int i, int j);

String getVariable(java.lang.String name, int i, int j, int k);

String intVariables(java.lang.String name, int i1, int i2);

3. Algoritmos aleatorios y optimización

3.1 Introducción

La técnica de Programación Lineal Entera es muy versátil y puede ser usada para modelar y

resolver un amplio abanico de problemas de optimización. Pero tiene tiene algunos

inconvenientes. El primero es que los modelos deben estar formulados mediante restricciones

lineales combinadas con el operador and y por el operador or. Los problemas que requieren

restricciones no lineales no pueden ser modelos mediante esta técnica. Existen metodologías

más potentes que pueden tener en cuenta esas restricciones no lineales pero no las veremos en

este curso. El segundo es que los algoritmos que resuelven los modelos de Programación Lineal

entera si aparecen muchos operadores or explícita o implícitamente tienen una complejidad

mayor que polinomial. Esto los hace intratatables y por lo tanto encontrar una solución exacta

al problema planteado es inabordable en la mayoría de los casos.

El enfoque para resolver este problema es buscar soluciones aproximadas y renunciar de forma

general a encontrar la solución exacta. Este enfoque tiene dos vías. La primera es relajar el

problema de Programación Lineal Entera a otro de Programación Lineal eliminando el carácter

entero o binario de las variables y declarándolas todas reales. El Problema de Programación

Page 21: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

21 16. Algoritmos iterativos de aproximación

Lineal se puede resolver mediante el algoritmo del Simplex que tiene complejidad polinomial y

es muy eficiente para la inmesa mayoría de problemas. Pero la solución al problema relajado es

una aproximación que después puede ser mejorada. Una manera de mejorar la solución es la

t´ncia aleatoria conocida como Búsqueda Tabú

La segunda vía, que puede ser complementaria a la anterior, es usar directamente algoritmos

aleatorios para buscar una solución aproximada del problema de optimización. Eso es lo que

vamos a ver ahora concretándonos en lso Algoritmos Genéticos y la técnica de Simulated

Annealing.

Veamos, en primer lugar, como caracterizar un problema de optimización y como transformarlo

a otro dónde las restricciones se pasan a la función objetivo.

3.2 Problemas de optimización

Los problemas que pretenden optimizar una función objetivo. Estos problemas pueden

escribirse de la forma:

min𝑥∈Ω

𝑓(𝑥)

Donde 𝑥 es un vector de 𝑛 variables y Ω un dominio dónde las variables deben tomar valores.

Los valores de que cumplen 𝑥 ∈ Ω los llamaremos valores válidos. Consideramos que la función

objetivo 𝑓 es una expresión que devuelve valores reales.

Los problemas de maximización pueden transformarse en problemas de minimización de la

forma:

max𝑥∈Ω

𝑓(𝑥) = min𝑥∈Ω

−𝑓(𝑥)

En general el dominio Ω se decribirá como un conjunto de restricciones. Las restricciones sulen

ser de los tipos:

𝑔(𝑥) ≤ 0

ℎ(𝑥) = 0𝑎 ≤ 𝑥 ≤ 𝑏

Dónde 𝑥, 𝑎, 𝑏 son vectores de valores. Las primeras son restricciones de desigualdad, las

segundas de igualdad y las últimas de rango.

En algunas de las técnicas de optimización es conveniente reducir el problema de optimización

a otro que sólo tenga restricciones de rango. Esto se puede hacer de la forma siguiente. Si Ω, el

conjunto de restricciones, es de la forma:

𝑔𝑖(𝑥) ≤ 0, 𝑖 = 1, … , 𝑟

ℎ𝑗(𝑥) = 0, 𝑗 = 1, … , 𝑠

𝑎 ≤ 𝑥 ≤ 𝑏

Page 22: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

22 Introducción a la Programación

Entonces el problema puede ser transformado de la forma:

min𝑥∈Ω

? = min𝑎≤𝑥≤𝑏

𝑇(𝑥) = 𝑚𝑖𝑛𝑎≤𝑥≤𝑏

∑(𝑐(𝑔𝑖(𝑥)))2 + ∑(ℎ𝑗(𝑥))2

𝑠

𝑗=1

𝑟

𝑖=1

Dónde 𝑐(𝑧) una función d ela forma:

𝑐(𝑧) = max (0, 𝑧) = {0, 𝑧 ≤ 0𝑧, 𝑧 > 0

Abordaremos también los llamados problemas multiobjetivo. En estos estos hay que optimizar

simultáneamente varios objetivos y por ello el problema es ahora de la forma:

(min𝑥∈Ω

𝑓1(𝑥), min𝑥∈Ω

𝑓2(𝑥), … , max𝑥∈Ω

𝑓𝑚−1(𝑥), max𝑥∈Ω

𝑓𝑚(𝑥))

Que cambinado los signos adecaudamente se puede transformar en:

min𝑥∈Ω

(𝑓1(𝑥), 𝑓2(𝑥) … , −𝑓𝑚−1(𝑥), −𝑓𝑚(𝑥)) = min𝑥∈Ω

(𝑔1(𝑥), 𝑔2(𝑥) … , 𝑔𝑚−1(𝑥), 𝑔𝑚(𝑥))

Este problema puede ser reducido a un problema uniobjetivo de la forma:

min𝑥∈Ω

∑ 𝜔𝑖𝑔𝑖(𝑥)

𝑚

𝑖=1

, 𝜔𝑖 > 0

Donde el valor relativo de las 𝜔𝑖 indicará la prioridad del objetivo correspondiente.

Las restricciones Ω de un problema pueden ser introducidas en la función objetivo introduciendo

un primer objetivo de minimización más prioritario que los demás de la forma:

(min𝑥∈Ω

𝑓1(𝑥), … , max𝑥∈Ω

𝑓𝑚(𝑥)) = (min𝑥

𝑇(𝑥) , min𝑥

𝑓1(𝑥), … , max𝑥

𝑓𝑚(𝑥))

Algunas equivalencias son:

min𝑥

𝑓(𝑥)

𝑔𝑖(𝑥) ≤ 0, 𝑖 = 1, … , 𝑟

ℎ𝑗(𝑥) = 0, 𝑗 = 1, … , 𝑠

𝑎 ≤ 𝑥 ≤ 𝑏

≡ min𝑥

𝑓(𝑥) + 𝐾(∑(𝑐(𝑔𝑖(𝑥)))2 + ∑(ℎ𝑗(𝑥))2)

𝑠

𝑗=1

𝑟

𝑖=1

𝑎 ≤ 𝑥 ≤ 𝑏

Page 23: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

23 16. Algoritmos iterativos de aproximación

max𝑥

𝑓(𝑥)

𝑔𝑖(𝑥) ≤ 0, 𝑖 = 1, … , 𝑟

ℎ𝑗(𝑥) = 0, 𝑗 = 1, … , 𝑠

𝑎 ≤ 𝑥 ≤ 𝑏

≡ min𝑥

−𝑓(𝑥) + 𝐾(∑(𝑐(𝑔𝑖(𝑥)))2 + ∑(ℎ𝑗(𝑥))2)

𝑠

𝑗=1

𝑟

𝑖=1

𝑎 ≤ 𝑥 ≤ 𝑏

Con 𝐾 un valor suficientemente grande. De forma similar podemos obtener equivalencias que

maximicen una función objetivo que incluya la restricciones del problema.

3.3 Algoritmos probabilísticos

Los algoritmos genéticos (GA), simulated annealing (SA), y la búsqueda tabú (TS) son algoritmos

iterativos generales de optimización combinatoria. Son algoritmos probabilístico cuyo diseño

está inspirado en los mecanismos evolutivos que se encuentran en la naturaleza. Estos

algoritmos tienen muchas similitudes, pero también poseen características distintivas,

principalmente en sus estrategias para buscar en el espacio de estado de soluciones.

Los algortimos anteriores están orientados a resolver problemas de optimización. Un problema

de optimización, como hemos dicho antes, pretende buscar la solución 𝑥𝑜𝑝 que minimiza una

función objetivo 𝑔(𝑥) que toma valores en el conjunto de soluciones 𝑆 que cumplen las

restricciones Ω(𝑥). Así tenemos:

𝑆 = {𝑥: 𝑇|Ω(𝑥)}𝑥𝑜𝑝 = min

𝑥:𝑆𝑔(𝑥)

Dónde 𝑇 es el tipo de las soluciones del problema y, aunque hemos puesto min, podríamos

haber considerado max en la misma forma. Al conjunto 𝑆 se le suele llamar espacio de soluciones

del problema. En los algoritmos que vamos a considerar introducimos un espacio de valores 𝑉

y una función de decodificación 𝑑(𝑣) que toma valor en 𝑉 y devuelve otro en 𝑇. El espacio 𝑉 se

escoje para que su valores se puedan generar fácilmente aplicando pertubaciones aleatorias a

uno de ellos 𝑣0 o mediante mezclas aleatorias de pares de ellos (𝑣0, 𝑣1). Pasar del tipo 𝑇 al 𝑉

lo llamamos codificar y la revés decodificar. De forma general a las perturbaciones sobre un valor

los llamaremos operadores de mutación y a los segundos operadores de cruce. En los algoritmos

genéticos los valores del espacio de valores se le suele llamr cromosomas. Usaremos los mismos

términos en los tres algoritmos probabilísticos que vamos a considerar.

Asociada al conjunto de restricciones Ω(𝑥) asumimos la existencia de una función 𝑅(𝑥) que

toma valores reales positivos y que cumple Ω(𝑥) → 𝑅(𝑥) = 0, ! Ω(𝑥) → 𝑅(𝑥) > 0. Es decir si

©

V: Valores

S: Soluciones

𝑥𝑜𝑝: Mejor Solución

Page 24: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

24 Introducción a la Programación

se cumple las restricciones entonces 𝑅(𝑥) = 0 y si no se cumplen 𝑅(𝑥) > 0. Antes hemos visto

la forma de obtener esa función a partir de las restricciones. Ejemplos son:

Restricción Ω(𝑥) Función 𝑅(𝑥) equivalente

𝑔(𝑥) ≤ 0 (max(0, 𝑔(𝑥)))2

𝑔(𝑥) ≥ 0 (min(0, (𝑔(𝑥)))2

ℎ(𝑥) = 0 (ℎ(𝑥))2

Ω1(𝑥), … , Ω𝑛(𝑥) 𝐾1R1(𝑥) + ⋯ + 𝐾𝑛R𝑛(𝑥)

La última fila muestra que podemos asociar a la conjunción de varias restricciones una función,

con las propiedades anteriores, sumando las funciones correspondientes a cada restricción

indicidual multiplicada por una constante positiva.

Por último definiremos la función de fitness asociada al problema min𝑥∈Ω

𝑔(𝑥) como 𝑓(𝑣) =

𝑔(𝑑(𝑣)) + 𝐾 𝑅(𝑑(𝑣)). Dónde estamos considerando un problema de minimización y 𝐾 una

constante suficientemente grande. Esta función, como vemos, se define para cada valor (o

cromosoma) que incluye las restricciones del problema y que pretendemos minimizar.

Para resolver un problema mediante técnicas aleatorias tenemso que escoger un tipo de

cromosomas que genere el espacio de valores 𝑉. Pueden existir distintas tipos de cromosomas

adecuados. La mejor alternativa es aquella en la que el espacio de valores es de un tamaño

cercano al espacio de soluciones. Es decir el conjunto de soluciones inválidas obtenidas a partir

del conjunto de valores es lo más pequeño posible.

4. Un catálogo de tipos de cromosomas

Hay una amplia gama de problemas combinatorios que pueden ser abordados partiendo de un

catálogo de cromosomas cuyos operadores de cruce y mutación son conocidos y pueden ser

reutilizados. Este catálogo es útil en los algoritmos genéticos y las ideas pueden ser usadas en

simulated annealing que son las técnicas que veremos con más detalle. Veamso los tipos

adecuados para ser usados en los Algoritmos Genéticos.

Partimos del tipo genérico para construir los espacios de valores que llamaremos

Chromosome<T>:

public interface Chromosome<T> {

T decode();

double fitness();

}

T decode():Función de decodificación

double fitness():Función de fitness

Page 25: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

25 16. Algoritmos iterativos de aproximación

4.1 ValuesInRangeChromosome<E>

Representa una lista de valores de tipo E que están en un rango. Dispondremos de 3 subtipos:

BinaryChromosome, RangeChromosome y DoubleChromosome. Los detalles específicos para

cada uno de estos cromosomas se indicarán en una implementación del tipo

ValuesInRangeProblemAG<E,S>. Dónde E el el tipo de los elementos del cromosoma y S el tipo

de la solución del problema.

public interface ValuesInRangeProblemAG<E,S> extends ProblemaAG {

Double fitnessFunction(ValuesInRangeChromosome<E> cr);

E getMax(Integer i);

E getMin(Integer i);

Integer getVariableNumber();

S getSolucion(ValuesInRangeChromosome<E> cr)

}

Restricciones:

n = getVariableNumber();

d = decode();

d = decode.size();

getMin()<= d[i] <= getMax(), i:0..n-1;

4.1.1 BinaryChromosome

Este cromosoma es un caso particular del anterior donde los valores son enteros de mínimo 0 y

máximo 1. Es un cromosoma básico a partir del cual se pueden construir otros más complejos.

Los operadores de mutación son muy conocidos y consisten fundamentalmente en permutar el

valor binario de una casilla escogida al azar.

Los operadores de cruce son también ampliamentre conocidos y pueden consultarse en la

literatura.

Usos:

Este cromosoma es adecuado para modelar un amplio abanico de situaciones. Puede ser

considerado el cromosoma básico a partir del cual construir otros. Con él podemos modelar

todos los problemas de Programación Lineal Entera con variables binarias.

Ejemplo 1: Problema de la Asignación

En este problema tenemos una lista de agentes 𝐿 y una lista de tareas 𝑇 ambas del mismo

tamaño 𝑛. El coste de que el agente 𝑖 realice la tarea 𝑗 sea 𝑐𝑖𝑗 . Se pretende asignar a cada agente

una tarea y sólo una de tal forma que se ejecuten todas las tareas con el coste mínimo.

Page 26: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

26 Introducción a la Programación

Una primera versión del problema es hacer una implementación de la solución propuesta más

arriba mediante la técnica de la Programación Lineal Entera. En la solución asumimos las

variables binarias xij toman valor 1 si el agente i ejecuta la tarea j y cero si no la ejecuta. Decimos

que hemos codificado el problema mediante las variables binarias xij. La solución en

Programación Lineal Entera fue:

min ∑ 𝑥𝑖𝑗 𝑐𝑖𝑗

𝑛−1,𝑛−1

𝑖=0,𝑗=0

∑ 𝑥𝑖𝑗 = 1, 𝑖 ∈ [0, 𝑛 − 1]

𝑛−1

𝑗=0

∑ 𝑥𝑖𝑗 = 1, 𝑗 ∈ [0, 𝑛 − 1]

𝑛−1

𝑖=0

𝑏𝑖𝑛 𝑥𝑖𝑗, 𝑖 ∈ [0, 𝑛 − 1], 𝑗 ∈ [0, 𝑛 − 1]

El cromosoma BinaryChromosome dispone de un vector 𝑑, el resultado de la decodificación, que

debe contenedor todas la varaibles binarias en un total de 𝑛2 que será el tamaño del

cromosoma. Identificamos cada variable 𝑥𝑖𝑗 con una posición 𝑘 en el vector 𝑑 en la forma: 𝑥𝑖𝑗 =

𝑑[𝑘] si 𝑘 = 𝑛𝑖 + 𝑗. La función de fitnes debe tener en cuenta las restricciones tal como hemos

explicado arriba. Con todo ello la función de fitnes, teniendo en cuenta que los Algoritmos

Genéticos buscan el maximizar, puede ser:

𝑓 = − ( ∑ 𝑥𝑖𝑗 𝑐𝑖𝑗

𝑛−1,𝑛−1

𝑖=0,𝑗=0

) − 𝐾(∑(∑ 𝑥𝑖𝑗) − 1)^2 +

𝑛−1

𝑗=0

𝑛−1

𝑖=0

∑((∑ 𝑥𝑖𝑗) − 1)^2)

𝑛−1

𝑖=0

𝑛−1

𝑗=0

Hay otra forma mejor de resolver este problema como veremos más adelante con un cromosoma de otro tipo. La razón es que el porcentaje de valores de cromosomas que no son válidos (que no cumplen las restricciones) es muy alto. En efecto el número total variables es 𝑛2 y de valores posibles es

2𝑛2. Dadas las restricciones de igualdad el número de variables libres es 𝑛2 − 2𝑛 y el total de

valores válidos, que cumplen lass restricciones, es 2𝑛2−2𝑛. El cociente nos da la probabilidad de encontrar un valor válido al azar y es:

2𝑛2−2𝑛

2𝑛2 =2𝑛2

22𝑛2𝑛2 =1

22𝑛

Este valor nos da una medida de la calidad de la codificación. Ejemplo 2: Problema de las estaciones de bomberos

Una ciudad se compone de 𝑛 barrios. Cada barrio es vecino de otros barrios y la relación de

vecindad se puede representar mediante un grafo no dirigido cuyos vértices representan los

barrios y existe una arista entre dos barrios si son vecinos. Queremos ubicar una estación de

bomberos en algunos barrios con la restricción que en cada barrio o en uno de sus vecinos haya

Page 27: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

27 16. Algoritmos iterativos de aproximación

una estación de bomberos. El objetivo es minimizar el número de estaciones de bomberos. Si

las varaibles binarias 𝑥𝑗 indican si un barrio tendrá estación de bomberos o no y 𝑁(𝑗) los

vecinos del barrio 𝑗, el problema de Programación Lineal Entera era:

min ∑ 𝑥𝑗

𝑚−1

𝑗=0

(∑ 𝑥𝑗) ≥ 1, 𝑖 ∈ [0, 𝑚)𝑗:𝑁(𝑖)

𝑏𝑖𝑛 𝑥𝑗 , 𝑗 ∈ [0, 𝑚)

Que podemos podemos reescribir mediante la función de fitness:

𝑓 = − ( ∑ 𝑥𝑗

𝑚−1

𝑗=0

) − 𝐾 ∑ 𝜑

𝑚−1

𝑖=0

(( ∑ 𝑥𝑗

𝑗:𝑁(𝑖)

) − 1)

𝜑(𝑢) = {−𝑢, 𝑥 < 0

0, 𝑥 ≥ 0

4.1.2 RangeChromosome

Es un subtipo de ValuesInRangeChromosome<Integer> cuyos valores son listas de enteros con

las siguientes restricciones del cromosoma. Es decir, la lista decodificada es de tamaño igual al

número de objetos y cada casilla de la misma es un entero positivo o cero y menor o igual que

el máximo permitido para ese tipo de objetos.

Usos:

Es un cromosoma adecuado para resolver problemas cuya solución es un Multiset formado con

elementos de un conjunto dado u otros problemas en los que aparecen variables enteras en un

rango.

Ejemplo: Problema de la Mochila

Ya lo hemos explicado arriba. Ahora las casillas de la lista decodificada es el número de unidaes

escogido de cada objeto. Si 𝑑 es la lista decodificada entonces la función de fitness es:

𝑓 = ∑ 𝑑[𝑖]𝑣(𝑖) − 𝐾𝜑((∑ 𝑑[𝑖]𝑤(𝑖

𝑠−1

𝑖=0

)

𝑛−1

𝑖=0

) − 𝐶)

𝜑(𝑢) = {0, 𝑢 ≤ 0𝑢, 𝑢 > 0

4.1.3 RealChromosome

Page 28: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

28 Introducción a la Programación

Es un subtipo de ValuesInRangeChromosome<Double>. Los valores de estos cromosomas son

listas de números reales en rangos especificados.

Usos:

Este cromosoma es adecuado para modelar funciones de varias variables reales del tipo

𝑓(𝑥0, 𝑥1, … , 𝑥𝑛−1) de las que se quiere obtener el máximo o el mínimo en un dominio.

4.2 IndexChromosome

Representa una lista de valores de tipo E que están en un rango. Dispondremos de 3 subtipos:

IndexSubListChromosome, IndexPermutationChromosome,

IndexPermutationSubListChromosome.

Los detalles específicos para cada uno de estos cromosomas se indicarán en una

implementación del tipo IndexProblemAG<S>. Dónde S el tipo de la solución del problema.

public interface IndexProblemAG<S> extends ProblemaAG {

Double fitnessFunction(IndexChromosome cr) ;

Integer getMaxMultiplicity(int index);

List<Integer> getNormalSequence();

Integer getObjectsNumber();

S getSolucion(IndexChromosome cr);

}

Restricciones y notación:

n = getObjectsNumber();

r = getNormalSequence().size();

d = decode();

s = d.size();

n<=s<=r;

m(i) = getMax(i);

Cada cromosoma de este tipo tiene asociada una secuencia normal. Esta está formada por la

concatenación de n sublistas L(i). Cada L(i) está se compone de getMaxMultiplicity (i) copias del

entero i, con i en el rango 0..n-1.

El valor decodificado es una lista con enteros que pueden ser usados como índices en una lista

de objetos.

4.2.1 IndexSubListChromosome

Es un subtipo de IndexChromosome cuyos valores son un subconjunto de la secuencia normal

sin importar el orden.

Usos:

Page 29: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

29 16. Algoritmos iterativos de aproximación

Es un cromosoma adecuado para resolver problemas cuya solución es un Multiset formado con

elementos de un conjunto dado.

Ejemplo: Problema de la Mochila

Se parte de 𝐿, una lista de objetos de tamaño 𝑛, y 𝑚 una lista de enteros del mismo tamaño

dónde 𝑚(𝑖) indica el número de repeticiones posibles del objeto en la posición 𝑖. A su vez cada

objeto 𝑜𝑏𝑖 de la lista es de la forma 𝑜𝑏𝑖 = (𝑤(𝑖), 𝑣(𝑖)) dónde 𝑤(𝑖), 𝑣(𝑖) son, respectivamente,

su peso y su valor unitario. Además la mochila tiene una capacidad 𝐶. El problema busca ubicar

en la mochila el máximo número unidades, siempre que no superen las máximas permitidas

para cada tipo de objeto, que quepan en la mochila para que el valor de los mismos sea máximo.

Si 𝑑 es el valor decodificado entonces la función de fitness es:

𝑓 = ∑ 𝑣(𝑑[𝑖]) − 𝐾𝜑((∑ 𝑤(𝑑[𝑖]

𝑠−1

𝑖=0

)

𝑠−1

𝑖=0

− 𝐶)

𝜑(𝑢) = {0, 𝑢 ≤ 0𝑢, 𝑢 > 0

Hemos de tener en cuenta que 𝑑 es un vector cuyas casillas son índices a la lista 𝐿 que se repiten

un máximo indicado en el problema.

4.2.2 IndexPermutationChromosome

Es un subtipo de IndexChromosome cuyos valores son listas de enteros que son permutaciones

de la secuencia normal. Cada entero es un índice a la lista de objetos proporcionada.

Usos:

Es un cromosoma adecuado para resolver problemas cuya solución es una permutación de un

multiconjunto dado de objetos.

Ejemplo: Problema de la Asignación

Como ya vimos en este problema tenemos una lista de agentes 𝐿 y una lista de tareas 𝑇 ambas

del mismo tamaño 𝑛. El coste de que el agente 𝑖 realice la tarea 𝑗 sea 𝑐𝑖𝑗 . Se pretende asignar a

cada agente una tarea y sólo una de tal forma que se ejecuten todas las tareas con el coste

mínimo.

Si asumimos que 𝑑[𝑖] es la tarea asignada al agente 𝑖 la función de fitness se puede escribir

como:

Page 30: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

30 Introducción a la Programación

𝑓 = − ∑ 𝑐𝑖𝑑[𝑖]

𝑛−1

𝑖=0

Si comparamos esta solución con la que usaba el BinaryChromosome podemos ver sus ventajas.

Aquí todos los valores son válidos y la función de fitness y mucho más simple de escribir.

4.2.3 IndexPermutationSubListChromosome

Es un subtipo de IndexChromosome cuyos valores son listas de enteros que son subconjuntos

de permutacionaciones de la secuencia normal. Cada entero es un índice a la lista de objetos

proporcionada.

Usos:

Es un cromosoma adecuado para resolver problemas cuya solución es una permutación de un

subconjunto de un multiconjunto dado de objetos.

Ejemplos: El problema de los anuncios simplificado.

Un canal de televisión quiere obtener el máximo rendimiento (en euros) de la secuencia

de anuncios que aparecerá en la cadena después de las campanadas de fin de año. La

secuencia de anuncios del año durará 𝑇 segundos como máximo. Hay una lista 𝐿, de

tamaño 𝑛, de anuncios que se ofertan para ser emitidos. Cada anuncio anuncio 𝑎(𝑖)

tiene un tiempo de duración 𝑡(𝑖) y está dispuesto a pagar un precio 𝑝(𝑖) = 𝑏 𝑡(𝑖)

𝑝𝑜𝑠(𝑖)+ 𝑐.

Dónde 𝑏, 𝑐 son constantes y 𝑝𝑜𝑠(𝑖) es la posición en la que se emitirá el anuncio si llega

a ser emitido. Se quiere emitir el subconjunto de 𝐿 cuyo tiempo total de emisión sea

menor o igual que 𝑇 y maximice el precio total de los anuncios.

La función de fitness es:

𝑓 = ∑(𝑏 𝑡(𝑑[𝑖])

𝑖 + 1

𝑠−1

𝑖=0

+ 𝑐) − 𝐾𝜑(∑ 𝑡(𝑑[𝑖])

𝑠−1

𝑖=0

− 𝑇)

𝜑(𝑥) = {0, 𝑥 ≤ 0𝑥, 𝑥 > 0

4.3 ExpressionChromosome

Los valores de este cromosoma son expresiones construidas con un conjunto de operadores, un

conjunto de variables y otro constantes cuyos valores hay que determinar.

Page 31: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

31 16. Algoritmos iterativos de aproximación

public interface IExpresssionChromosome<T> extends IChromosome<Exp<T>> {

Integer getNumOperators();

Integer getNumVariables();

Integer getNumConstants();

Exp<T> getExp();

Exp<T> getOperator(int i);

VariableExp<T> getVariable(int i);

ConstantExp<t> getConstant(int i);

ProblemaAGExpression<?,T> getProblem();

}

public interface ProblemaAGExpression<S,T> extends ProblemaAG {

T convert(java.lang.Integer e) ;

Double fitnessFunction(IExpressionChromosome<T> chromosome);

Integer getMaxValueConstant();

NAryExp<T> getNaryExp();

Integer getNumOperators();

Integer getNumVariables();

Integer getNumConstants();

List<Exp<T>> getOperators();

S getSolucion(IExpressionChromosome<T> chromosome) ;

}

Usos:

Este cromosoma es adecuado para encontrar expresiones que cumplan con algunos requisitos.

Ejemplo:

Dadas dos listas de valores 𝐿𝑥, 𝐿𝑦 con valores para la variables 𝑥, 𝑦 encontrar una función ℎ tal

que 𝑦 = ℎ(𝑥) que sea una aproximación a ellos.

La función de fitness es:

𝑓 = − ∑(𝑒(𝐿𝑥[𝑖]) − 𝐿𝑦[𝑖])2

𝑛−1

𝑖=0

Dónde 𝑒(𝑥) es la expresión aociada al cromosoma evaluada en 𝑥.

4.4 ListIntegerChromosome

Es un cromosma más general que se decodifica mediante una lista de valores enteros. Es un

cromosoma básico que se puede combinar con operadores de mutación de diferentes tipos. Los

operadores de mutación son muy conocidos y consisten fundamentalmente en permutar el

valor de una casilla escogida al azar o en intercambiar los valores de dos casillas escogidas al

azar.

Page 32: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

32 Introducción a la Programación

Los detalles del problema se indican en una implementación de ProblemaAGListInteger

public interface ProblemaAGListInteger<S> extends ProblemaAG {

Double fitnessFunction(ListIntegerChromosome cr) ;

int getDimension();

MutationPolicy getMutationPolicy();

CrossoverPolicy getCrossoverPolicy()

List<Integer> getRandomList()

S getSolucion(ListIntegerChromosome cr);

}

Escogiendo adecuadamente los operadores de mutación podemos obtener conjuntos

adecuados de listas de enteros.

Los operadores de cruce son también ampliamentre conocidos y similares a los usados para el

cromosoma binario anterior. Los operadores de cruce tienen que escoger adecuadamente para

conseguir que el conjunto de valores del cromosoma esté dentro del conjunto buscado. En

algunos casos es preferible usar solo operadores de mutación y no de cruce para conseguirlo.

5. Algoritmos Genéticos

Los Algoritmos Genéticos se inspiran en la evolución biológica. Estos algoritmos hacen

evolucionar una población de individuos sometiéndola a acciones aleatorias semejantes a las

que actúan en la evolución biológica (cruces y mutaciones), así como también a una selección de

acuerdo con algún criterio, en función del cual se decide cuáles son los individuos más

adaptados, que sobreviven, y cuáles los menos aptos, que son descartados. Llamamos

generaciones, como en la evolución biológica, a las sucesivas poblaciones que se van obteniendo

haciendo evolucionar la primera de ellas.

En este tipo de algoritmos asumimos que se trata de maximizar la función objetivo.

Es esto algoritmos también se estable una condición de parada. El esquema es de la forma:

Population evolve(Population initial, StoppingCondition condition) {

Population current = initial;

while (!condition.isSatisfied(current)) {

current = nextGeneration(current);

}

return current;

}

La población inicial se suele inicializar de forma aleatoria. Cada individuo de la problación (en la

estrategia anterior una instancia del estado) tiene una representación interna que llamaremos

cromosoma, codificación o representación del individuo y una representación externa (lo que

hemos denominado solución en la estrategia anterior) que está más cercana a los individuos tal

Page 33: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

33 16. Algoritmos iterativos de aproximación

como se observan el el domino del problema. Para cada problema hay que establecer un

mecanismo de decodificación. Es decir una manera de obtener la representación externa de la

interna. Cada individuo tiene asociada una media de su fortaleza. Esa medida la denominaremos

fitness. El objetivo del algortimo genético es encontrar el o los individuos que maximizan su

fitnes tras hacer evolucionar la población.

De una forma abstracta un cromosoma podemos verlo como una lista de valores de un tipo

dado. Es decir un cromosoma será del tipo List<T> con algunas operaciones adicionales. Entre

ellas la que calcula la fitness del cromosoma y los operadores para hacer la mutación y el cruce.

Los elementos de la lista los denominaremos genes.

La población es un agregado de individuos que se puede implementar de diferentes formas y

que debe tener mecanismos para obtener una generación a partir de otra. Una población elitista

es aquella que pasa sin cambios un porcentaje de sus mejores individuos a la siguiente

generación.

Los mecanismos para obtener la siguiente generación se consiguen aplicando políticas de

elitismo, cruce y mutación siguiendo el esquema:

1. Se escogen los mejores individuos de una población sigún la tas de elitismo escogida y

se pasan sin copia a a siguiente generación.

2. Se repiten lo siguientes pasos hasta que la nueva generación alcanza el tamaño

prefijado.

a. Siguiendo la Política de Selección elegida se escogen dos cromosomas

b. En un porcentaje establecido por la Tasa de Cruce se aplica el Operador de Cruce

fijado

c. En un porcentaje establecido por la Tasa de Mutación se aplica el Operador de

Mutación fijado

Una política de selección muy usada es la denomianda Elección por Torneo. Consiste en

seleccionar sin reemplazamiento un grupo de inviduos al azar de la población y de entre ellos

escoger el mejor. El tamaño del grupo se denomina aridad del Torneo. Una aridad alta implica

que los individuos peores casi nunca son escogidos.

6. Algoritmos Genéticos detalles de implementación

En el API incluimos una implementación de los Algoritmos Genéticos. La implementación es

una adaptación del software que se ofrece en Apache.

Aquí solo incluimos algunos detalles para dar una idea de la implementación.

Es esque del Algoritmo Genético es de la forma:

public Population evolve(Population initial, StoppingCondition condition) {

Population current = initial;

Page 34: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

34 Introducción a la Programación

while (!condition.isSatisfied(current)) {

current = nextGeneration(current);

}

return current;

}

Hay muchas propuestas de operadores de cruce pero los más usuales son:

OnePointCrossover: Se selecciona un punto del cromosoma al azar. La primera parte de

cada progenitor se copia en el hijo correspondiente, y la segunda parte se copian en

cruz.

NPointCrossover: Se seleccionan N puntos en le cromosoma al azar. El cromosoma

queda dividido en N+1 partes. Las primeras partes de cada progenitor se copias en el

hijo correspondiente, la segunda parte se copian en cruz, la tercera en el hijo

correspondiente, etc.

UniformCrossover: Dada una tasa r se escogen r% de genes de un padre y 1-r del otro.

Esto es típicamente un pobre método de cruce, pero la evidencia empírica sugiere que

es más exploratorio y resultados en una parte más grande de espacio del problema que

se busca.

CycleCrossover: Identificaciclos entre dos cromosomas padres y los copia a los hijos.

OrderedCrossover: Copia un trozos consecutivos de un padre, y completa con los genes

restantes del otro padre.

Una documentación de la implementación de estos operadores puede encontarse en apache.

El operador de mutación, con la probabilidad escogida, escoge un gen al azar y lo cambia.

Los tipos siguientes son ofrecidos en Apache. CrossoverPolicy:

CrossoverPolicy: Operador de cruce

MutationPolicy: Operador de mutación

SelectionPolicy: Operador de selección

StoppingCondition: Condición de parada

Population: Agregado de Chromosome.

Chromosome: Un cromosoma.

Cualquier problema que quiera ser resuelto mediante Algoritmos Genéticos debe implementar

el tipo siguiente donde:

S es el tipo de la solución

C el tipo de los cromosomas

public interface ProblemaAG<S, C extends Chromosome> {

C getInitialChromosome();

S getSolucion(C chromosome);

}

Page 35: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

35 16. Algoritmos iterativos de aproximación

Para concretar un problema debemos instanciar el tipo S con el tipo de la solución, y el tipo C

con el tipo del cromosoma que a su vez debe heredar de una de las clases BinaryChromosome,

RandomKey<T> o MixChromosome.

Con esos tipos el esquema de ejecución de un Algoritmo Genético (método ejecuta) puede

implementarse en la clase AlgoritmoAG.

El código completo puede encontrarse en AlgoritmoAG. Algunos detalles son:

CrossoverPolicy crossOverPolicy;

MutationPolicy mutationPolicy;

SelectionPolicy selectionPolicy;

StoppingCondition stopCond;

Population initialPopulation;

Population finalPopulation;

Chromosome bestFinal;

ElitisticListPopulation randomPopulation() {

List<Chromosome> popList = new LinkedList<>();

for (int i = 0; i < POPULATION_SIZE; i++) {

Chromosome randChrom = getCromosome();

popList.add(randChrom);

}

return new ElitisticListPopulation(popList,popList.size(),ELITISM_RATE);

}

Chromosome getCromosome() {…};

void ejecuta() {

GeneticAlgorithm ga = new GeneticAlgorithm(

crossOverPolicy,

CROSSOVER_RATE,

mutationPolicy,

MUTATION_RATE,

selectionPolicy);

finalPopulation = ga.evolve(initialPopulation, stopCond);

bestFinal = finalPopulation.getFittestChromosome();

}

6.1 Parámetros de un Algoritmo Genético

Page 36: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

36 Introducción a la Programación

Para afinar un algoritmo genético necesitamos, además, dar valores a un conjunto de

parámetros de configuración. Algunos de ellos, con la denominación quen usaremos en la

implementación son:

DIMENSION: Dimensión del cromosoma

POPULATION_SIZE: Tamaño de la población. Usualmente de un valor

NUM_GENERATIONS: Número de generaciones

ELITISM_RATE: Tasa de elitismo. El porcentaje especificado de los mejores cromosomas

pasa a la siguiente generación sin cambio. Valor usual 0.2

CROSSOVER_RATE: Tasa de cruce: Indica con qué frecuencia se va a realizar la cruce. Si

no hay un cruce, la descendencia es copia exacta de los padres. Si hay un cruce, la

descendencia está hecha de partes del cromosoma de los padres. Valores usuales entre

0.8 y 0.95

MUTATION_RATE: Tasa de mutación. Indica con qué frecuencia serán mutados cada uno

de los cromosomas. Si no hay mutación, la descendencia se toma después de cruce sin

ningún cambio. La mutación se hace para evitar que se caiga en un máximo local.Valores

usales entre 0.5 y 1.

TOURNAMENT_ARITY: Número de participantes en el torneo para elegir los

cromosomas que participarán en el cruce y mutación. Valor usual 2.

Por último es necesario indicar un acondición de parada. Opciones posibles son:

Tiempo transcurrido. Se acaba cuando pase el timepo indicado

Numero de generaciones máximo

Número de soluciones distintas encontradas

Alguna combinación de las anteriores

En la clase Algoritmos se incluyen métodos de factoría para crear algoritmos que usen los

cromosomas anteriores:

public static AlgoritmoAG createAG(ChromosomeType tipo, ProblemaAG p);

En la llamada anterior el problema p tiene que ser del subtipo adecuado para aportar al

información neesaria al tipo de cromosoma proporcionado.

7. Ejemplos de algoritmos genéticos

7.1 Problema de la Mochila

Se parte de 𝐿, una lista de objetos de tamaño 𝑛, y 𝑚 una lista de enteros del mismo tamaño

dónde 𝑚(𝑖) indica el número de repeticiones posibles del objeto en la posición 𝑖. A su vez cada

Page 37: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

37 16. Algoritmos iterativos de aproximación

objeto 𝑜𝑏𝑖 de la lista es de la forma 𝑜𝑏𝑖 = (𝑤(𝑖), 𝑣(𝑖)) dónde 𝑤(𝑖), 𝑣(𝑖) son, respectivamente,

su peso y su valor unitario. Además la mochila tiene una capacidad 𝐶. El problema busca ubicar

en la mochila el máximo número unidades, siempre que no superen las máximas permitidas

para cada tipo de objeto, que quepan en la mochila para que el valor de los mismos sea máximo.

Si 𝑑 es el valor decodificado usando un cromosoma tipo IndexChromosomeSubList entonces la

función de fitness es:

𝑓 = ∑ 𝑣(𝑑[𝑖]) − 𝐾𝜑((∑ 𝑤(𝑑[𝑖]

𝑠−1

𝑖=0

)

𝑠−1

𝑖=0

− 𝐶)

𝜑(𝑢) = {0, 𝑢 ≤ 0𝑢, 𝑢 > 0

Hemos de tener en cuenta que 𝑑 es un vector cuyas casillas son índices a la lista 𝐿 que se repiten

un máximo indicado en el problema.

Si 𝑑 es la lista decodificada usando un cromosoma tipo IndexChromosomeBinary entonces la

función de fitness es:

𝑓 = ∑ 𝑑[𝑖]𝑣(𝑖) − 𝐾𝜑((∑ 𝑑[𝑖]𝑤(𝑖

𝑠−1

𝑖=0

)

𝑛−1

𝑖=0

) − 𝐶)

𝜑(𝑢) = {0, 𝑢 ≤ 0𝑢, 𝑢 > 0

El código para resolver el problema puede encontrarse en ProblemaMochilaAG, que define el

problema de la mochila y en las clases TestMochilaAGBinary que usa un cromosoma de tipo

BinaryIndexChromosome y TestMochilaAGInteger que utiliza un cromosoma de tipo

IntegerIndexChromosome.

7.2 Problema de las Reinas:

Colocar 𝑁𝑟 reinas en un tablero de ajedrez 𝑁𝑟 × 𝑁𝑟 de manera tal que ninguna de ellas

amenace a ninguna de las demás. Una reina amenaza a los cuadrados de la misma fila, de la

misma columna y de las mismas diagonales. Las filas y columnas toman valores en (0, 𝑁𝑟 − 1).

Este problema lo podemos modelar por un cromosoma de tipo ListIntegerChomosome, junto

con un un operador de mutación que iontercambie dos casillas al azar, o un

IndexChromosomePermutationRandonKey. La función de fitness es:

𝑓 = −(2𝑛 − |{𝑖: 0. . 𝑛 − 1 • 𝑑[𝑖] − 𝑖}| − |{𝑖: 0. . 𝑛 − 1 • 𝑑[𝑖] + 𝑖}|)

Page 38: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

38 Introducción a la Programación

Para ello ebemos usar un cromosoma inciar con los valores (0,1,2, … , 𝑛 − 1). Cada reina estará

ocupando la casilla (𝑖, 𝑑[𝑖]) estará en las diagonales principal y secundaria 𝑑[𝑖] − 𝑖, 𝑑[𝑖] + 𝑖

respectivamente. Para que cada reina esté en una diagonal principal y otra secundaria

diferentes, los conjuntos formados por esos valores tienen que tener cardinal 𝑛.

7.3 Problema de los Anuncios

Un canal de televisión quiere obtener el máximo rendimiento (en euros) de la secuencia

de anuncios que aparecerá en la cadena después de las campanadas de fin de año. La

secuencia de anuncios del año durará 𝑇 segundos como máximo. Hay una lista 𝐿, de

tamaño 𝑛, de anuncios que se ofertan para ser emitidos. Cada anuncio anuncio 𝑎(𝑖)

tiene un tiempo de duración 𝑡(𝑖) y está dispuesto a pagar un precio 𝑝(𝑖) = 𝑏 𝑡(𝑖)

𝑝𝑜𝑠(𝑖)+ 𝑐.

Dónde 𝑏, 𝑐 son constantes y 𝑝𝑜𝑠(𝑖) es la posición en la que se emitirá el anuncio si llega

a ser emitido. Se quiere emitir el subconjunto de 𝐿 cuyo tiempo total de emisión sea

menor o igual que 𝑇 y maximice el precio total de los anuncios.

La función de fitness es:

𝑓 = ∑(𝑏 𝑡(𝑑[𝑖])

𝑖 + 1

𝑠−1

𝑖=0

+ 𝑐) − 𝐾𝜑(∑ 𝑡(𝑑[𝑖])

𝑠−1

𝑖=0

− 𝑇)

𝜑(𝑥) = {0, 𝑥 ≤ 0𝑥, 𝑥 > 0

El problema puede ser ampliado para tener en cuenta otras restricciones como por ejemplo

que existan anuncios

7.4 Problema de regresión

Dadas dos listas de valores 𝐿𝑥, 𝐿𝑦 con valores para la variables 𝑥, 𝑦 encontrar una función ℎ tal

que 𝑦 = ℎ(𝑥) que sea una aproximación a ellos.

La función de fitness es:

𝑓 = − ∑(𝑒(𝐿𝑥[𝑖]) − 𝐿𝑦[𝑖])2

𝑛−1

𝑖=0

7.5 Problema de extremo de una función

Page 39: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

39 16. Algoritmos iterativos de aproximación

Dada una función en un rango y con unas restricciones encontrar su mínimo o su máximo.

max𝑎≤𝑥≤𝑏, 𝑥∈Ω

ℎ(𝑥)

La función de fitness es de la forma

𝑓 = ℎ(𝑑) − 𝐾 ∗ 𝑅(𝑑)

Usando el cromosoma RealChromosome el valor decodificado es una lista de valores reales en

el rango especificado. La función 𝑅(𝑑) mide la distancia del punto a la zona definida por las

restricciones

8. Algoritmos de Simulated Annealing

Los Algoritmos de Simulated Annealing parten de un problema (como en la estrategia Voraz),

las soluciones posibles las representamos por un conjunto de estados y para cada uno de ellos

un valor calculado por la función objetivo y otro valor que indica si el estado es válido o no. En

general asumimos que el conjunto de estados posibles incluye todos los estados que

representan soluciones válidas, los estados válidos, y muchos más estados inválidos.

Normalmente la función objetivo incluirá términos que penalicen a los estados inválidos como

hemos visto arriba.

En este tipo de algoritmos se busca optimizarla función objetivo. Aquí para reutilizar material de

los Algoritmos Genéticos maximizaremos la función objetivo.

Igual que antes para cada instancia del estado 𝑒 se definen un conjunto de alternativas 𝐴𝑒. Se

escoge de forma aleatoria una de las alternativas de 𝐴𝑒. Se calcula el estado siguiente tras esa

alternativa mediante la función 𝑛𝑒𝑥𝑡(𝑒, 𝑎). Si el estado siguiente se acepta se continúa. Si no se

acepta se vuelve al estado anterior.

En este tipo de algoritmos es clave la noción de aceptación del nuevo estado. Sean los estados

𝑒′ = 𝑛𝑒𝑥𝑡(𝑒, 𝑎)

Sean 𝑓, 𝑓′ los valores de la función objetivo para los estados 𝑒, 𝑒′ y ∆ = 𝑓′ − 𝑓 el incremento de

la función objetivo. Entonces el nuevo estado se acepta con probabilidad

𝑝𝑎(∆) = {1, ∆> 0

𝑒−∆/𝑇 , ∆≤ 0

Es decir se acepta con total seguridad si el incremento es negativo (estamos asumiendo

problemas de minimización) y con la probabilidad indicada si es positivo. La probabilidad

depende de un concepto llamado temperatura. La temperatura, que intenta emular la

temperatura de un sistema, toma un valor inicial y posteriormente va disminuyendo hasta

Page 40: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

40 Introducción a la Programación

acercarse a cero. Una cuestión clave es la estategia de enfriamiento. Es decir el mecanismo

disminución de la temperatura. Se han propuesto varias alternativas. Aquí, en un primer

momento, escogeremos

𝑇 = 𝑇0 𝛼𝑖, 0 < 𝛼 < 1

Dónde 𝛼 es un parámetro, 𝑖 el número de iteración y 𝑇0 la temperatura inicial. También será

necesario establecer 𝑛 el número de iteraciones y 𝑚 el número de iteraciones sin cambiar la

temperatura.

El algoritmo comienza a dar pasos y en las primeras iteraciones acepta incrementos positivos

con probabilidad 𝑒−∆/𝑇0. Al final acepta incrementos positivos con probabilidad 𝑒−∆/𝑇0𝛼𝑛. Para

ajustar el algoritmo debemos escoger los parámetros anteriores. Para ello escogemos la

probabilidad de aceptación al principio de 𝑝0 y al final 𝑝𝑓. La primera debe ser alta (0.98 por

ejemplo) y la segunda baja (0.01 por ejemplo). A partir de lo anterior vemos que debe cumplirse

𝑒−∆/𝑇0 = 𝑝0, 𝑒−∆/𝑇0𝛼𝑛= 𝑝𝑓

Si conocemos el tamaño típico de ∆ y escogemos 𝑛 (el número de iteraciones con cambio de

temperatura en cada una de ellas) podemos despejar 𝑇0, 𝛼.

𝑇0 = −∆/ ln 𝑝0, 𝛼 = √−∆

𝑇0 ln 𝑝𝑓

𝑛

De la relaciones anteriores podemos concluir que 𝑇0 debe ser escogido en función del valor de

∆ de tal forma que 𝑇0

∆≅ 100. El valor de 𝑝0 debe ser cercano a 1 y el de 𝑝𝑓 cercano a cero. A

partir de las ideas anteriores y las relaciones previas podemos obtener valores para 𝑇0, 𝑛, 𝛼.

Si 𝑝0 = 0.99, 𝑝𝑓 = 0.01, ∆= 1, 𝑛 ≈ 300 tenemos 𝑇0 ≈ 100, 𝛼 ≈ 0.98.

O alternativamente

Si 𝑝0 = 0.99, 𝑝𝑓 = 0.01, ∆= 1, 𝑛 ≈ 200 tenemos 𝑇0 ≈ 100, 𝛼 ≈ 0.97.

Otro parámetro a escoger es 𝑚 (el número de iteraciones a la misma temperatura). Escogidos

esos parámetros el tiempo de ejecución del algoritmo es proporcional al producto 𝑚 ∗ 𝑛.

Junto a la anterior expresión para la evolución de la temperatura hay muchas otras posibles.

Una de ellas, también bastante común es

𝑇 = 𝑇0

ln(1 + 𝑎𝑖)

Donde 𝑖 es el número de la iteración, con 𝑛 iteraciones en total y 𝑇0 la temperatura inicial. Como

antes habrá que calcular los valores adecuados de 𝑇0, 𝑎, 𝑛.

Page 41: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

41 16. Algoritmos iterativos de aproximación

Operadores de mutación

Más arriba hemos diseñado un conjunto de cromosomas. Esas implementaciones la podemos

usar directamente en los Algoritmos Genéticos. En Simulated Annealing podríamos usar los

mismos cromosomas pero usando sólo los operadores de mutación y descartando los de cruce

y selección. Aquí abordaremos la técnica de Simulated Annealing implementado cromosomas

para cada caso concreto y dotándolos de operadore de mutación. Veamos algunos.

Los cromosomas binarios pueden dotarse de un operador del tipo 𝑜𝑏(𝑐), con 0 ≤ 𝑐 < 𝑛 , que

indica cambiar el contenido de la casilla 𝑐.

Los cromosomas lista de enteros (similares al IntegerIndexChromosome) pueden dotarse de un

operador del tipo 𝑜𝑚(𝑐, 𝑣), con 0 ≤ 𝑐 < 𝑛, 0 ≤ 𝑣 ≤ 𝑚(𝑐) , que indica cambiar el contenido de

la casilla 𝑐 por 𝑣.

En los cromosomas de permutación el operador de mutación más complejo. Se usa una lista ℎ,

del mismo tamaño, formada por valores reales comprendidos entre cero y uno. El mecanismo

para generar permutaciones consiste en perturbar ℎ y posteriormente ordenarla de tal forma

que cuando cambiamo las casillas 𝑖 por 𝑗 en ℎ también las cambiamos en 𝑙.

Otro operador posible en los cromosomas de permutación es 𝑜𝑙(𝑎, 𝑐) con 0 ≤ 𝑎 < |𝑙|, 0 ≤ 𝑐 <

|𝑙|, 𝑎 ≠ 𝑐. Aplicar el operador significa permutar los valores de las casillas 𝑎, 𝑐.

Los cromosomas reales y sublista se implementan a partir de los demás y por lo tanto heredan

sus operadores de mutación.

8.1 Busqueda Tabú

La solución inicial se obtiene redondeando las variables enteras alrededor sus valores óptimos

en relajaciones LP. La búsqueda tabú comienza a modificar esta solución haciendo cambios

exclusivamente en las variables enteras. Modificaciones de la solución se realizan en una

estructura de vecindad simple: incrementar o decrementar en una unidad el valor de una

variable entera. La vecindad una solución aproximada 𝑥 está formada por aquellos valores 𝑥′

que difieren en una unidad en un elemento 𝑥𝑖. Por lo tanto 𝑥′𝑖 = 𝑥𝑖 + 1 o 𝑥′𝑖 = 𝑥𝑖 − 1 y eel

resto de las variables iguales.

En la búsqueda tabú los movimientos de una variable que se ha cambiado recientemente son

prohibidos y son aceptados si conducen a la mejor a una mejor solución que la encontrada hasta

el momento. La búsqueda se complementa con intensificación y diversificación. Intensificación

permite a variables no prohibidas mejorar su valor mediante técnicas de ramifica y poda que

veremos más adelante. La diversificación crea nuevas soluciones basadas en relajaciones, pero

manteniendo una parte de la solución actual sin cambios.

Aquí no veremos esta técnica con mucho detalle.

Page 42: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

42 Introducción a la Programación

9. Detalles de implementación de los Algoritmos de Simulated Annealing

El algortimo de Simulated Annealing podemos verlo como una versión simplificada de los

algoritmos genéticos. Usaremos también los mismos tipos de cromosomas pero ahora sólo los

operadores de mutación.

Los datos del problema los incluiremos en una clase que implemente el interface adecuado

según el tipo de cromosoma. Posteriormente llamaremos al algoritmo con la factoría

Algoritmos:

ProblemaReinasAG p = ProblemaReinasAG.create();

AlgoritmoSA ap = Algoritmos.createSA(ChromosomeType.IndexPermutation,p);

Fijados los tipos anteriores podemos implementar el esquema del Algoritmo de Simulated

Annealing. Una versión simplificada de este algoritmo es:

public void ejecuta() {

this.mejorSolucionEncontrada =

ChromosomeFactory.randomChromosome(this.type);

for (Integer n = 0; !parar && n < numeroDeIntentos; n++) {

this.temperatura = temperaturaInicial;

this.estado = ChromosomeFactory.randomChromosome(this.type);

for (int numeroDeIteraciones = 0; !parar

&& numeroDeIteraciones < numeroDeIteracionesPorIntento;

numeroDeIteraciones++) {

for (int s = 0; !parar && s <

numeroDeIteracionesALaMismaTemperatura; s++) {

this.nextEstado = (IChromosome<?>)

this.mutationPolicy.mutate(this.estado.asChromosome());

double incr = nextEstado.fitness() - estado.fitness();

if (aceptaCambio(incr)) {

estado = nextEstado;

actualizaMejorValor();

}

parar = this.stopCond.isSatisfied(this.soluciones);

}

this.temperatura= nexTemperatura(numeroDeIteraciones);

}

soluciones.addChromosome(this.estado.asChromosome());

}

}

private void actualizaMejorValor() {

if (estado.fitness() > mejorSolucionEncontrada.fitness()) {

mejorSolucionEncontrada = estado;

}

}

Page 43: Introducción a la Programacióngustavo.lsi.us.es:8117/document/Tema16.pdf16. Algoritmos iterativos de aproximación 3 operadores, para cada estado, se escoge aleatoriamente una alternativa

43 16. Algoritmos iterativos de aproximación

private double nexTemperatura(int numeroDeIteraciones) {

return alfa*temperatura;

// return temperaturaInicial/Math.log(2+3*numeroDeIteraciones);

}

private boolean aceptaCambio(double incr) {

return Math2.aceptaBoltzmann(-incr, temperatura);

}

Una versión más completa puede encontrarse en el API.