LINGO Sintaxis
LINGO Sintaxis
LINGO Sintaxis
Carlos Ivorra
Introduccin o
LINGO es una aplicacin capaz de resolver modelos de programacin matemtica. Estas notas se han o o a elaborado considerando la versin 12.0. En esta primera seccin describiremos m o o nimamente el uso de la aplicacin en s mientras que en las siguientes describiremos el lenguaje que hemos de emplear para o , introducir los modelos en LINGO y la interpretacin de las soluciones que ste proporciona. o e Una vez instalado, LINGO trabaja con dos clases de documentos: documentos con extensin .lg4, en o los que escribimos el modelo que queremos resolver (y se crean desde el men File New) y documentos u con extensin .lgr, en los que LINGO escribe la solucin. Ambos se pueden guardar de la forma habitual, o o con los mens File Save y File Save as. . . u Una diferencia es que, si al salir de LINGO hay algn documento .lg4 sin guardar, aparece un cuadro u de dilogo que nos pregunta si queremos guardarlo, mientras que los documentos .lgr se pierden si no se a guardan. Por otro lado, una vez que LINGO ha creado un documento .lgr con datos sobre un modelo, podemos modicarlo a nuestro gusto, borrando cualquier informacin que no nos interese, aadiendo cualquier o n clase de explicaciones, t tulos, comentarios, etc., pegando en un unico documento el contenido de varios documentos .lgr o incluso .lg4, etc. Por el contrario, lo que escribamos en un documento .lg4 debe ser correcto en el lenguaje de LINGO, pues en otro caso al intentar resolver el problema obtendremos mensajes de error en lugar de la solucin o deseada. No vamos a describir aqu las funciones de los mens e iconos de LINGO, si bien muchos de ellos u realizan tareas t picas que podemos encontrar en muchas otras aplicaciones. Destacamos unicamente el men Edit Paste function, que despliega varios de los comandos y funciones disponibles en el lenguaje u de LINGO, y el men LINGO Options. . . , que nos permite congurar muchas caracter u sticas del funcionamiento de LINGO. De momento destacamos las siguientes: General Solver Dual computations: Podemos seleccionar que LINGO calcule los multiplicadores de Kuhn y Tucker o variables duales (Prices), o tambin los intervalos de sensibilidad de los coee cientes de la funcin objetivo (en programacin lineal) y de los trminos independientes de o o e las restricciones (Prices & Ranges) o nada (None). Hay una cuarta opcin que limita el o clculo de los multiplicadores para el caso en que ste consuma demasiado tiempo. a e Si la opcin Prices & Ranges est seleccionada, LINGO puede presentar mensajes de error o a con algunos problemas de programacin no lineal (incluso en algunos muy sencillos). o Variables assumed non-negative: Con esta opcin LINGO supone que todas las variables o de un problema son 0 salvo que se indique expl citamente lo contrario. En los ejemplos de estas notas supondremos siempre que esta opcin est seleccionada. o a Global Solver Use global solver: Esta opcin hace que LINGO busque ptimos globales en lugar de o o o ptimos locales. En problemas grandes puede ralentizar mucho el proceso de resolucin, pero en o 1
problemas pequeos mejora el resultado en muchas ocasiones. Naturalmente, slo es relevante n o en problemas no lineales. Model Generator Unary Minus Priority: Es conveniente jar esta opcin en Low. Su efecto es que, por o ejemplo, LINGO interprete 22 como 4 en lugar de como 4.
Assume model is linear: Esta opcin optimiza el precesamiento del modelo para problemas o lineales.
Una empresa elabora tres tipos de piensos usando cuatro tipos de cereales. Cada saco de pienso contiene 50 kg. y se vende al precio (en euros) indicado en la tabla siguiente, que contiene tambin la e composicin de cada saco y las existencias de cereales en la fbrica: o a Pienso 1 2 3 Existencias Avena 25 0 20 50 000 Ma z 25 20 0 80 000 Cebada 0 20 30 40 000 Mijo 0 10 0 10 000 Precio 9 12 6.20
Determina el nmero de sacos que deber producir la empresa de cada tipo de pienso para maximizar u a el ingreso (supuesto que vende toda su produccin). o El modelo matemtico correspondiente a este problema es: a Max. 9x + 12y + 6.2z s.a 25x + 20z 50 000 25x + 20y 80 000 20y + 30z 40 000 10y 10 000 x, y, z 0 Y la forma de escribirlo en LINGO (en un documento .lg4) es la siguiente: [Ingresos] Max = 9*x+12*y+6.2*z; [Avena] 25*x+20*z < 50000; [Maiz] 25*x+20*y < 80000; [Cebada] 20*y+30*z < 40000; [Mijo] 10*y < 10000; Observaciones: La funcin objetivo se introduce precedida de Max = o de Min =. o Para introducir una desigualdad de o se escribre <= o >= aunque se puede abreviar a < o >. Para introducir una igualdad escribimos simplemente = Si hemos seleccionado la opcin Variables assumed non-negative no es necesario introducir las o condiciones de signo. Cada instruccin termina obligatoriamente con ; o 2
Los cambios de l nea son irrelevantes. Por claridad podemos escribir cada ecuacin en una l o nea, pero ser equivalente escribirlas todas seguidas en la misma l a nea. Rec procamente, si una restriccin o es muy larga, podemos partirla en dos o ms l a neas (teniendo en cuenta que un cambio de l nea es como un espacio en blanco, por lo que no podemos partir una palabra o un nmero). u Las etiquetas entre corchetes verb/[ ]/ son opcionales. Sirven unicamente para relacionar ms a fcilmente la solucin que proporciona LINGO con las distintas l a o neas del modelo. En caso de introducir etiquetas, stas no pueden contener espacios en blanco ni signos especiales, como acentos, e ees, etc. Una etiqueta puede contener nmeros, pero no empezar por un nmero. Podemos usar n u u el guin bajo para separar palabras (p.ej.: [Existencias_de_mijo]). o Las mismas consideraciones que acabamos de hacer para las etiquetas valen para los nombres de las variables. En lugar de x, y, z podr amos haber elegido x1, x2, x3, o incluso sacos_1, sacos_2, sacos_3. LINGO no distingue entre maysculas o minsculas, de modo que si en un lugar escribimos x y en u u otro X, para LINGO se tratar de la misma variable. Del mismo modo, da igual escribir Max, MAX a o max. No se pueden omitir los signos de multiplicacin *. Para introducir, por ejemplo, (x 5)3 , escrio bir amos (x-5)^3. Las funciones matemticas disponibles en LINGO (exponenciales, logaritmos, a etc.) pueden consultarse en el men Edit Paste function Mathematical / Trigonometrical u Es posible insertar l neas de comentarios (es decir, l neas que LINGO no leer) sin ms que empea a zarlas por un signo ! (y terminarlas igualmente con ;).
Interpretacin de la solucin o o
Una vez introducido un modelo, LINGO lo resuelve si seleccionamos el men LINGO Solve (o, u equivalentemente, pulsando en el icono en forma de diana). LINGO genera entonces un documento .lgr que, en el caso del ejemplo anterior (adems de alguna informacin tcnica) contiene lo siguiente: a o e Variable X Y Z Row INGRESOS AVENA MAIZ CEBADA MIJO Value 2000.000 1000.000 0.000000 Slack or Surplus 30000.00 0.000000 10000.00 20000.00 0.000000 Reduced Cost 0.000000 0.000000 1.000000 Dual Price 1.000000 0.3600000 0.000000 0.000000 1.200000
La columna titulada Value contiene el valor ptimo de cada variable. o En la columna titulada Slack or Surplus, la entrada correspondiente a la funcin objetivo (es o decir, la etiquetada como INGRESOS) contiene el valor ptimo de la funcin objetivo, mientras que o o las restantes contienen las variables de holgura de las restricciones. Por ejemplo, vemos que para la solucin ptima sobran 10 000 kg de ma o o z. La columna titulada Reduced Cost contiene (salvo el signo) los multiplicadores de Kuhn y Tucker de las variables del problema. El signo es el que se corresponde con la interpretacin siguiente: o
El coste reducido de una variable x indica aproximadamente lo que empeorar la funcin a o objetivo (es decir, disminuir en un problema de maximizar o aumentar en un problema a a de minimizar) por cada unidad que aumente el trmino independiente de la restriccin e o x 0. Estrictamente hablando, el coste reducido ha de entenderse como la derivada de la funcin valor o o ptimo respecto al trmino independiente indicado1 (cambiada de signo en los problemas de maxie mizar), por lo que la mejora de la funcin objetivo cuando la condicin de signo pasa a ser x c o o ser aproximadamente c, y sta aproximacin slo es vlida para valores de c sucientemente a e o o a pequeos. n Para problemas lineales el coste reducido tiene una interpretacin2 alternativa: o El coste reducido de una variable x que tome el valor 0 es lo que debe mejorar el coeciente de x en la funcin objetivo para que el valor ptimo de x pase a ser no nulo. (Las variables o o que ya son no nulas tienen coste reducido nulo.) As por ejemplo, por cada saco de pienso de tipo 3 que quisiramos fabricar, los ingresos dismi, e nuir en 1 C o, equivalentemente, para que resulte rentable fabricar sacos de pienso de tipo 3 es an necesario que su precio de venta aumente al menos en 1 C. La columna Dual Price contiene (salvo el signo) los multiplicadores de Kuhn y Tucker (o variables duales, en el caso de la programacin lineal) de las restricciones (excepto la entrada correspondiente o a la funcin objetivo, cuyo valor es siempre igual a 1). El signo es el que se corresponde con la o interpretacin siguiente: o El precio dual de una restriccin indica aproximadamente lo que mejorar la funcin o a o objetivo por cada unidad que aumente el trmino independiente de la restriccin. e o Esto ha de entenerse igualmente como una derivada en las mismas condiciones en que es vlida la a interpretacin de los costes reducidos. o Por ejemplo, por cada kg adicional de avena que pudiramos conseguir los ingresos aumentar en e an 0.36 C. Si hemos seleccionado la opcin para que LINGO calcule los intervalos de sensibilidad, podemos o obtenerlos en el men LINGO Range (teniendo activa la ventana correspondiente al documento .lg4). u El resultado es un nuevo documento .lgr con las tablas siguientes (que en la prctica podemos copiar y a pegar en la ventana que contiene la solucin del problema): o Objective Coefficient Ranges: Current Coefficient 9.000000 12.00000 6.200000 Allowable Increase INFINITY INFINITY 1.000000 Allowable Decrease 1.250000 12.00000 INFINITY
Variable X Y Z
1 Esto bajo el supuesto de que la solucin ptima sea un punto de Kuhn y Tucker y que la funcin valor ptimo sea o o o o diferenciable. En caso contrario la interpretacin anterior no es vlida. Esto sucede si y slo si la solucin ptima es un o a o o o punto regular del problema, es decir, si los gradientes de las restricciones saturadas son linealmente independientes. 2 La condicin necesaria y suciente para que cualquiera de las dos interpretaciones sea vlida en el caso de la programacin o a o lineal es que la solucin ptima no sea degenerada, es decir, que no tenga ninguna variable bsica nula. o o a
Righthand Side Ranges: Current RHS 50000.00 80000.00 40000.00 10000.00 Allowable Increase 10000.00 INFINITY INFINITY 5000.000 Allowable Decrease 50000.00 10000.00 20000.00 10000.00
En problemas de programacin lineal, la interpretacin es la siguiente:3 o o La tabla titulada Objective Coefficient Ranges contiene el valor actual del coeciente de cada variable en la funcin objetivo junto con lo mximo que puede aumentar o disminuir para que la o a solucin ptima no cambie. o o Por ejemplo, mientras el precio de los sacos de tipo 1 no descienda ms de 1.25 C, la solucin ptima a o o del problema seguir siendo la misma. a La tabla titulada Righthand Side Ranges contiene el valor actual de trmino independiente de e cada restriccin junto con lo mximo que puede aumentar o disminuir para que las variables bsicas o a a de la solucin ptima sigan siendo las mismas. Si la restriccin no est saturada podemos decir que o o o a la solucin ptima seguir siendo la misma. o o a Por ejemplo, mientras la cantidad disponible de avena no aumente en ms de 10 000 kg seguir a a siendo cierto que 1. No convendr producir pienso de tipo 3 (z = 0), a 2. Agotaremos toda la avena disponible (la holgura de la avena ser nula), a 3. Agotaremos todo el mijo disponible (la holgura del mijo ser nula). a Se cumple que el precio dual de una restriccin slo es aplicable para determinar (de forma exacta o o en programacin lineal) la mejora de la funcin objetivo que tiene lugar cuando se produce un o o incremento en el trmino independiente de la restriccin que queda dentro del rango indicado en la e o tabla que acabamos de interpretar. Terminamos con algunas observaciones: Si intentamos resolver un problema infactible o no acotado, LINGO lo indica mediante un cuadro de dilogo. a Si resolvemos un problema sin funcin objetivo (por ejemplo, poniendo una exclamacin ante la o o primera l nea de nuestro modelo de ejemplo), LINGO estudia si las restricciones introducidas son o no factibles. Si no hemos puesto etiquetas a las restricciones, LINGO se referir a ellas con nmeros (segn el a u u orden en que las hemos escrito en el modelo), de ah la conveniencia de poner etiquetas.
3 Esta interpretacin slo es vlida en el caso en que la solucin ptima no es degenerada, es decir, que ninguna variable o o a o o bsica es nula. a
Variable X
Value 1900.000
Aqu hay que entender que el coste reducido es (salvo el signo) el multiplicador de Kuhn y Tucker de la restriccin x 1900, y nos indica que por cada unidad que aumentramos el nmero mximo o a u a de sacos de pienso permitidos de tipo 1 los ingresos empeorar en 1.25 C, es decir, aumentar an an en 1.25 C. En general, el coste reducido se reere a la cota (inferior o superior) que est saturada e (y es nulo si ninguna lo est). a No obstante, una instruccin @BND no equivale necesariamente a dos restricciones. Por ejemplo, o si aadimos las restricciones x>-4; x<10; teniendo en cuenta que suponemos marcada la opcin n o Variables assumed non-negative, el rango de variacin de x es en realidad 0 x 10. Sin o embargo, si escribimos @BND(-4,x,10); con ello cancelamos la condicin de no negatividad, y o permitimos que la variable x var entre 4 y 10. e Ms claramente: LINGO asocia a cada variable una cota inferior y una cota superior. Cuando se a selecciona la opcin de variables no negativas la cota inferior de cada variable es 0 por defecto, y la o cota superior es un nmero muy grande por defecto. La instruccin @BND modica el valor de estas u o cotas.
La instruccin @Free(x); declara la variable x como variable libre, es decir, establece a cota inferior o de la variable en un nmero muy pequeo (muy negativo) y la cota superior en un nmero muy u n u grande. En particular, cancela para la variable en cuestin la condicin de no negatividad, si es que o o sta est establecida por defecto. e a La instruccin @GIN(x); obliga a la variable x a tomar valores enteros (positivos o negativos, salvo o que las variables sean no negativas por defecto). La instruccin @BIN(x); obliga a la variable x a tomar unicamente los valores 0 o 1. o La instruccin @Semic(10,x,20); convierte a x en una variable semicontinua, que ha de tomar el o valor 0 o bien estar en el rango 10 x 20. La introduccin en un modelo de variables enteras, binarias o semicontinuas hace que las interpretao ciones indicadas en la seccin anterior de los precios duales y costes reducidos dejen de ser vlidas. o a
Denicin de conjuntos o
LINGO permite introducir los modelos en trminos de conjuntos de e ndices, lo cual aporta numerosas ventajas: Las ecuaciones son independientes de los datos, de modo que se puede cambiar stos sin modicar e aqullas, o incluso se puede escribir un modelo que contenga unicamente las ecuaciones y que lea e los datos de otro documento. Si el modelo tiene varias ecuaciones que siguen un mismo esquema, se pueden introducir todas ellas como una unica frmula general. o La estructura del modelo se simplica, ya que, por una parte, las ecuaciones pueden escribirse conceptualmente, sin mezclarlas con los datos y, por otra, los datos pueden introducirse en un orden ms claro, independiente del lugar en el que deben aparecer en el modelo. a Veamos cmo modelizar el ejemplo de las secciones precedentes en trminos de conjuntos. Para ello o e observamos que todos los datos del problema estn asociados esencialmente a dos conjuntos: un conjunto a de cuatro cereales y un conjunto de tres tipos de pienso. Una forma de introducir estos conjuntos en LINGO es la siguiente: 6
SETS: Cereal/Avena, Maiz, Cebada, Mijo/:Existencias; Pienso/1..3/: Precio, Sacos; ENDSETS Las palabras SETS: ENDSETS determinan una seccin en un modelo de LINGO. En general, una o seccin empieza con su nombre (en este caso SETS) seguido de : (no ;) y termina con END y el o mismo nombre (sin ningn signo de puntuacin). La seccin SETS sirve para denir conjuntos. u o o Para denir un conjunto escribimos su nombre, luego sus elementos entre barras / / y luego, separadas por :, las variables asociadas al conjunto. As por ejemplo, las l , neas anteriores denen un conjunto llamado Cereal cuyos elementos son Avena, Maiz, Cebada, Mijo, de modo que cada cereal tiene asociada una variable Existencias, es decir, que hemos denido cuatro variables4 llamadas Existencias(Avena), Existencias(Maiz), Existencias(Cebada) y Existencias(Mijo). Similarmente, hemos denido un conjunto llamado Pienso cuyos elementos son los nmeros del 1 u al 3, y estos elementos tienen denidas dos variables, Precio y Sacos, de modo que tenemos seis nuevas variables, Precio(1), Precio(2), Precio(3), Sacos(1), Sacos(2), Sacos(3). En vez de 1..3 pod amos haber escrito 1, 2, 3, pero los dos puntos .. son una de las formas abreviadas que admite LINGO para denir los elementos de un conjunto. En general tenemos las posibilidades siguientes (aparte de la enumeracin expl o cita de los elementos): Denicin o 4..7 CH2..CH5 MON..WED OCT..JAN NOV2010..FEB2011 Elementos 4, 5, 6, 7 CH2, CH3, CH4, CH5 MON, TUE, WED OCN,NOV,DEC, JAN NOV2010, DEC2010, JAN2011, FEB2011
Podemos ver las variables que hemos denido resolviendo el problema que hemos tecleado hasta ahora (que de momento slo consta de la seccin SETS). Entonces LINGO nos dice que el problema es o o factible y presenta como ejemplo de solucin factible la siguiente: o Variable EXISTENCIAS( AVENA) EXISTENCIAS( MAIZ) EXISTENCIAS( CEBADA) EXISTENCIAS( MIJO) PRECIO( 1) PRECIO( 2) PRECIO( 3) SACOS( 1) SACOS( 2) SACOS( 3) Value 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568
En general, cuando busca soluciones factibles, LINGO asigna el valor 1.234568 a las variables que no estn sujetas a ninguna restriccin. a o
4 A estas variables les vamos a asignar valores constantes, las existencias de cada cereal dadas en el enunciado del problema, pero en principio LINGO no distingue entre variables y constantes, sino que una variable se convierte en constante en el momento en que se le asigna un valor jo.
Para asignar un valor jo a algunas variables (y convertirlas as en constantes) usamos una seccin o DATA: SETS: Cereal/Avena, Maiz, Cebada, Mijo/:Existencias; Pienso/1..3/: Precio, Sacos; ENDSETS DATA: Existencias = 50000 80000 Precio = 9, 12, 6.20; ENDDATA
40000
10000;
Notemos que hemos separado por comas los distintos precios, mientras que no hemos puesto nada entre las existencias de cada cereal. El uso de comas es opcional (al igual que lo es en la declaracin de o los elementos de un conjunto en la seccin SETS). Si ahora volvemos a resolver el problema veremos que o las constantes ya tienen su valor asignado, y que slo quedan las variables Sacos, que son las autnticas o e variables del problema: Variable EXISTENCIAS( AVENA) EXISTENCIAS( MAIZ) EXISTENCIAS( CEBADA) EXISTENCIAS( MIJO) PRECIO( 1) PRECIO( 2) PRECIO( 3) SACOS( 1) SACOS( 2) SACOS( 3) Value 50000.00 80000.00 40000.00 10000.00 9.000000 12.00000 6.200000 1.234568 1.234568 1.234568
Si hubiramos querido asignar a todas las existencias el valor 10 000 podr e amos haber escrito Esistencias = 10000; Si hubiramos querido dejar las existencias de cebada como variable podr e amos haber escrito: Existencias = 50000, 80000, , 10000; (Este es el unico caso en que el uso de comas es obligatorio.) La declaracin de los elementos de un conjunto puede hacerse indistintamente en la seccin SETS o o o en la seccin DATA. As por ejemplo, podr o , amos haber escrito: SETS: Cereal:Existencias; Pienso/1..3/: Precio, Sacos; ENDSETS DATA: Cereal = Avena Maiz Existencias = 50000 80000 Precio = 9, 12, 6.20; ENDDATA
Cebada 40000
Mijo; 10000;
Igualmente podr amos haber escrito Pienso = 1..3; en la seccin DATA, pero siempre cuidando de o no denir nunca dos veces el mismo conjunto. Si quisiramos denir una constante no asociada a ningn conjunto (por ejemplo, un mximo nmero e u a u de sacos que nos estuviera pemitido producir) lo har amos en la seccin DATA, de este modo: o MaxSacos = 2500; Nos falta introducir la cantidad de cada cereal que contiene cada tipo de pienso. Estas cantidades no estn asociadas ni a los cereales ni a los piensos, sino a las parejas de ambos. Para ello hemos de denir a el conjunto de tales parejas. La forma de hacerlo es la siguiente: SETS: Cereal:Existencias; Pienso/1..3/: Precio, Sacos; Pareja(Pienso, Cereal): Cantidad; ENDSETS DATA: Cereal Cantidad
Cebada 0 20 30 40000
Mijo; 0 10 0; 10000;
La denicin Pareja(Pienso, Cereal) establece que el conjunto Pareja est formado por todos o a los pares de un pienso y un cereal. Cada pareja tiene asociada una variable Cantidad, de modo que hemos denido 12 nuevas variables Cantidad(1, Avena), etc. Igualmente se pueden denir conjuntos de ternas, cudruplas, etc. a A la hora de dar un valor a todas las variables asociadas a un conjunto de parejas, ternas, etc. se jan todos los ndices menos el ultimo y se hace variar ste, luego se aumenta el penltimo y e u se vuelve a hacer variar el ultimo, y as sucesivamente. Por ejemplo, si deniramos una variable e a(I, J, K) donde cada uno de los tres conjuntos tiene elementos 1, 2, habr que introducir los a valores de a en el orden a111 , a112 , a121 , a122 , a211 , a212 , a221 , a222 . Como siempre, los valores sucesivos se pueden separar por comas o no, y tampoco hay ninguna necesidad de cambiar de l nea al completar una la de una tabla, ni mucho menos de alinear sus columnas. Si lo hemos hecho as en la tabla del ejemplo ha sido unicamente por claridad. Tambin habr e amos podido denir simultneamente el conjunto Cereal y las variables Existencias, a as : Cereal, Existencias = Avena 50000, Maiz 80000, Cebada 40000, Mijo 10000; (Como siempre, las comas se pueden suprimir.) Terminamos esta seccin observando que tambin es posible asignar un valor inicial a una variable o e sin que por ello LINGO deje de considerarla variable. Para ello no asignamos el valor en la seccin DATA, o sino en una seccin INIT, as o : INIT: sacos = 1000; ENDINIT 9
Con esto las tres variables sacos toman el valor inicial 1 000. Si slo quisiramos asignar dicho valor a o e sacos(1) tendr amos que haber escrito sacos = 1000, , ; Esto puede ser util cuando conocemos una solucin prxima a la solucin ptima (por ejemplo, porque o o o o vamos a resolver un problema que resulta de modicar levemente otro problema cuya solucin ptima o o conocemos) o bien cuando LINGO tiene dicultad en encontrar una solucin factible y nosotros conocemos o una. En situaciones de este tipo, proporcionar a LINGO una buena solucin inicial puede ayudarle a o encontrar ms rpidamente la solucin ptima. a a o o
Veamos ahora cmo introducir las ecuaciones de un modelo cuando los datos estn expresados en o a trminos de conjuntos. Para el ejemplo que estamos considerando tendr e amos que escribir: SETS: Cereal:Existencias; Pienso/1..3/: Precio, Sacos; Pareja(Pienso, Cereal): Cantidad; ENDSETS DATA: Cereal Cantidad
Cebada 0 20 30 40000
Mijo; 0 10 0; 10000;
[Ingresos] Max = @Sum(Pienso(p): precio(p)*sacos(p)); @For(Cereal(c):[Limite] @Sum(Pienso(p): Cantidad(p, c)*sacos(p))<Existencias(c)); La l nea de la funcin objetivo empieza como siempre, con una etiqueta seguida de Max =. El resto o se lee as Suma para todo pienso p del precio de p por el nmero de sacos producidos de p. En : u general, dentro de @Sum() ponemos el nombre de un conjunto seguido de una nueva variable (en este caso p), que hace referencia a un elemento genrico del conjunto, luego : y la expresin (en e o funcin de p) que queremos sumar para todo p. o La segunda l nea dene simultneamente cuatro restricciones, una para cada cereal. Podemos leer: a Para todo cereal c, denimos la restriccin etiquetada [Limite] como que la suma para todo o pienso p de la cantidad de cereal c en el pienso p por el nmero de sacos producidos de p ha de ser u que las existencias de c.
La sintaxis de @For() es la misma que la de @Sum(). Escribimos el nombre de un conjunto con una nueva variable entre parntesis (en este caso c), luego : y luego lo que queremos que LINGO haga e para cada valor de c.
Las instrucciones de LINGO que recorren los elementos de un conjunto son las siguientes: @For(Conjunto(i): ) @Sum(Conjunto(i): ) @Prod(Conjunto(i): ) @Max(Conjunto(i): ) @Min(Conjunto(i): ) @Writefor(Conjunto(i): ) Repite una tarea para todo i Suma una expresin para todo i o Multiplica una expresin para todo i o Calcula el mximo para todo i a Calcula el m nimo para todo i Escribe una expresin para todo i (vase la seccin 9) o e o 10
En general, cuando dentro de estas instrucciones slo aparece un o ndice, ste se puede suprimir. e Por ejemplo, la funcin objetivo se pod haber introducido as o a : [Ingresos] Max = @Sum(Pienso: precio*sacos); As si queremos exigir que todas las variables del problema sean enteras podemos escribir , @For(Pienso(p): @GIN(Sacos(p))); o simplemente @For(Pienso: @GIN(Sacos)); Podemos anidar cualquiera de estas instrucciones dentro de otra. Por ejemplo: @Sum(A(i): @Sum(B(j): c(i)*d(j))) calcula la suma de ci dj para todo i del conjunto A y todo j del conjunto B. Los bucles pueden recorrer conjuntos de pares, ternas etc., en cuyo caso hemos de introducir tantas variables como componentes tiene el conjunto. Por ejemplo, si queremos sumar todas las cantidades para todo pienso y todo cereal, podemos escribir: @Sum(Pareja(p, c): Cantidad(p, c))
Ms sobre conjuntos a
Es posible denir subconjuntos de un conjunto dado. Por ejemplo:
SETS: Ciudad/C1..C5/:Distancia,Demanda; Extranjera(ciudad)/C4,C5/:x; Carretera(Ciudad, Ciudad)|(&1 #LT# &2):y; ENDSETS DATA: Distancia = 0, 50, 1150, 1200, 1500; Demanda =1000, 2300, 800, 3000, 900; ENDDATA SETS: Lejana(Ciudad)|(Distancia(&1)#GE#1000):z; ENDSETS Aqu hemos denido un conjunto de cinco ciudades C1, C2, C3, C4, C5, cada una de las cuales tiene asociada una distancia y una demanda. A continuacin denimos un subconjunto formado por las ciudades extranjeras, cuyos elementos o son C4, C5. Para denir un subconjunto escribimos su nombre seguido del nombre del conjunto entre parntesis. e Esto signica que, por ejemplo, @Sum(Ciudad(c):Demanda(c)) es la suma de las demandas de todas las ciudades, mientras que @Sum(Extranjera(c):Demanda(c)) es la suma de las demandas de todas las ciudades extranjeras. En general, el hecho de que Extranjera sea un subconjunto de Ciudad se traduce en que las variables denidas sobre los ndices de Ciudad estn denidas tambin para los a e ndices de Extranjera.
11
Un subconjunto se puede denir indicando expl citamente sus elementos (como en el caso de Extranjera) o bien mediante una propiedad que los determine. Es lo que hemos hecho para denir el conjunto Carretera, que consta de los pares de ciudades (Ci , Cj ) con i < j. Para entender la denicin necesitamos tener presentes varias cosas: o LINGO dispone de los operadores lgicos siguientes: o #EQ# #NE# #GE# #GT# #LT# #LE# #AND# #OR# #NOT# igual no igual mayor o igual mayor menor menor o igual y o (inclusivo) no
No hay que confundir el uso de, por ejemplo, #EQ# con el de =. El primero es un operador lgico que da lugar a expresiones que son verdaderas o falsas, mientras que el segundo da lugar o a ecuaciones, como x = y + 1, que no son ni verdaderas ni falsas, sino que expresan relaciones entre variables. Siempre que queramos construir una armacin que deba ser clasicada como o verdadera o falsa de forma inmediata, usaremos los operadores anteriores. Para denir un subconjunto mediante una condicin lgica se escribe el nombre del subconjunto o o (en este caso Carretera, luego entre parntesis el nombre del conjunto que lo contiene (en e este caso el conjunto de parejas de ciudades), luego el signo | y luego la condicin lgica (en el o o ejemplo la hemos puesto entre parntesis por claridad, pero los parntesis se pueden suprimir). e e Luego ya podemos asignar variables al subconjunto, empezando con :, como de costumbre (en este caso hemos asignado a cada carretera una variable y). Para hacer referencia a un elemento genrico del conjunto en la condicin lgica usamos la e o o expresin &1 (y si es un conjunto de parejas de dos conjuntos A y B usaremos &1 para un o elemento genrico del conjunto A y &2 para un elemento genrico del conjunto B, etc.) e e Finalmente hemos denido un conjunto Lejana formado por las ciudades cuya distancia es mayor o igual que 1 000. Notemos que para denirlo era preciso introducir primero las distancias en una seccin DATA, por lo que necesariamente hemos tenido que utilizar dos secciones SETS. o Si resolvemos el problema obtendremos las variables siguientes: X( X( C1, C1, C1, C1, C2, C2, C2, C3, C3, C4, Z( Z( Z( C4) C5) C2) C3) C4) C5) C3) C4) C5) C4) C5) C5) C3) C4) C5) 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568 1.234568
Y( Y( Y( Y( Y( Y( Y( Y( Y( Y(
12
Vemos as que las variables x estn denidas para las ciudades extranjeras, las variables y estn a a denidas para los pares de ciudades sin repeticiones y las variables z estn denidas para las ciudades a lejanas. Tambin podemos seleccionar elementos de un conjunto a la hora de aplicar cualquiera de los e operadores @For(), @Sum, etc. Por ejemplo @Sum(Ciudad(c)| Demanda(c) #GE# 1000: Distancia(c)) suma las distancias a todas las ciudades cuya demanda es mayor o igual que 1 000. Notemos que en este contexto no necesitamos los signos &1, &2,. . . porque ya tenemos variables que nombran a los elementos genricos de los conjuntos (en este caso la variable c). e Hay algunas sutilezas sobre la forma en que LINGO entiende los conjuntos que conviene tener presente para no incurrir en confusiones. La clave es que, para LINGO, los elementos de un conjunto son siempre los primeros nmeros naturales. Por ejemplo, si denimos u SETS: Letras/A, C, J, I, L, P/:Puntos,x; Vocales/A, I/; ENDSETS DATA: Puntos = 1, 3, 4, 6, 9, 12; ENDDATA En realidad para LINGO el conjunto Letras consta de los elementos {1, 2, 3, 4, 5}, y lo que hemos hecho en la denicin es asignar un nombre a cada elemento del conjunto. As para LINGO, A es el nombre o , del elemento 1 de Letras, y C es el nombre del elemento 2, etc. As por ejemplo, si escribimos la restriccin x(3)=5; y resolvemos el modelo, obtendremos la , o solucin o X( X( X( X( X( X( A) C) J) I) L) P) 1.234568 1.234568 5.000000 1.234568 1.234568 1.234568
en la que LINGO ha dado el valor 5 a la variable X(J). En cambio, si escribimos x(J) = 5; obtendremos un error, porque, en contra de lo que uno pueda pensar, J no es un elemento de Letras. Si queremos expresar que x(J) = 5 sin calcular nosotros mismos el ndice correspondiente que hemos de escribir, podemos usar la funcin @Index as o : x(@Index(Letras, J)) = 5; En general, @Index(Conjunto, nombre) proporciona el elemento del conjunto dado (como nmero u natural) cuyo nombre es el dado. Esto es especialmente relevante cuando los nombres de los elementos tambin son nmeros. Por e u ejemplo, si denimos A/2,5,7/:x y hacemos x(2) = 10, LINGO nos dar una solucin en la que a o x(5) tomar el valor 10, porque 2 es el elemento de A cuyo nombre es 5 o, dicho de otro modo, a @Index(A, 5) toma el valor 2. 13
Otro ejemplo: si escribimos z = @Sum(Vocales(v): Puntos(v));, el valor de z que obtendremos no ser Puntos(A)+Puntos(I) = 1 + 6 = 7, sino 4, porque la variable verb/v/ recorre los elementos a de vocales, que son los ndices 1 y 2, luego la suma es Puntos(1)+Puntos(2) = 1 + 3 = 4. Esto se debe a que, en realidad, la denicin del conjunto Vocales no es muy afortunada. Para o evitar estas cosas deber amos haberlo denido como un subconjunto de Letras, es decir, as : SETS: Letras/A, C, J, I, L, P/:Puntos,x; Vocales(Letras)/A, I/; ENDSETS De este modo, Vocales no es un conjunto con elementos {1, 2} (llamados A, I), sino que es el subconjunto formado por los elementos de Letras llamados A, I, luego sus elementos son los nmeros {1, 4}. Con esta denicin, el valor de z ser el 7 esperado, pues ahora la variable v del u o a sumatorio recorrer los a ndices 1 y 4. Es posible usar @Index sin especicar el conjunto, y escribir, por ejemplo x(@Index(P)) = 10; y as obtenemos el ndice de P en el primer conjunto que LINGO encuentra con un elemento llamado P. Si no encuentra ninguno se producir un mensaje de error. Si los conjuntos que manejamos no tienen a (nombres de) elementos en comn, no hay peligro de suprimir el nombre del conjunto al calcular u un ndice, pero en caso contrario podemos obtener resultados inesperados. Lo fundamental es recordar que las variables que recorren elementos genricos de conjuntos recorren e en realidad nmeros naturales y no los nombres que les hemos asignado en cada conjunto. u Las funciones bsicas para operar con conjuntos son las siguientes: a @Index(conjunto, nombre) proporciona el elemento del conjunto (como nmero natuu ral) con el nombre dado. @In(conjunto, nombre) es verdadero si el elemento nombrado est en el conjunto y a falso en otro caso. @Size(conjunto) es el nmero de elementos del conjunto. u
Clculos a
A veces el planteamiento de un modelo requiere realizar algunos clculos con los datos. Tales clculos a a se hacen en una seccin espec o ca llamada CALC. Consideremos por ejemplo el problema siguiente: Una empresa se plantea la posibilidad de emprender seis proyectos de 5 aos de duracin. Se prev n o e que cada uno de ellos d lugar a los ujos de caja determinados por la tabla siguiente: e Proyecto Proyecto Proyecto Proyecto Proyecto Proyecto 1 2 3 4 5 6 Ao 1 Ao 2 Ao 3 Ao 4 Ao 5 n n n n n 1000 800 900 1000 500 800 900 100 1500 1000 1500 100 100 200 1500 1800 90 10 1000 2000 2000 900 1000 1800 1500 950 1000 700 200 0
La empresa dispone de un presupuesto de 2 000 u.m. para el primer ao y de 1 800 u.m. para el segundo n ao. Para los aos siguientes, las inversiones requeridas por cada proyecto debern nanciarse con n n a los benecios proporcionados por los otros. Por otra parte, la empresa puede retrasar el inicio de cada proyecto hasta un mximo de 2 aos. Determinar los proyectos que debe emprender la empresa y el ao en a n n que debe iniciarlos para maximizar el VAN total de su inversin, considerando un factor de capitalizacin o o k = 0.04. Introducimos los datos en el modelo del modo siguiente: 14
-800 900 -900 -100 100 100 -90 -10 900 -1000 1000 500 1800, 0,
Notemos que hemos denido un conjunto de 7 aos porque, como cada proyecto puede retrasarse hasta n un mximo de 2 aos, el proyecto global puede durar hasta un mximo de 7 aos. Vamos a desdoblar a n a n cada proyecto en tres proyectos distintos, segn que se empiece a efectuar en el primer ao, en el segundo u n o en el tercero. Para ello necesitamos ms conjuntos: a SETS: Proyecto/1..6/; Periodo/1..5/; Pareja(Proyecto,Periodo):Flujo; Anyo/1..7/:presupuesto; Inicio/1..3/; Terna(Proyecto, inicio,Anyo):Fl; ProyIni(Proyecto, inicio):Van, x Las variables Fl(p, i, a) contendrn el ujo de caja que genera en el ao a el proyecto p si se inicia a n en el ao i. Las variables Van(p, i) contendrn el VAN del proyecto p si se inicia en el ao i, mientras n a n que las variables x(p,i) sern las autnticas variables del problema, variables binarias que determinarn a e a si se inicia o no el proyecto p en el ao i. Introducimos entonces una seccin CALC para calcular los n o valores Fl(p, i, a) y Van(p,i): CALC: @For(Terna(p,i,a): Fl(p,i,a) = @IF(a-i+1 #GE# 1 #AND# a-i+1 #LE# @Size(Periodo), Flujo(p,a-i+1),0)); @For(ProyIni(p,i): Van(p,i) = @Sum(Anyo(a): (1+k)^(1-a)*Fl(p,i,a))); ENDCALC Para calcular los ujos hemos usado la funcin @IF(condicion, casoV, casoF), que proporciona o como resultado la expresin casoV si la condicion es verdadera y la expresin casoF si es falsa. Hemos o o usado que el ujo en el ao a del proyecto p iniciado en el ao i es el ujo del proyecto p en el periodo n n a-i+1, salvo que este ndice no est entre 1 y 5, en cuyo caso el ujo es 0. e Por denicin, el VAN es la suma de los ujos de caja transportados al ao inicial multiplicndolos o n a por el factor (1 + k)t . Si hubiramos intentado incluir estas l e neas en la seccin DATA habr o amos obtenido un error, pues LINGO no permite hacer clculos con bucles etc. en una seccin DATA. a o 15
Otra diferencia es que en una seccin DATA cada variable puede ser denida slo una vez, mientras o o que en una seccin CALC podemos modicar el valor de una variable denida en una seccin DATA, o o o denir varias veces la misma variable, o dar deniciones de una variable en trminos de ella misma, e como x = 2*y+z; x = x/100; Notemos que si escribiramos estas l e neas fuera de cualquier seccin, LINGO las tomar por reso a tricciones y de la segunda concluir que x = 0. a Ms an, en una seccion CALC podemos hacer que una variable a la que se le ha asignado un valor a u jo (sea en una seccin DATA o CALC) vuelva a ser considerada como variable, mediante la instruccin o o @Release(x); Ahora ya es fcil escribir las restricciones. El modelo completo queda as a : SETS: Proyecto/1..6/; Periodo/1..5/; Pareja(Proyecto,Periodo):Flujo; Anyo/1..7/:presupuesto; Inicio/1..3/; Terna(Proyecto, inicio,Anyo):Fl; ProyIni(Proyecto, inicio):Van, x; ENDSETS DATA: k = 0.04; Flujo = -1000 -800 900 1000 -800 -900 -100 1500 -1500 100 100 200 -1800 -90 -10 1000 -2000 900 -1000 1800 -950 1000 500 -200 Presupuesto = 2000, 1800, 0, 0, ENDDATA
CALC: @For(Terna(p, i,a): Fl(p,i,a) = @If(a-i+1#GE# 1 #AND# a-i+1 #LE# Size(Periodo),Flujo(p,a-i+1),0)); @For(ProyIni(p,i): Van(p,i) = @Sum(Anyo(a): (1+k)^(1-a)*Fl(p,i,a))); ENDCALC [VANTotal] Max = @Sum(ProyIni(p, i): Van(p,i)*x(p, i)); @For(Anyo(a):[ResPres] @Sum(ProyIni(p, i): Fl(p,i,a)*x(p,i))+presupuesto(a)>0); @For(proyecto(p):[UnIni]@Sum(inicio(i): x(p, i))<1); @For(ProyIni: @BIN(x)); Notemos que las restricciones UniIni exigen que cada proyecto se inicie solamente una vez. En una seccin CALC podemos usar la instruccin @SET para establecer las opciones que pueden estao o blecerse manualmente desde el men LINGO Options. . . De este modo nos aseguramos de que nuestro u modelo no se comporte de forma diferente en distintos ordenadores por tener conguraciones distintas por defecto. La sintaxis general es @SET(nombre,valor);, excepto en el caso @SET(Default); que restaura las opciones por defecto y no requiere ningn parmetro. Destacamos algunas de las opciones: u a 16
Por defecto 1
0 1 0 0 0
Descripcin o Restablece las opciones por defecto. Clculos duales: a 0 (none) Ninguno 1 (prices only) Precios duales 2 (prices & ranges Precios duales e intervalos de sensibilidad) 1 busca ptimos globales, 0 no. o 1 supone las variables no negativas, 0 no. 0 22 = 4, 1 22 = 4 1 supone que el modelo es lineal, 0 no. Determina qu escribe LINGO en su informe .lrg: e 0 (verbose) es la opcin por defecto o 1 (terse) Imprime el valor de la funcin objetivo y poco ms o a 2 (errors only) Slo imprime los errores o 3 (nothing) Nada 1 muestra cuadros de dilogo con errores, 0 no. a
Errdlg
Personalizacin de la salida o
Cuando modelizamos un problema con conjuntos, LINGO escribe en su informe .lgr los valores de todas las variables, contando entre ellas los datos del problema, con lo que los valores ms relevantes a pueden quedar perdidos en un mar de nmeros. Para evitar esto podemos personalizar el formato del u informe. Tambin podemos hacer que LINGO escriba parte de la informacin del problema en un archivo e o que pueda a su vez ser le por otra aplicacin para procesar los resultados. do o Sin embargo, a la hora de hacer esto nos encontramos con un inconveniente, y es que LINGO ejecuta primero todas las instrucciones que encuentra en el modelo y nalmente resuelve el problema, con lo que, en principio, no nos da opcin a pedirle que escriba nada relacionado con la solucin (si le pedimos que o o escriba el valor ptimo de las variables, lo har antes de haber resuelto el problema, y no nos dir nada o a a de inters). Para evitar esto debemos denir el problema como un submodelo. e Consideremos por ejemplo el problema estudiado en la seccin anterior, que ahora retocamos as o : SETS: Proyecto/1..6/:ini; Periodo/1..5/; Pareja(Proyecto,Periodo):Flujo; Anyo/1..7/:presupuesto; Inicio/1..3/; Terna(Proyecto, inicio,Anyo):Fl; ProyIni(Proyecto, inicio):Van, x; ENDSETS DATA: k = 0.04; Flujo = -1000 -800 900 1000 500 -800 -900 -100 1500 1000 -1500 100 100 200 1500 -1800 -90 -10 1000 2000 -2000 900 -1000 1800 1500 -950 1000 700 -200 0; Presupuesto = 2000,1800,0,0,0,0,0; ini = 0; ENDDATA
17
SUBMODEL Proyectos: [VANTotal] Max = @Sum(ProyIni(p, i): Van(p,i)*x(p, i)); @For(Anyo(a):[ResPres] @Sum(ProyIni(p, i): Fl(p,i,a)*x(p,i))+presupuesto(a)>0); @For(proyecto(p):[UnIni]@Sum(inicio(i): x(p, i))<1); @For(ProyIni: @BIN(x)); ENDSUBMODEL CALC: @For(Terna(p, i,a): Fl(p,i,a) = @If(a-i+1#GE# 1 #AND# a-i+1 #LE# @Size(Periodo),Flujo(p,a-i+1),0)); @For(ProyIni(p,i): Van(p,i) = @Sum(Anyo(a): (1+k)^(1-a)*Fl(p,i,a))); @SOLVE(Proyectos); ENDCALC Hemos aadido unas variables ini(p) para cada proyecto a las que hemos dado el valor 0. Salvo por n esto, el resultado es el mismo que antes, slo que ahora las ecuaciones del modelo estn incluidas en una o a seccin SUBMODEL. A diferencia de las dems secciones, una seccin SUBMODEL ha de tener necesariamente o a o un t tulo, que en este caso es Proyectos. Como vemos, el t tulo se pone entre la palabra SUBMODEL y los dos puntos. El efecto de esto es que LINGO no resuelve el modelo mientras no se encuentre la instruccin o @SOLVE(Proyectos). Si eliminramos la penltima l a u nea, LINGO no har nada. a De este modo tenemos localizado el momento en que LINGO resuelve el problema. Por ejemplo, si escribimos @Write(x(1,1)); @SOLVE(Proyectos); @Write(x(1,1)); Nos encontraremos con que LINGO escribe el valor 1.234567880630493 antes de la solucin ptima o o (es decir, el valor de la variable x(1,1) antes de que LINGO resuelva el problema) y el valor 1 despus de e la solucin ptima, pues ste es, en efecto, el valor ptimo de dicha variable. Para personalizar el informe o o e o con la solucin escribimos lo siguiente: o @SET(terseo,3); @SOLVE(Proyectos); @For(Proyecto(p): ini(p) = @Sum(inicio(i)|x(p,i) #EQ# 1:i)); @Write(A~o,14* ); n @WriteFor(Anyo(a):a,9* ); @Write(@Newline(1),(15+@Size(Anyo)*10)*-,@Newline(1)); @For(Proyecto(p): !Aqu empieza un bucle. @Write(Proyecto ,p); @IFC(ini(p)#NE#0: !Aqu empieza un condicional; @Write(10*(ini(p)-1)* ); @WriteFor(Periodo(pr): @Format(Flujo(p,pr),10.0f)); ); !Aqu termina el condicional; @Write(@Newline(1))); !Aqu termina el bucle; @Write((15+@Size(Anyo)*10)*-,@Newline(1),Flujo: ); @WriteFor(Anyo(a): @Format(Respres(a)-Presupuesto(a),10.0f)); @Write(@Newline(2),VAN: , @Format(VANTotal,0.2f));
18
Antes de explicar el signicado de estas instrucciones, veamos el resultado: A~o n 1 2 3 4 5 6 7 ------------------------------------------------------------------------------------Proyecto 1 -1000 -800 900 1000 500 Proyecto 2 Proyecto 3 -1500 100 100 200 1500 Proyecto 4 -1800 -90 -10 1000 2000 Proyecto 5 Proyecto 6 -950 1000 700 -200 0 ------------------------------------------------------------------------------------Flujo: -1950 -1600 10 890 1600 2200 1500 VAN: 1673.39 La primera instruccin hace que LINGO no escriba nada por su cuenta en el informe; la siguiente o resuelve el problema, y la siguiente calcula el valor de ini(p) como el ao de inicio del proyecto p n (que conserva su valor 0 si el proyecto no se ejecuta). La instruccin bsica para escribir es @Write(), dentro de la cual ponemos una sucesin de nmeros o a o u y/o cadenas de signos separados por comas. Toda cadena de signos se escribe entre comillas simples o dobles. As la instruccin @Write(A~o,14* ); escribe la palabra Ao seguida de 14 espacios en , o n n blanco (LINGO admite la multiplicacin de un nmero natural n por una cadena, cuyo resultado o u es la cadena repetida n veces). La instruccin @WriteFor(Anyo(a):a,9* ); genera un bucle de escritura. Para cada ao a, o n escribe el valor de a seguido de nueve espacios en blanco. La instruccin @Write(@Newline(1),(15+@Size(Anyo)*10)*-,@Newline(1)); escribe un camo bio de l nea, una cantidad de signos - proporcional al nmero de aos y otro cambio de l u n nea. En general, la instruccin @Newline(n) inserta n cambios de l o nea. Con esto tenemos escritas las dos primeras l neas del informe. A continuacin empieza un bucle @For(Proyecto(p): ); que termina seis l o neas ms abajo. Para a cada valor de p se imprime una l nea del informe. La l nea correspondiente al proyecto p empieza con el texto Proyecto p, que se escribe con la instruccin @Write(Proyecto ,p); o El resto de la l nea contendr datos o estar en blanco en funcin de si el proyecto p se ejecuta o a a o no. Para distinguir ambos casos usamos la instruccin @IFC(ini(p)#NE#0: ); que termina tres o l neas ms abajo. a No hemos de confundir la instruccin @IF(condicion, casoV, casoF), que proporciona un resulo tado, un clculo u otro segn que la condicin sea verdadera o falsa, con la instruccin a u o o @IFC(condicion, instrucciones); que realiza las instrucciones dadas si y slo si la condicin es verdadera. La estudiaremos con ms o o a detalle en la seccin 12. En nuestro caso, resulta que LINGO ejecuta las dos instrucciones siguientes o si y slo si el proyecto p se ejecuta. o La instruccin @Write(10*(ini(p)-1)* ); escribe una cantidad de espacios en blanco proporo cional al ao de inicio del proyecto. n
19
La instruccin @WriteFor(Periodo(pr): @Format(Flujo(p,pr),10.0f)); ejecuta un bucle de o escritura. Para cada uno de los cinco periodos pr escribe el ujo del proyecto p correspondiente al periodo pr. La instruccin @Format() especica la forma en que se escribe un nmero o una cadena. o u Aqu estamos especicando que escriba el ujo en un espacio de 10 caracteres con 0 decimales. Luego describiremos todos los formatos posibles. Tanto si el proyecto se ejecuta como si no, terminamos la l nea con un cambio de l nea dado por la instruccin @Write(@Newline(1)). Con ella termina el paso del bucle correspondiente al proyecto p. o A continuacin escribimos una l o nea de signos - de longitud proporcional al nmero de aos, luego u n un cambio de l nea, y luego la palabra Flujo:. A continuacin un nuevo bucle escribe, para cada ao a, la variable de holgura de la restriccin o n o presupuestaria de dicho ao menos el presupuesto de dicho ao, lo cual es el ujo de caja total de n n dicho ao. n Finalmente escribimos dos cambios de l nea, la palabra VAN: y el valor ptimo de la funcin o o objetivo (con el formato adecuado). Nos falta explicar con detalle el uso de @Format() y el modo de acceder a toda la informacin o relacionada con la solucin ptima (sea para escribirla, sea para manipularla). o o En general, para formatear un nmero escribimos @Format(numero, formato), donde formato u (escrito entre comillas) es una cadena de signos dentro de las posibilidades indicadas en la tabla siguiente: Formato 10.5f 10.5e 10.5g #10.5g Descripcin o Ocupa 10 espacios con 5 decimales Notacin cient o ca en 10 espacios con 5 decimales Notacin decimal o cient o ca en 10 espacios con 5 cifras signicativas Igual que el anterior, pero si hay menos cifras signicativas las completa con ceros.
Tambin se puede usar @Format() con una cadena de signos, en cuyo caso los formatos posibles son e dos: 10s la escribe en 10 espacios justicada a la izquierda, y -10s la escribe en 10 espacios justicada a la derecha. Para hacer clculos sobre la disposicin del texto puede ser util la funcin @Strlen(cadena), que da a o o la longitud de la cadena. Cuando el nmero o la cadena no cabe en el espacio sealado, se sale por la derecha. As por ejemplo, u n , la instruccin @Format(VANTotal,0.2f) no deja ningn espacio para escribir la funcin objetivo, por lo o u o que sta se escribe inmediatamente a continuacin, sin dejar ningn espacio en blanco (con dos decimales). e o u Para referirnos a cualquier variable (en particular, para escribirla) usamos su nombre. As por ejem, plo, para escribir el VAN del primer proyecto si empieza en el ao 1 escribiremos @Write(Van(1,1)); n Para referirnos a una variable de holgura o a la funcin objetivo usaremos la etiqueta de su reso triccin. Por ejemplo, ya hemos visto que @Write(VANTotal); imprime el valor ptimo de la funcin o o o objetivo, y @Write(Respres(1)); escribe la variable de holgura de la restriccin presupuestaria del o ao 1. n Adems podemos aplicar las funciones siguientes al nombre de cualquier variable: a Nombre @Name() @Dual() @RangeD() @RangeU() Resultado Nombre de la variable Variable dual (coste reducido o precio dual) Disminucin mxima en el intervalo de sensibilidad o a Aumento mximo en el intervalo de sensibilidad a
20
Finalmente, la funcin @Status() (sin nada dentro de los parntesis) nos proporciona un cdigo o e o que corresponde al resultado del proceso de resolucin, de acuerdo con la tabla siguiente: o Cdigo o 0 1 2 3 4 5 6 7 8 9 Signicado Optimo global Infactible No acotado Indeterminado (LINGO no ha sabido resolver el problema) Factible Infactible o no acotado Optimo local Localmente infactible Se ha alcanzado el nivel de precisin exigido o Error numrico e
Si escribimos las l neas @Divert(archivo.txt); ... @Divert(); LINGO crear un archivo llamado archivo.txt e imprimir en l todo lo que tenga que imprimir a a e (incluido su informe habitual, si no lo hemos cancelado), hasta que se encuentre con la instruccin o @Divert(); Podemos anidar varias instrucciones de este tipo con distintos nombres de documentos. Cada vez que LINGO encuentra una instruccin @Divert(); cierra el archivo en el que est escribiendo y pasa a o a escribir en el que escrib antes de haber abierto el ultimo, hasta que ya no queda ninguno abierto, y a entonces pasa a escribir en la pantalla (en un documento .lgr).
10
Submodelos
LINGO permite denir varios submodelos parciales, de modo que la instruccin @Solve puede tomar o como argumentos varios submodelos a la vez, con la unica condicin de que entre todos no haya ms de o a una funcin objetivo. Veamos un ejemplo de la utilidad de esta posibilidad. o El modelo siguiente dene un conjunto de 12 escenarios y, para cada uno de ellos, tiene como datos las rentabilidades esperadas de tres activos nancieros llamados ATT, GMT, USX. Cada escenario tiene asociada una probabilidad, que en el ejemplo es la misma para todos ellos, igual a 1/12. El problema consiste en elegir la proporcin X(i) en que cada uno de ellos debe aparecer en una cartera de inversin o o para garantizar una rentabilidad esperada de al menos 1.15% con el m nimo riesgo. Se proponen tres medidas de riesgo diferentes: 1. La varianza, que es la media ponderada (con las probabilidades) de los cuadrados de las desviaciones de la rentabilidad esperada para la cartera en cada escenario respecto de la rentabilidad media en todos los escenarios. 2. La semivarianza, en la que slo se tienen en cuenta las desviaciones negativas, es decir, las de los o escenarios en los que la rentabilidad esperada queda por debajo de la media. 3. El riesgo inferior, en el que la media ponderada se hace tambin considerando las desviaciones e negativas, pero sin elevarlas al cuadrado. Como vemos, se dene un submodelo con las restricciones (en el que, por conveniencia, se calculan las tres medidas de riesgo) y luego otros tres submodelos en los que se escoge una de las funciones como funcin objetivo. Cada instruccin @Solve incluye el submodelo de las restricciones y uno de los objetivos. o o 21
SETS: Escenario/1..12/: Prob, R, DesvSup, DesvInf; Activo/ ATT, GMT, USX/: X; Par(Escenario, Activo): Rent; ENDSETS DATA: Objetivo = 1.15; Rent = 1.300 1.225 1.149 1.103 1.290 1.260 1.216 1.216 1.419 0.954 0.728 0.922 0.929 1.144 1.169 1.056 1.107 0.965 1.038 1.321 1.133 1.089 1.305 1.732 1.090 1.195 1.021 1.083 1.390 1.131 1.035 0.928 1.006 1.176 1.715 1.908; Prob= .08333; ENDDATA Submodel Restricciones: !Esta ecuacin hace que Media sea la media ponderada o sobre todos los escenarios e de las rentabilidades R(e); Media = @SUM(Escenario: Prob * R); Media >= Objetivo; @SUM(activo: X) =1; @FOR(Escenario(e): !Aqu definimos la rentabilidad de la cartera en el escenario e como la media de las rentabilidades de los activos ponderada por el peso de cada uno en la cartera; R(e) = @SUM(activo(i): Rent(e, i) * X(i)); !La ecuacin siguiente define las desviaciones superior e inferior o respecto a la media salvo una constante, pero el objetivo de minimizar har que la constante se ajuste para que al menos una de las dos sea nula; a DesvSup(e) - DesvInf(e) = R(e) - Media); [Varianza] Var = @SUM(Escenario: Prob * (DesvSup + DesvInf)^2); [Semivarianza] Semivar = @SUM(Escenario: Prob * DesvInf^2); [RiesgoInferior] RiesgoInf = @SUM(Escenario: Prob * DesvInf); EndSubmodel Submodel MinVar: [MV] Min = Var; EndSubmodel
22
Submodel MinSemi: [MS] Min = Semivar; EndSubmodel Submodel MinRI: [MR] Min = RiesgoInf; EndSubmodel CALC: @SET(Terseo,3); @Solve(Restricciones, MinVar); @Write(11* ); @WriteFor(Activo:@Format(@Name(x),8s)); @Write( Var Semivar RiesgoInf,@Newline(1)); @Write(MinVar: ); @WriteFor(Activo: @Format(X,8.3f)); @Write(@Format(Var,8.3f),@Format(SemiVar,8.3f), @Format(RiesgoInf,8.3f),@Newline(1)); @Solve(Restricciones, MinSemi); @Write(MinSemi: ); @WriteFor(Activo: @Format(X,8.3f)); @Write(@Format(Var,8.3f),@Format(SemiVar,8.3f), @Format(RiesgoInf,8.3f),@Newline(1)); @Solve(Restricciones, MinRi); @Write(MinRI: ); @WriteFor(Activo: @Format(X,8.3f)); @Write(@Format(Var,8.3f),@Format(SemiVar,8.3f), @Format(RiesgoInf,8.3f),@Newline(1)); ENDCALC El resultado es el siguiente: MinVar: MinSemi: MinRI: X( ATT) X( GMT) X( USX) 0.530 0.357 0.114 0.575 0.039 0.386 0.511 0.489 0.000 Var 0.021 0.024 0.021 Semivar 0.010 0.009 0.012 RiesgoInf 0.056 0.065 0.056
Vemos que las distintas medidas del riesgo llevan a soluciones ptimas diferentes. o
11
La instruccin para leer datos de un chero es @FILE(nombre del fichero). La primera vez que o aparece esta instruccin LINGO abre el chero y lee los datos hasta que aparezca el carcter ~, y cada o a sucesiva aparicin de la instruccin hace que LINGO lea los datos que siguen hasta la prxima aparicin o o o o del carcter ~. Si en lugar de dicho carcter se acaba el chero, LINGO cierra el archivo. Los datos en a a el chero han de estar exactamente igual como estar si los escribiramos directamente en el modelo. an e Por ejemplo, en lugar de SETS: Ciudad/Barcelona, Madrid, Valencia/:demanda; Fabrica/1..20/:oferta; ENDSETS podemos escribir:
23
SETS: Ciudad/@FILE(datos.txt)/:demanda; Fabrica/@FILE(datos.txt)/:oferta; ENDSETS e importar los datos de un archivo llamado datos.txt que contenga el texto siguiente: Barcelona, Madrid, Valencia ~ 1..20 o tambin vale e SETS: Ciudad/@FILE(datos.txt)/:demanda; Fabrica/1..@FILE(datos.txt)/:oferta; ENDSETS si en el archivo de datos escribiemos 20 en lugar de 1..20, o incluso SETS: Ciudad/@FILE(datos.txt)/:demanda; @FILE(datos.txt) ENDSETS si en el archivo de datos escribimos: Barcelona, Madrid, Valencia ~ Fabrica/1..20/:oferta; (Notemos que la ultima l nea no termina en ; porque el ; est ya en el archivo y LINGO lo lee igualmente.) a En suma, cualquier porcin de un modelo puede ser le de un archivo de texto. o da NOTA: Los archivos han de tener peridicamente cambios de l o nea. LINGO no los tendr en cuenta a para nada, pero no leer l a neas demasiado largas.
12
A la hora de dirigir la actividad de LINGO disponemos de varias instrucciones. Ya conocemos @FOR(), que nos permite incluir una lista de instrucciones separadas por ; que se ejecutarn para cada elemento de un conjunto prejado. a Una instruccin similar es @WHILE(), en la que el bucle no depende de un conjunto sino de una o condicin lgica. La sintaxis es: o o @WILE(condicion: instrucciones); Las instrucciones se repetirn hasta que deje de cumplirse la condicin. a o Si en el interior de un bucle @For o @While LINGO se encuentra la instruccin @BREAK saldr del o a bucle inmediatamente. La instruccin @STOP(mensaje de error) abre un cuadro de dilogo con el mensaje de error y o a detiene el clculo. a La instruccin @PAUSE(texto) muestra un mensajde y da la opcin de continuar o detener el o o clculo. El mensaje puede combinar cadenas de texto y nmeros como una instruccin @WRITE. a u o 24
Tambin hemos visto antes la instruccin @IFC. Se puede usar opcionalmente en combinacin con e o o @ELSE. Un ejemplo sencillo ser el siguiente: a DATA: r=?; ENDDATA Submodel Nada: x=0; Endsubmodel CALC: @Solve(Nada); @IFC(r #GE#100: @PAUSE(El nmero es grande); u @ELSE @PAUSE(El nmero es peque~o) u n ); ENDCALC En primer lugar notemos que si en una seccin DATA un dato aparece igualado a ?, LINGO pregunta o por l mediante un cuadro de dilogo en el momento en que tiene que resolver un modelo (pero no e a antes, por eso hemos tenido que crear un modelo tonto, para forzar a LINGO a preguntar por r). Luego tenemos una instruccin @IFC cuya condicin es r 100. Si se cumple LINGO ejecuta o o una unica instruccin (podriamos haber puesto varias), que muestra un cuadro de dilogo. A o a continuacin escribimos @ELSE, cuyo efecto es que las instrucciones que vienen despus se ejecutan o e slo si la condicin es falsa. En este caso LINGO muestra otro cuadro de dilogo distinto. o o a
25