1. Programación Lineal Generalizada y Gen

Anuncio
1.
Programación Lineal Generalizada y Generación de columnas
Suponemos un problema de Programación Lineal en la forma estandar
(P)
Minimizar
sujeto a
z = cx
Az = b
x≥0
donde
n = número de variables
m = número de restricciones
A = matriz m × n de coeficientes aij
c = (c1 , ..., cn ) vector fila de costos
b = (b1 , ..., bm )T vector columna del lado derecho
z = función objetivo
Aunque el tamaño de los problemas que pueden resolverse hoy dı́a es muy
elevado (miles de variables y restricciones en un simple PC), existen numerosos
problemas prácticos de grandes dimensiones que no pueden ser ni siquiera formulados adecuadamente debido al excesivo número de variables y la cantidad
de memoria exigida para almacenarlas. Estos Problemas de Gran Escala pueden
a veces ser resueltos mediante técnicas de descomposición que reducen la solución de un problema grande a una sucesión de problemas de menor dimensión.
Los principales métodos de descomposición, como el de Dantzig-Wolfe y el de
Benders, están basados en técnicas de generación de columnas y generación de
restricciones y se aplican a multitud de problemas de Programación Lineal y
también de Programación Entera. Es esta sección vamos a ver la filosofı́a general de los métodos de generación de columnas, que se engloba generalmente en
el término de Programación Lineal Generalizada. Los métodos de Generación
de restricciones, que es la versión dual de generación de columnas, se aplican
fundamentalmente en los modelos de Programación Entera, y serán vistos en la
parte 2.
Suponemos aquı́ que el problema (P) tiene un número de variables n mucho
mayor que el número de restricciones m, es decir n À m, de forma que, aunque es
imposible almacenar en la memoria del ordenador todas las columnas de la matriz A, conocemos las columnas sólo implı́citamente. Por ejemplo, cada columna
puede corresponder a un vértice o punto extremo de un poliedro, o en otros
casos a un camino entre dos nodos en cierto grafo. En cada ejemplo especı́fico
el conjunto de columnas puede tener una forma diferente, y aquı́ supondremos
que S ⊂ Rm es el conjunto de todas las columnas, y para cada a ∈ S se tiene
asociado el costo c(a).
La formulación del problema completo en la forma de columnas es:
(P)
Minimizar
z=
sujeto a
n
P
n
P
cj xj
j=1
aj x j = b
j=1
1
xj ≥ 0, j = 1, ..., n
donde los vectores columna aj y b pertenecen a Rm .
Como el número de columnas puede ser elevadı́simo se trata se no intentar enumerarlas todas explı́citamente, sino generar sólo las columnas que se
necesiten. Más concretamente, suponemos que se han generado un conjunto
de columnas con ı́ndices G ⊂ {1, ..., n} y se considera el problema restringido
siguiente:
(PR)
Minimizar
sujeto a
P
cj xj
z=
P j∈G
aj x j = b
xj ≥ 0, ∀j ∈ G
j∈G
Mientras que el problema original (P) no puede ser resuelto explı́citamente,
porque el número de columnas o variables es excesivo, el problema restringido
(PR) debe poder resolverse completamente. Después de aplicar el método simplex se tendrá una SBF óptima x0 correspondiente a una base B, y un vector
de multiplicadores simplex o varibles duales óptimo ω = cB B −1 .
Toda solución factible para (PR) (xj , j ∈ G) es factible para el problema
(P), pues basta extender las varibles con xj = 0, ∀j ∈
/ G. Entonces, para saber
si la solución actual x0 , que es óptima para (PR), es óptima para (P) o, en caso
contrario, determinar la columna que va a entrar enla base, habrı́a que calcular
el coste reducido zj −cj = cB B −1 aj −cj = ωaj −cj para toda columna no básica
aj o ı́ndice j ∈ R, para después tomar el coste reducido máximo. Si tenemos
definidas las columnas implı́citamente como a ∈ S, calcular el coste reducido
máximo máx {zj − cj } es equivalente a resolver el siguiente subproblema:
j=1,...,n
(Pω )
máx {ωa − c(a)}
a∈S
Si a ∈ S es una solución óptima del subproblema (Pω ) y ωa − c(a) ≤ 0 entonces
la solución actual es óptima, y si ωa − c(a) > 0 entonces añadimos la columna a
a la formulación actual del problema (PR) y se reoptimiza mediante el método
simplex .
Esta aproximación es llamada Genaración de Columnas porque normalmente sólo se generan explı́citamente una fracción muy pequeña de todas las
columnas de S. Dependiendo de la estructura de S y de la forma del costo c(a),
el subproblema (Pω ) puede ser un problema sencillo de PL , un problema de
Programación Dinámica, un problema de redes o de flujo máximo, o un problema sencillo de Programación Entera como por ejemplo un problema de tipo
mochila.
Los algoritmos de generación de columnas están basados en la interacción
entre el problema de Programación Lineal (PR), que se resuelve explı́citamente,
y el subproblema (Pω ), que genera las columnas, como se ve en la siguiente
Figura:
2
vector w
Subproblema ( P w )
Problema (PR)
columna a
Esta aproximación se ha aplicado a multitud de situaciones y problemas,
entre los que se pueden destacar:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
El problema Cutting Stock.
Problemas con estructuras especiales, y el principio de descomposición de Dantzig-Wolfe.
Flujo de costo mı́nimo en una red.
Flujo en redes multiproducto. Reformulación por caminos.
Problemas con estructura de bloques angulares.
Programación multi-item.
Resolución del dual Lagrangeano por generación de columnas.
Maximización de funciones cóncavas y lineales a trozos.
Programación de tripulaciones (Crew Scheduling).
Descomposición de problemas de Programación Entera. Branchand-Price.
3
2.
El problema de Cutting Stock
El problema de corte de materiales o Cutting Stock fué uno de los primeros
problemas resueltos mediante un algoritmo de generación de columnas (por
Gilmore y Gomory hacia 1961), y hoy dı́a constituye uno de los problemas
clásicos de la Investigación Operativa. Aquı́ vamos a ver la versión de dimensión
1, pero ideas análogas se pueden aplicar a dimensión 2 (corte de tableros y
otras superficies) y dimensión 3 (empaquetado de objetos en contenedores). La
cantidad de problemas de corte y empaquetado es tan variada que constituye
ya un área propia dentro de los problemas de producción (ver por ejemplo
H. Dyckhoff y U. Finke Cutting and Packing in Production and Distribution,
Physica-Verlag 1992). En la siguiente página Web CaPaD Cutting and Packing
at Dresden University of Technology, http://www.math.tu-dresden.de/ capad/,
se mantiene actualizada mucha información sobre estos tipos de problemas.
El problema surge en industrias dedicadas al papel, madera, hierro, textiles,
plásticos, etc., y el de dimensión 1 se formula de la forma siguiente: se tiene
en stock una cantidad muy grande de barras o tiras de longitud L, y se tiene
que servir un pedido de deferentes piezas de menores longitudes. Supongamos
por ejemplo que hay m tipos de piezas demandadas, y se requieren bi piezas
de longitud li , i = 1, ..., m. Supondremos que li ≤ L, i = 1, ..., m, pues si no el
problema no tiene solución. El problema es cómo cortar el material del stock para
servir todas las piezas demandadas y de forma que la cantidad desperdiciada sea
mı́nima. Para modelizar el problema Gilmore y Gomory introdujeron el concepto
de patrón de corte. Un patrón es es una forma particular de cortar una barra del
stock produciendo cierto número de las piezas demandadas. Entonces un patrón
viene determinado por el vector a = (a1 , a2 , ..., am ), donde ai es el número de
piezas de longitud li que produce ese patrón. Notar que este vector verifica las
condiciones:
m
P
li a i ≤ L
i=1
ai ≥ 0
entero
i = 1, ..., m
Supongamos que se pudieran enumerar todos los patrones posibles, con ı́ndices
j = 1, ..., n, y sea
aij = el número de piezas de longitud li que produce el patrón j
xj = el número de veces que se usa el patrón j
Entonces el problema de minimizar el número de barras del stock para servir
las piezas demandadas se puede formular como el siguiente problema de Programación Entera:
Minimizar
z=
n
P
xj
j=1
sujeto a
n
P
aij xj ≥ bi
i = 1, ..., m
j=1
xj ≥ 0, entero
4
j = 1, ..., n
Este problema de Programación Entera suele ser difı́cil de resolver fundamentalmente por dos razones: una es la presencia de variables enteras, y otra
es que el número n de columnas o variables puede ser muy elevado. Por ejemplo, para una longitud L = 200 y demandas de m = 40 longitudes diferentes
en el intervalo [20, 80] el número de patrones fácilmente está entre 10 y 100
millones. Sin embargo, el número de restricciones del sistema anterior es fijo,
y es = m. Basandose en este hecho, Gilmore y Gomory dieron una solución a
este problema, resolviendo, mediante un algoritmo de generación de columnas,
la Relajación Lineal
Minimizar
z=
n
P
xj
j=1
n
P
sujeto a
aij xj ≥ bi
i = 1, ..., m
j=1
xj ≥ 0
j = 1, ..., n
Una vez resuelta la relajación lineal, es fácil obtener soluciones factibles (enteras). La forma más sencilla es redondear hacia arriba la solución, aunque hay
otras formas de obtener soluciones factibles ligeramente mejores como se verá a
continuación. Indicando por z el valor óptimo entero (desconocido), por zLP el
valor óptimo de la relajación lineal y por z 0 el valor de una solución factible
entera, se tienen las desigualdades básicas en Programación Entera para un
problema de minimización:
zLP ≤ z ≤ z 0
La diferencia z 0 − zLP es conocida como el hueco de dualidad (duality gap) y
cuando es pequeña indica que la solución factible actual de valor z 0 está cerca
del óptimo.
Ejemplo 1 Suponemos un stock con longitud L = 100 y demandas de las
siguientes piezas:
97
610
395
211
piezas
piezas
piezas
piezas
de
de
de
de
longitud
longitud
longitud
longitud
45
36
31
14
En este ejemplo es fácil enumerar todos los patrones posibles, resultando
n = 37 y la siguiente matriz A de patrones:
j
a1j
a2j
a3j
a4j
1
2
0
0
0
2
1
1
0
1
3
1
1
0
0
4
1
0
1
1
5
1
0
1
0
6
1
0
0
3
7
1
0
0
2
8
1
0
0
1
5
9
1
0
0
0
10
0
2
0
2
11
0
2
0
1
12
0
2
0
0
13
0
1
2
0
14
0
1
1
2
j
a1j
a2j
a3j
a4j
15
0
1
1
1
16
0
1
1
0
17
0
1
0
4
18
0
1
0
3
19
0
1
0
2
20
0
1
0
1
21
0
1
0
0
22
0
0
3
0
23
0
0
2
2
24
0
0
2
1
25
0
0
2
0
j
a1j
a2j
a3j
a4j
27
0
0
1
3
28
0
0
1
2
29
0
0
1
1
30
0
0
1
0
31
0
0
0
7
32
0
0
0
6
33
0
0
0
5
34
0
0
0
4
35
0
0
0
3
36
0
0
0
2
37
0
0
0
1
26
0
0
1
4
Si resolvemos la relajación lineal del problema anterior para este ejemplo, eliminando las restricciones de xj enteros, se obtiene la siguiente solución
óptima: x1 = 48,5; x∗10 = 105,5; x∗12 = 100,75; x∗13 = 197,5, y el resto 0, con
zLP = 452,25.
¿Cómo obtener a partir de esta solución fraccionaria una solución entera?.
Una solución factible (entera) se obtiene siempre redondeando hacia arriba,
0
0
0
0
dando en este caso la solución: x1 = 49; x10 = 106; x12 = 101; x13 = 198, con
z 0 = 454. Se tienen entonces las desigualdades 452,25 ≤ z ≤ 454, y como z
tiene que ser un entero, las desigualdades mejoradas 453 ≤ z ≤ 454. La solución heurı́stica se puede mejorar ligeramente de diferentes formas: redondeamos
primero los x∗ hacia abajo obteniendo una solución que usa 450 barras del stock
y produciendo 96 piezas de 45 cm. , 607 piezas de 36 cm., 394 piezas de 31 cm.
y 210 piezas de 14 cm, y las piezas que faltan se pueden obtener fácilmente de
otras 3 barras, ası́ que tendrı́amos servidas todas las piezas con 453 barras del
stock. Como la relajación lineal tiene un valor de zLP = 452,25, esta solución de
valor z = 453 es necesarianente óptima. En general se pueden aplicar esquemas
de redondeo del tipo anterior para obtener soluciones óptimas o casi óptimas,
salvando ası́ la dificultad de las variables enteras. Otra posibilidad es resolver el
problema entero con las columnas que han sido generadas.
6
3.
Algoritmo de generación de columnas para el
problema Cutting Stock
En esta sección vamos a resolver por generación de columnas la relajación
lineal del problema, es decir el problema
(PM)
Minimizar
z=
n
P
xj
j=1
n
P
sujeto a
aj x j ≥ b
j=1
xj ≥ 0
j = 1, ..., n
donde aj , b son vectores columna de dimensión m. Este problema es llamado a
veces el problema maestro (PM). Como el número n de variables xj (o columnas
aj ) puede ser muy elevado, normalmente no podemos tener definido explı́citamente el problema maestro completo. Supongamos que se han generado un
conjunto de columnas con ı́ndices G ⊆ {1, 2, ..., n} y considermos el Problema
Maestro Restringido:
P
(PMR) Minimizar z =
xj
P j∈G
sujeto a
aj x j ≥ b
j∈G
xj ≥ 0
j∈G
y se supone que este problema ha sido resuelto explı́citamente y que es factible.
Sea x una solución óptima del problema anterior, y sea ω solución dual óptima,
o vector de multiplicadores asociado a la base óptima. Extendiendo la solución
con x = 0 si j ∈
/ G se puede considerar x solución fatible para (PM). Para saber
si x es óptima deberı́amos calcular los costes reducidos
zj − cj = ωaj − cj = ωaj − 1
para todo j = 1, ..., n. En vez de esto bastarı́a calcular el coste reducido máximo,
y esto llevarı́a al Subproblema:
máx {ωaj } − 1
j=1,...,n
Eliminando el término constante -1 y aplicando la caracterización de patrones
vista anteriormente, el Subproblema se pone de la siguiente forma (donde ahora
las variables son a1 , a2 , ..., am ):
(Pω )
Maximizar
sujeto a
m
P
i=1
m
P
ωi ai
li a i ≤ L
i=1
ai ≥ 0 entero
7
i = 1, ..., m
Este subproblema es un problema de tipo mochila (una sola restricción con
variables enteras) que se puede resolver relativamente bien. Sea a una solución
óptima del subproblema. Si ωa ≤ 1 (en la práctica ωa ≤ 1 + tol, donde tol es
cierta tolerancia) entonces lasolución actual es óptima, mientras que si ωa > 1
la columna a generada deberá entrar en el Problema Maestro Restringido, y se
reoptimiza mediante el método simplex revisado.
Como conjunto inicial pueden tomarse los siguientes m patrones: para cada
i = 1, ..., m el patrón i corta bL/li c piezas de tipo i , lo que darı́a como matriz
de patrones inicial la matriz diagonal:


