A menudo, cuando se trabaja con modelos grandes , los datos del modelo tienden a no ser compactos como fueron trabajados en el modelo anterior, sinó más bien en un formato disperso. Los datos compactos pueden ser percibidos de la misma manera como los datos en una hoja de cálculo. Ordinariamente, este es usado para vectores de datos con no más de dos dimensiones, donde cada columna y cada fila es llenada con datos.
Los datos Dispersos, por otro lado, tipicamente involucra multiples dimensiones, pero no necesariamente contienen valores para cada combinación de los índices. Los datos dispersos son usualmente almacenados en formato de tabla, donde cada columna representa un índice o un valor de dato. Cuando se trabaja con grandes conjunto de datos dispersos, es común trabajar con los datos en un formato de tabla. Esto le permite fácilmente saltarse ciertas combinaciones de los índices, que no son válidos, omitiéndolos en la tabla.
Algunas veces, cuando formulamos modelos de planificación de la producción, la decisión involucra cuáles máquinas usar para producir los productos. Como todas las máquinas no están disponibles en cada planta, este presenta una dispersión en el modelo. Cunado definimos los datos y las variables vector del modelo, entonces utilizamos esa dispersión para asegurar que el tamaño del modelo no sea tan grande. Esto puede ser logrado, usando un comando estándar WHERE(Dónde) sobre el vector de datos, o usando el operador IN para asociar los índices relevantes.
El operador IN en MPL le permite seleccionar uno de los índices dominio de un índice multidimensional. Por ejemplo, si tiene un índice multidimensional que especifique cuáles máquinas están disponibles y en qué plantas, usted puede usar el operador IN para sumar sobre todas las máquinas para esa planta en particular.
INDEX plant := (p1, p2, p3, p4); machine := (m11, m12, m13, m21, m22, m31, m32, m41); PlantMach[plant,machine] := (p1.m11, p1.m12, p1.m13, p2.m21, p2.m22, p3.m31, p3.m32, p4.m41);
En el ejemplo de arriba, hemos definido un índice multidimensional llamado PlantMach que asocia a las plantas con las correspondientes máquinas.
El índice PlantMach puede ser usado selectivamente, para elegir sólo las máquinas que están disponibles en una planta en particular. Por ejemplo:
SUBJECT TO PlantCapacity[plant] : SUM(machine IN PlantMach: Produce[machine]) <= MaxCapacity[plant];
En el ejemplo de arriba, sumamos todo cuánto es producido en cada máquina para una planta en particular. Luego nos aseguramos que la producción total esté limitada a la capacidad máxima.
Así como puede almacenar datos en un archivo externo de datos, también puede almacenar índices en archivos de índices externos. Los archivos de índices le permiten almacenar los elementos de un índice en un archivo, en lugar de especificarlos directamente en el modelo. Cuando está definiendo un índice con un archivo índice use la palabra clave INDEXFILE con un nombre de archivo en lugar del listado usual de los elementos. Por ejemplo:
INDEX product := INDEXFILE("Product.idx"); month := INDEXFILE("Month.idx"); plant := INDEXFILE("Plant.idx");
El archivo índice es justamente un archivo de texto estándar que contiene un listado de los elementos índices para un índice particular. Usted puede separar los elementos en el archivo con una coma, un espacio o ambos. Por ejemplo aquí hay un archivo de índice de muestra para el índice product(producto).
! Product.idx - Index element for the product index A1, A2, A3
Generalmente, cuando se trabaja con modelos dispersos, los datos involucrados son muy grandes y vienen de otras aplicaciones, tal como base de datos corporativos o de escritorio. En las sesiones anteriores, los datos fueron tipeados en el archivo del modelo o almacenados en un archivo de datos compactos. Cuando trabajamos con conjuntos de datos grandes, se necesita un método más eficiente para importar los datos a MPL desde otras aplicaciones. Para este propósito, MPL tiene la habilidad de leer los datos desde un archivo de datos dispersos. Este archivo le permite ingresar los datos en un formato de tabla estándar, el cual es más cercano a las actuales características de los datos, por ejemplo, desde una base datos relacional. Un ejemplo de un archivo de datos disperso puede ser como sigue:
ProdCost[plant, machine, product] := SPARSEFILE("ProdCost.dat");
El archivo ProdCost.dat contiene los datos en el formato de columnas orientadas con los índices en las tres primeras columnas y los correspondientes valores de datos al final de cada fila, como sigue:
p1, m11, A1, 73.30, p1, m11, A2, 52.90, p1, m12, A3, 65.40, . . . p4, m41, A2, 63.30, p4, m41, A3, 53.80
Por favor note, que MPL le permite también almacenar multiples columnas de datos en un simple archivo de datos dispersos. Puede especificar cuál columna, agregando una coma y el número de columna de los datos después del nombre de archivo que está dentro del paréntesis.
ProdCost[plant, machine, product] := SPARSEFILE("ProdCost.dat", 2);
El uso de archivos de datos dispersos es común en el modelado del mundo real. Esos archivos pueden terminar siendo muy grandes, con múltiples índices y contener cantidades de datos. Frecuentemente, se tendrá múltiples archivos índices y archivos de datos dispersos almacenando todos los datos y dejando que el archivo del modelo sólo tenga las sentencias actuales del modelo, tal como las variables, función objetivo y las restricciones.
En esta sesión, actualizará el modelo para tener múltiples máquinas distribuídas entre las plantas. Usará el modelo creado en la sesión 6, y haga las adiciones y actualizaciones necesarias.
Puesto que ahora tenemos diferentes máquinas dentro de cada planta, el costo de producción y la tasa de producción tienen ahora diferentes valores para cada máquina. La siguiente es una tabla con una sola fila para cada planta, combinación de productos y máquinas que son aplicables.
Plant | Product | Product | ProdCost | ProdRate |
---|---|---|---|---|
p1 | m11 | A1 | $73.30 | 500 |
m11 | A2 | $52.90 | 450 | |
m12 | A3 | $65.40 | 550 | |
m13 | A3 | $47.60 | 350 | |
p2 | m21 | A1 | $79.00 | 550 |
m21 | A3 | $66.80 | 450 | |
m22 | A2 | $52.00 | 300 | |
p3 | m31 | A1 | $75.80 | 450 |
m31 | A3 | $50.90 | 300 | |
m32 | A1 | $79.90 | 400 | |
m32 | A2 | $52.10 | 350 | |
p4 | m41 | A1 | $82.70 | 550 |
m41 | A2 | $63.30 | 400 | |
m41 | A3 | $53.80 | 350 |
La decisión de Producción, cuánto producir de cada producto, necesita tomarse en cuenta que ahora tenemos múltiples máquinas. Además, se actualizará la variable Produce(Producción) para incluir el índice machine (Máquina) y luego usará la condición WHERE para excluir los elementos que no son aplicables, tal como la planta p1, máquina m11, y producto A3.
El listado de abajo es la formulación del modelo completo Planning7. Las adiciones al modelo son resaltadas en negritas para hacer más fácil ver los cambios con respecto al modelo de la sesión 6.
TITLE Production_Planning7; INDEX product := (A1, A2, A3); month := (Jan, Feb, Mar, Apr); plant := (p1, p2, p3, p4); toplant := plant; fromplant := plant; machine := (m11, m12, m13, m21, m22, m31, m32, m41); DATA Price[product] := (120.00, 100.00, 115.00); Demand[plant, product, month] := DATAFILE("Demand6.dat"); ProdCost[plant, machine, product] := SPARSEFILE("Produce.dat", 1); ProdRate[plant, machine, product] := SPARSEFILE("Produce.dat", 2); ProdDaysAvail[month] := (23, 20, 23, 22); InvtCost[plant, product] := DATAFILE("InvtCost.dat"); InvtCapacity[plant] := (800, 400, 500, 400); ShipCost[fromplant, toplant] := DATAFILE ("ShipCost.dat"); VARIABLES Produce[plant, machine, product, month] -> Prod WHERE (ProdCost > 0); Inventory[plant, product, month] -> Invt; Sales[plant, product, month] -> Sale; Ship[product, month, fromplant, toplant] WHERE (fromplant <> toplant); MACROS TotalRevenue := SUM(plant, product, month: Price * Sales); TotalProdCost := SUM(plant, machine, product,month: ProdCost * Produce); TotalInvtCost := SUM(plant, product, month: InvtCost * Inventory); TotalShipCost := SUM(product, month, fromplant, toplant: ShipCost * Ship); TotalCost := TotalProdCost + TotalInvtCost + TotalShipCost; MODEL MAX Profit = TotalRevenue - TotalCost; SUBJECT TO ProdCapacity[plant, machine, month] -> PCap: SUM(product: Produce / ProdRate) <= ProdDaysAvail; PlantBal[plant, product, month] -> PBal: SUM(machine: Produce) + Inventory[month-1] + SUM(fromplant: Ship[fromplant, toplant:=plant]) = Sales + Inventory + SUM(toplant: Ship[fromplant:=plant, toplant]); MaxInventory[plant, month] -> MaxI: SUM(product: Inventory) <= InvtCapacity; BOUNDS Sales < Demand; END
Inicie la aplicación MPL.
Elija File (Archivo) | Open (Abrir) y abra el modelo de la sesión anterior Planning6.mpl.
Elija File (Archivo ) | Save As (Guardar Cómo) para guardarlo como un nuevo archivo del modelo Planning7.mpl.
Cambie el título del modelo para que refleje que se está trabajando con el modelo Planning7.
TITLE Production_Planning7;
En este modelo, cada planta tiene ahora múltiples máquinas. Para crear un índice para las máquinas agregue la siguiente definición para el índice machine(máquina) en la sección INDEX.
INDEX product := (A1, A2, A3); month := (Jan, Feb, Mar, Apr); plant := (p1, p2, p3, p4); toplant := plant; fromplant := plant; machine := (m11, m12, m13, m21, m22, m31, m32, m41);
El costo de producción y la tasa de producción necesitan ahora ser incluídos al índice de máquinas puesto que tienen diferentes valores para cada máquina. También, puesto que ahora los datos están dispersos, esto es, cada planta no tiene asociado sus máquinas, estaremos almacenando los datos en un archivo de datos dispersos. MPL le permite almacenar mútiples columnas de datos en un archivo sencillo de datos dispersos. Especifique cuál columna va a leer agregando una coma y el número de columna después del nombre del archivo.
Actualice las definiciones para los vectores de datos ProdCost y ProdRate para ser incluídos en el índice machine y cambiar el nombre de archivo a un nuevo archivo de datos dispersos llamado Produce.dat. Para el costo de producción especifique el número de columna 1 después del nombre de archivo y para la tasa de producción especifique el número de columna 2.
DATA Price[product] := (120.00, 100.00, 115.00); Demand[plant, product, month] := DATAFILE("Demand6.dat"); ProdCost[plant, machine, product] := SPARSEFILE("Produce.dat", 1); ProdRate[plant, machine, product] := SPARSEFILE("Produce.dat", 2); ProdDaysAvail[month] := (23, 20, 23, 22); InvtCost[product] := DATAFILE("InvtCost.dat"); InvtCapacity[plant] := (800, 400, 500, 400); ShipCost[fromplant, toplant] := DATAFILE("ShipCost.dat");
Ahora necesita crear el archivo de datos dispersos Produce.dat de los datos en la descripción del problema anterior dados en esta sesión.
Para crear el archivo de datos para el costo de producción abra una nueva ventana del editor para el archivo de datos llamado Produce.dat y escriba lo siguiente:
! ! Produce.dat - Production Cost and Rate ! ! ProdCost[plant, machine, product]: ! ProdRate[plant, machine, product]: ! p1, m11, A1, 73.30, 500, p1, m11, A2, 52.90, 450, p1, m12, A3, 65.40, 550, p1, m13, A3, 47.60, 350, p2, m21, A1, 79.00, 550, p2, m21, A3, 66.80, 450, p2, m22, A2, 52.00, 300, p3, m31, A1, 75.80, 450, p3, m31, A3, 50.90, 300, p3, m32, A1, 79.90, 400, p3, m32, A2, 52.10, 350, p4, m41, A1, 82.70, 550, p4, m41, A2, 63.30, 400, p4, m41, A3, 53.80, 350,
La variable Produce necesita ahora tener el índice machine en las declaraciones como necesitamos saber en qué máquina es producido cada producto. Además, puesto que no todas la máquinas están en cada planta necesitamos excluir las combinaciones que no son válidas. Esto es hecho usando la condición where sobre el vector de datos ProdCost. Las combinaciones de índices son usados sólo cuando ProdCost es mayor que cero o cuando la variable Produce es ampliada. Ingrese los cambios a la variables produce como sigue:
VARIABLES Produce[plant, machine, product, month] -> Prod WHERE (ProdCost > 0);
En la macro del costo total de producción, agregue el índice machine para que refleje que la variable produce contiene ahora el índice machine.
MACROS TotalRevenue := SUM(plant, product, month: Price * Sales); TotalProdCost := SUM(plant, machine, product,month: ProdCost * Produce); TotalInvtCost := SUM(plant, product, month: InvtCost * Inventory); TotalShipCost := SUM(product, month, fromplant,toplant: ShipCost * Ship); TotalCost := TotalProdCost + TotalInvtCost + TotalShipCost;
En la declaración de la restricción de la capacidad de la producción, el índice machine debe ser incluído puesto que ahora tiene un límite de capacidad separada para cada máquina en la planta. Ingrese los cambios a la restricción ProdCapacity como sigue:
SUBJECT TO ProdCapacity[plant, machine, month] -> PCap: SUM(product: Produce / ProdRate) <= ProdDaysAvail;
En la restricción de equilibrio de planta hay una variable produce separada para cada máquina. Como necesitamos agregar junto al total de producción para una planta en particular, necesitamos ahora sumar sobre el índice máquina cuando se refiera a la variables Produce. Para hacer esto agregue la siguiente sumatoria a la restricción PlantBal:
PlantBal[plant, product, month] -> PBal: SUM(machine: Produce) + Inventory[month-1] + SUM(fromplant: Ship[fromplant, toplant:=plant]) = Sales + Inventory + SUM(toplant: Ship[fromplant:=plant, toplant]);
El próximo paso es resolver el modelo 'Planning7.mpl' eligiendo Solve CPLEX del menú Run. Sí todo está bien MPL visualizará el mensaje 'Optimal Solution Found' ( Solución Optima Encontrada) . Sí subiera algún error de sintáxis, por favor verifique la formulación ingresada anteriormente en esta sesión del modelo detallado.
Usará la ventana de definición del modelo otra vez, como en la sesión 6, para mirar las partes de la solución que sean de su interés. Para abrir la ventana de definición del Planning7 elija Model Definitions del menú View (Ver).
Ventana Arbol de Definición del Modelo Planning7
Para ver los valores de la variable Produce haga doble click sobre el icono produce del árbol o seleccionelo y presione el botón View(ver). Este visualizará la ventana View(Ver) conteniendo los valores de la solución solo para la variable produce tal como se muestra más abajo.
VARIABLE Produce[plant,machine,product,month] : plant machine product month Activity Reduced Cost -------------------------------------------------------------------- p1 m11 A1 Jan 4300.0000 0.0000 p1 m11 A1 Feb 4200.0000 0.0000 p1 m11 A1 Mar 5487.5000 0.0000 p1 m11 A1 Apr 5300.0000 0.0000 p1 m11 A2 Jan 6480.0000 0.0000 p1 m11 A2 Feb 5220.0000 0.0000 p1 m11 A2 Mar 5411.2500 0.0000 p1 m11 A2 Apr 5130.0000 0.0000 p1 m12 A3 Feb 9049.3506 0.0000 p1 m12 A3 Mar 916.1616 0.0000 p1 m12 A3 Apr 10803.1169 0.0000 p1 m13 A3 Jan 8050.0000 0.0000 p1 m13 A3 Feb 7000.0000 0.0000 p1 m13 A3 Mar 8050.0000 0.0000 p1 m13 A3 Apr 7700.0000 0.0000 p2 m21 A1 Jan 5100.0000 0.0000 p2 m21 A1 Feb 6200.0000 0.0000 p2 m21 A1 Mar 6538.8889 0.0000 p2 m21 A1 Apr 7600.0000 0.0000 p2 m21 A3 Jan 4422.6136 0.0000 p2 m21 A3 Feb 3927.2727 0.0000 p2 m21 A3 Mar 5000.0000 0.0000 p2 m21 A3 Apr 3681.8182 0.0000 p2 m22 A2 Jan 6900.0000 0.0000 p2 m22 A2 Feb 6000.0000 0.0000 p2 m22 A2 Mar 6900.0000 0.0000 p2 m22 A2 Apr 6600.0000 0.0000 p3 m31 A1 Jan 3300.0000 0.0000 p3 m31 A1 Feb 5964.9351 0.0000 p3 m31 A1 Mar 2550.0000 0.0000 p3 m31 A1 Apr 4477.4026 0.0000 p3 m31 A3 Jan 4700.0000 0.0000 p3 m31 A3 Feb 2023.3766 0.0000 p3 m31 A3 Mar 5200.0000 0.0000 p3 m31 A3 Apr 3615.0649 0.0000 p3 m32 A1 Jan 800.0000 0.0000 p3 m32 A1 Feb 135.0649 0.0000 p3 m32 A1 Mar 2150.0000 0.0000 p3 m32 A1 Apr 1322.5974 0.0000 p3 m32 A2 Jan 7350.0000 0.0000 p3 m32 A2 Feb 6881.8182 0.0000 p3 m32 A2 Mar 6168.7500 0.0000 p3 m32 A2 Apr 6542.7273 0.0000 p4 m41 A1 Jan 4300.0000 0.0000 p4 m41 A1 Feb 4100.0000 0.0000 p4 m41 A1 Mar 5073.6111 0.0000 p4 m41 A1 Apr 4500.0000 0.0000 p4 m41 A2 Jan 2270.0000 0.0000 p4 m41 A2 Feb 5018.1818 0.0000 p4 m41 A2 Mar 2500.0000 0.0000 p4 m41 A2 Apr 5527.2727 0.0000 p4 m41 A3 Jan 3327.3864 0.0000 p4 m41 A3 Mar 2633.8384 0.0000 --------------------------------------------------------------------
La variable Produce está ahora definida sobre cuatro índices: plant(planta), machine(máquina), product(producto) y month(mes). Para cada planta el modelo decide qué máquina es la más eficiente para producir los productos en una planta en particular. Esta tabla puede ser usada como base para un programa de producción para la compañía completa.
La otra variable que es interesante en este modelo es la variable Inventory. Sí va a la ventana del árbol otra vez y abre la ventana View(Ver) para la variable Inventory obtendrá los siguientes valores de la solución:
VARIABLE Inventory[plant,product,month] : plant product month Activity Reduced Cost ----------------------------------------------------------- p1 A2 Jan 800.0000 0.0000 p2 A2 Jan 400.0000 0.0000 p3 A3 Jan 500.0000 0.0000 p4 A3 Jan 400.0000 0.0000 -----------------------------------------------------------
Como usted ve, el modelo ha decidido producir los productos A2 y A3 durante el mes de Enero para asegurar tener lo suficiente en el mes de Febrero.
Muchas de las plantas ahora están trabajando a su capacidad total. Sí usted va a la ventana del árbol y abre otra vez la ventana View(Ver) para la restricción ProdCapacity obtendrá los siguientes valores de la solución:
CONSTRAINT ProdCapacity[plant,machine,month] : plant machine month Slack Shadow Price ----------------------------------------------------------- p1 m12 Jan 23.0000 0.0000 p1 m12 Feb 3.9595 0.0000 p1 m12 Mar 20.2682 0.0000 p1 m12 Apr 1.2033 0.0000 p2 m21 Jan 3.6947 0.0000 -----------------------------------------------------------
Como usted puede ver la planta p1 tiene alguna capacidad extra en la máquina m12 y la planta p2 tiene alguna capacidad extra para la máquina m21. Otra cosa también es que todas las máquinas en cada planta están trabajando a su capacidad total para satisfacer la demanda.