bL/li c
0
0
0


0
bL/li c 0
0

B=
 ...
...
...
... 
0
0
0 bL/li c
Se tendrı́a entonces el siguiente procedimiento de generación de columnas
para resolver la relajación lineal del problema de Cutting Stock:
1. Se selecciona un conjunto inicial de patrones, como el anterior.
2. Se resuelve el problema de Programación Lineal con los patrones actuales
(Problema Maestro Restringido).
3. Usando los precios duales ω se resuelve el Subproblema, que es un problema de tipo mochila, con solución óptima a.
4. Si ωa > 1 entonces se añade la columna a generada al Problema Maestro
Restringido, y se
vuelve a la etapa 2.
5. Si ωa ≤ 1 ya tenemos la solución óptima del problema .
El procedimiento está basado en la interacción entre el Problema Maestro
Restringido (que genera un conjunto de precios ω), y el problema de la mochila
(que genera una columna a), como se muestra en la Figura 1.
A partir de la solución óptima del problema (PMR) final se obtiene una
solución factible para el problema entero original mediante algún procedimiento
de redondeo, o bien resolviendo el problema entero con las columnas generadas,
produciendo una solución entera muy cercana a la solución óptima.
4.
Propiedades de redondeo
Un problema de Programación Entera con valor óptimo z y valor óptimo de
la relajación lineal zLP se dice que tiene la propiedad de integralidad si z = zLP .
Se dice que tiene la propiedad de redondeo hacia arriba (IRUP: Integer RoundUp Property) si se verifica que z = dzLP e. Y se dice que tiene la propiedad
modificada de redondeo hacia arriba (MIRUP)si se verifica que z ≤ dzLP e + 1.
Todos los ejemplos del problema de Cutting Stock de dimensión uno que se
han resuelto verifican la propiedad MIRUP, pero este hecho no ha podido aún
demostrado matemáticamente. Este es el motivo por el que en 1997 Scheithauer
y Terno propusieran esta conjetura.
8
5.
Programa AMPL para el problema Cutting
Stock
A continuación están los ficheros con el modelo, los datos de un ejemplo y
los comandos para resolver un problema de Cutting Stock de dimensión 1.
Modelo
# ---- # MODELO CUTTING STOCK USANDO PATRONES # -------------param n integer >= 0, default 0;
param m integer >=0;
Longitud;
#Número de patrones
#Número de piezas distintas param
#Longitud del stock
param iter default 0;
param tol;
param n_usados default 0;
set PATRONES := 1..n;
set PIEZAS := 1..m;
param
param
param
param
pedidos {PIEZAS} > 0;
obtenidas{PIEZAS};
longitud{PIEZAS} > 0;
a {PIEZAS,PATRONES} integer >= 0;
param xheur{PATRONES}integer>=0;
check {j in PATRONES}:
sum {i in PIEZAS} longitud[i] * a[i,j] <= Longitud;
param zLP;
#------- #
PROBLEMA MAESTRO ENTERO #---------------------
var X {PATRONES} integer >= 0;
minimize Numero: sum {j in PATRONES} X[j];
subj to Demanda {i in PIEZAS}:
sum {j in PATRONES} a[i,j] * X[j] >= pedidos[i];
# ----------------# SUBPROBLEMA MOCHILA #--------------------
9
param precio {PIEZAS};
var patron {PIEZAS} integer >= 0;
maximize Precio_total:
sum {i in PIEZAS} precio[i] * patron[i];
subj to Long_Max:
sum {i in PIEZAS} longitud[i] * patron[i] <= Longitud;
Datos
Datos para un ejemplo de 4 piezas:
param tol:=1.e-5;
param Longitud := 100;
param m:=4;
param: longitud pedidos :=
1
45
97
2
36
610
3
31
395
4
14
211;
Comandos
En este script se resuelve primero la relajación lineal, obteniéndose ası́ la
cota inferior, y después se obtienen dos soluciones heurı́sticas (enteras), una por
redondeo entero directo, y otra resolviendo el problema entero con la matriz de
patrones que se han ido generando.
#
#
#
#
---------------------------------------METODO DE GENERACION DE COLUMNAS DE GILMORE-GOMORY
PARA EL CUTTING STOCK PROBLEM
----------------------------------------
# usar include c:\jsaez\prog_ampl\cutstock\cortar1.run;
reset;
model c:\jsaez\prog_ampl\cutstock\cortar1.mod;
data c:\jsaez\prog_ampl\cutstock\cortar2.dat;
option solver cplex;
option solution_round 6;
10
option solver_msg 0;
problem Maestro: X, Numero, Demanda;
option relax_integrality 1;
problem Mochila: patron,Precio_total,Long_Max;
option relax_integrality 0;
# Generación de m patrones iniciales
for {i
let
let
let
};
in PIEZAS} {
n:= n + 1;
a[i,n] := floor (Longitud/longitud[i]);
{i2 in PIEZAS: i2 <> i} a[i2,n] := 0;
# Bucle principal
repeat {
solve Maestro;
let iter:=iter+1;
#
display iter,Numero;
#
display X ;
let {i in PIEZAS} precio[i] := Demanda[i].dual;
solve Mochila;
#
display precio,patron;
if Precio_total <= 1+tol then break;
else {
let n := n + 1;
let {i in PIEZAS} a[i,n] := patron[i];
};
};
printf"\n**Solucion optima del problema Maestro relajado\n" ;
printf"\nNumero de patrones generados = %d",n;
printf"\nValor de la relajacion lineal = %.2f",Numero ;
let zLP:=Numero;
option display_transpose -10;
printf"\nMatriz de patrones \n" ;
display a;
11
display X ;
printf"\n**Heuristica de redondeo\n ";
let{j in PATRONES}xheur[j]:=ceil(X[j]);
display xheur;
printf"\nNumero de barras usadas = %d\n", sum{j in PATRONES}xheur[j];
printf "Desperdicio = %5.2f%%\n\n",
100 * (1 - (sum {i in PIEZAS} longitud[i] * pedidos[i])
/ (Longitud * sum{j in PATRONES}xheur[j])) ;
printf"\n**Segunda solucion entera heuristica\n\n";
option Maestro.relax_integrality 0;
solve Maestro;
display X;
printf"\nNumero de barras usadas = %d\n",Numero ;
printf "Desperdicio = %5.2f%%\n\n",
100 * (1 - (sum {i in PIEZAS} longitud[i] * pedidos[i])
/ (Longitud * Numero)) ;
printf"\nNumero de piezas obtenidas ";
display{i in PIEZAS}sum{j in PATRONES}a[i,j]*X[j];
printf"\n**Cotas finales sobre el optimo\n\nCota inferior = %d", ceil(zl);
printf"\tCota superior = %d\n\n",Numero;
12
Descargar