English version German version Italian version

Sesión 6: Aumentando el Modelo para Permitir Embarques entre las Plantas

En la sesión 5, usted encontró un modelo para una compañía de producción que usa multiples plantas para producir sus productos. Lo que usted debe notar acerca del modelo es que mientras que cada una de las diferentes plantas puede ser usada para producir individualmente, todas las ventas e inventarios fueron manejadas colectivamente, desde un origen común para toda la compañía. Ahorá ampliará ese modelo para permitir que cada planta venda los productos y mantenga inventario individualmente. Además, para satisfacer la demanda en la manera más eficiente, los productos pueden ser embarcados entre las plantas, según se necesite.

Para ampliar el modelo usted necesitará incluir dos nuevos índices ficticios, fromplant, y toplant, los cuales representan las plantas origen y las plantas destino. También actualizará las variables Inventory y Sales para incluirlas en el índice plant, así como cada planta puede ahora vender los productos y mantener inventario cada uno independientemente del otro.


Nuevos Conceptos en esta Sesión

Modelos de Transporte

Los Modelos que permiten embarques entre localizaciones son algunas veces llamados Modelos de Distribución o de Transporte. Normalmente, en modelos de transporte, usted tiene orígenes con cierta disponibilidad, destinos con ciertos requerimientos, y usted necesita embarcar los productos desde esos orígenes a esos destinos. En algunos casos, usted tiene modelos de transporte con multiples niveles. Por ejemplo, pueden haber embarques desde las plantas hacia los depósitos, y desde esos depósitos a las tiendas de ventas al por menor.

Modelos de Transbordo

Otro grupo de modelos de distribución son los modelos de transbordo. Esos modelos típicamente surgen cuando usted tiene múltiples localizaciones, donde se producen bienes y también son centros de demanda. Puesto que no hay orígenes ni destinos específicos, usted puede embarcar desde una localización a cualquier otra localización.

Indices Ficticios

Los índices Ficticios son muy usados cuando usted necesita definir un vector, el cual usa el mismo índice más de una vez, como un subíndice. Cuando se embarcan los productos entre plantas usted necesita crear una variable vector, que representa cuánto embarcar entre las plantas. Puesto que las plantas orígen y plantas destino vienen del mismo conjunto de plantas, usted necesita dos índices ficticios para las plantas. El primer índice ficticio es requerido para representar las plantas orígen, y el segundo índice ficticio es requerido para representar las plantas destino.

Usando Condiciones Where(Dónde) sobre las Variables Vector

Algunas veces, cuando se trabaja con variables vector multidimensionales encontrará casos donde no todos los elementos del vector son válidos, o tienen algún significado. Por ejemplo, en los modelos de transbordo tendría poco sentido embarcar un producto de cierta parte de la planta a esa misma planta. En esos casos, se usa la condición WHERE(Dónde) sobre la variable para eliminar elementos innecesarios.

Por ejemplo, en un modelo de transbordo puede eliminar la posibilidad de embarcar a la misma localización, definiendo la variable comos sigue:

     VARIABLES
        Ship[fromplant,toplant] WHERE (fromplant <> toplant);
    

En este caso, la condición (fromplant <> toplant) elimina todos los elementos del vector, donde la planta orígen es la misma que la planta destino.

En algunos casos, hay elementos que necesitan ser excluídos cuando no están basados sobre los valores de los índices. Ellos deben estar basados en algún vector de datos en el modelo. Normalmente, se tiene un vector costo conteniendo cuánto es el costo de embarcar entre las plantas. Para esas plantas, sí el embarque entre ellas no es factible, puede ingresar un valor especial para el costo, tal como cero, para usarlo como un identificador. Luego, en la definición de la variable, puede usar este vector de datos para excluír las rutas de embarque que no son factibles, como sigue:

     VARIABLES
        Ship[fromplant,toplant]
           WHERE (ShipCost[fromplant,toplant] > 0);
    

Restricciones de Equilibrio de Plantas

Cuando se trabaja con modelo de transbordo, necesita asegurarse que la cantidad de productos embarcados a una planta, más cuánto es producido y cuánto es retirado del inventario, debe ser igual a cuánto es embarcado desde la planta, más cuánto es vendido y cuánto ha quedado en inventario. En pocas palabras, cada cosa que llega a la planta debe ser igual a lo que sale de la planta. Esta clase de restricciones es normalmente llamada Restricciones de Equilibrio de plantas . A continuación vemos un ejemplo simple de una restricción de equilibrio de planta:

      PlantBal[plant, product, month]:
         Produce + Inventory[month-1]
       + SUM(fromplant: Ship[fromplant, toplant:=plant])
     =
         Sales + Inventory
       + SUM(toplant: Ship[fromplant:=plant, toplant]);
    

Notará que esta restricción es similar a la restricción de equilibrio de inventario que usted encontró en sesiones anteriores. La única diferencia es que ahora tiene que tomar en cuenta que estamos embarcando a y desde cada una de las plantas ingresando una suma sobre cada una de las plantas para la variable Ship(Embarque).

La asignación del índice 'toplant:=plant', en la primera suma, nos permite especificar que el subíndice toplant debe tomar el valor del subíndice plant para la restricción PlantBal. Esta suma adiciona todos los embarques de cada una de las plantas a una planta en particular en esa restricción. De manera similar, la asignación del índice 'fromplant:=plant', en la segunda suma, especifica que el subíndice fromplant debe tomar el valor del subíndice plant.


Descripción del Problema: Adiciones para Permitir Embarques entre Plantas

En esta sesión, un nuevo modelo será creado donde cada planta actúa ahora separadamente como un centro de demanda para esos productos, y puede también mantener inventario. Usará el modelo creado en la Sesión 5, y haga las adiciones necesarias y luego actualicelo.

Puesto que cada planta puede vender los productos, ahora tenemos una demanda diferente para cada planta, así como también para cada producto y cada mes. La demanda está dada en la siguiente tabla:

Estos datos tienen tres dimensiones, plantas, productos y meses. En modelos de programación Lineal es muy típico tener datos con dimensiones múltiples, posiblemente hasta ocho o más. En la próxima sesión, actualizaremos los datos de la demanda para incluir una dimensión más; máquinas, creando así un vector de cuatro dimensiones.

La capacidad del inventario es ahora diferente para cada planta. Tenemos cuatro valores para la capacidad del inventario, uno para cada planta, 800, 400, 500, y 400 respectivamente.

Puesto que ahora tenemos múltiples plantas, cada una de las cuales puede mantener su inventario, ahora tenemos diferentes costos de inventario para cada planta y cada producto. Los nuevos valores de costos para el inventario se muestran a continuación:

Finalmente, puesto que estamos permitiendo embarques entre las plantas, hay ciertos costos ivolucrados para embarcar un producto, como se muestra en la tabla que sigue:

Como usted puede ver, no hay valores en la tabla donde la planta orígen es la misma que la planta destino. Esto es porque no hay ningún beneficio embarcar a la misma planta.


Formulación del Modelo en MPL

El listado de abajo es la formulación del modelo completo para Planning6. Las adiciones al modelo están resaltadas en negrita para hacer más fácil que se vean los cambios respecto al modelo de la Sesión 5.

     TITLE
         Production_Planning6;

     INDEX
         product   := (A1, A2, A3);
         month     := (Jan, Feb, Mar, Apr);
         plant     := (p1, p2, p3, p4);
         fromplant := plant;
         toplant   := plant;


     DATA
         Price[product]                := (120.00, 100.00, 115.00);
         Demand[plant, product, month] := DATAFILE("Demand6.dat");
         ProdCost[plant, product]      := DATAFILE("ProdCost.dat");
         ProdRate[plant, product]      := DATAFILE("ProdRate.dat");
         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, product,month]      -> Prod;
         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, 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, month] -> PCap:
             SUM(product: Produce / ProdRate)  <=  ProdDaysAvail;

         PlantBal[plant, product, month] -> PBal:
               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
    

Ingrese Nuevos Elementos al Modelo Paso a Paso

Paso 1: Inicie MPL y Cree un Modelo Nuevo

  1. Inicie la aplicación MPL.

  2. Elija File(Archivo) | Open (Abrir) y abra el modelo de la sesión anterior Planning5.mpl.

  3. Elija File(Archivo) | Save As(Guardar Como) para guardarlo como un nuevo archivo del modelo Planning6.mpl.

Paso 2: Cambie el Título al Modelo

Cambie el Título al modelo para que refleje que se está trabajando con el modelo Planning6:

     TITLE
        Production_Planning6;
    

Paso 3: Agregue al Modelo Indices Ficticios para las Plantas Orígen y Plantas Destino

En esta sesión, expandiremos el modelo para permitir embarques entre las plantas. Los Alias indexes (índices ficticios) son usados cuando se necesita definir un vector, el cual se refiere al mismo índice más de una vez, como un subíndice. Los índices ficticios son una copia exacta del índice definido previamente.

En este caso, está creando una variable vector representando cuánto embarcar entre las plantas. Lo que significa que necesita dos índices ficticios para representar las plantas orígen y las plantas destino. Agregue las siguientes definiciones para los nuevos índices ficticios que se llamarán fromplanty toplant al final de la sección INDEX:

      INDEX
         product      := (A1, A2, A3);
         month        := (Jan, Feb, Mar, Apr);
         plant        := (p1, p2,p3, p4);
         fromplant    := plant;
         toplant      := plant;
    

Paso 4: Actualice el Vector de Datos 'Demand' para incluir el Indice 'plant'

Ahora tenemos una demanda diferente para cada planta. La definición para el vector de datos Demand necesita ser aumentado para incluir el índice plant. En el editor del modelo, agregue el índice plant al vector de datos Demand y cambie el nombre del archivo a Demand6.dat.

     DATA
        Price[product]                := (120.00, 100.00, 115.00);
        Demand[plant, product, month] := DATAFILE("Demand6.dat");
    

Puesto que el vector Demand tiene tres índices, el archivo de datos necesita ser actualizado. Además, usted está creando un nuevo archivo de datos llamado 'Demand6.dat' usando los valores de datos de la tabla en la descripción del problema dado anteriormente en esta sesión. Ingrese los valores de los datos al archivo de datos, como sigue:

     !
     ! Demand6.dat - Demand for each product and each plant
     !
     ! Demand[plant,product,month]:
     !
     !           Jan    Feb    Mar    Apr
     !          ---------------------------
     !plant 1:
                 4300,  4200,  6400,  5300,
                 4500,  5400,  6500,  7200,
                 5400,  6700,  7800,  8200,
     !plant 2:
                 5100,  6200,  5400,  7600,
                 6300,  7100,  5200,  6300,
                 4800,  6500,  5000,  7200,
     !plant 3:
                 4100,  6100,  4700,  5800,
                 5300,  5200,  5700,  4100,
                 4200,  4100,  5200,  6300,
     !plant 4:
                 4300,  4100,  5300,  4500,
                 5300,  6400,  4200,  6200,
                 5600,  5200,  3800,  4100
     

Cuando se tiene tres dimensiones de datos en los archivos de datos, liste los valores de los datos en el mismo orden que los índices fueron definidos en el vector de datos del modelo. Por ejemplo, en el archivo de datos de arriba Demand6, el índice que está más a la izquierda es el índice plant, seguido por el índice product y el índice month.

Paso 5: Aumente el Vector de Datos 'InvtCost' y el Dato Constante 'InvtCapacity' Para Incluir el Indice 'plant'

Puesto que ahora se puede almacenar inventarios en cada planta, se necesita actualizar el costo del inventario y los datos de la capacidad del inventario para incluir el índice plant. En el editor del modelo, agregue el índice plant en la declaración del vector de datos InvtCost y el dato constante InvtCapacity. Luego, para el vector de datos InvtCost elimine la lista de números y reemplacelo con la palabra clave DATAFILE y el nombre de archivo 'InvtCost.dat.' Para el InvtCapacity elimine el valor 800 y reemplacelo con la lista de cuatro valores, uno por cada planta, tomándolo de la descripción del problema anterior de esta sesión.

     InvtCost[plant, product] := DATAFILE("InvtCost.dat");
     InvtCapacity[plant]      := (800, 400, 500, 400);
    

Después, necesita crear un nuevo archivo de datos llamado 'InvtCost.dat' usando los valores de costos de la tabla de costos del inventario de la descripción del problema. Ingrese los valores de los datos al archivo de datos, como sigue:

      !
      ! InvtCost.dat - Inventory cost per item a month
      !
      ! InvtCost[plant,product]:
      !
      !         A1    A2    A3
      !     -----------------------
               8.50,  7.00, 6.50
               9.80,  9.80, 9.80
               7.50,  7.50, 7.50
               9.30,  8.00, 6.50
    

Paso 6: Agregue un Vector de Datos para los Costos de Embarque

Hay ciertos costos involucrados en embarcar productos entre plantas. En el editor del modelo, agregue un nuevo vector de datos llamado ShipCost definido sobre los índices ficticios fromplant y toplant seguido por la palabra clave DATAFILE y el nombre de archivo ShipCost.dat.

     ShipCost[fromplant, toplant] := DATAFILE("ShipCost.dat");
    

Después, necesita crear un nuevo archivo de datos llamado ShipCost.dat conteniendo los costos figurados de embarque entre las plantas proporcionados en la descripción del problema. Ingrese los valores de los datos para el archivo de datos, como sigue:

     !
     ! ShipCost.dat - Shipping costs from plant to plant
     !
     ! ShipCost[fromplant, toplant]
     !
                0, 15.00, 21.00, 13.00,
            16.00,     0, 12.00, 12.00,
            14.00, 17.00,     0, 15.00,
            21.00, 13.00, 10.00,     0,
    

Paso 7: Agregue una Variable Vector para Embarques entre Plantas

Estamos permitiendo embarques entre plantas, además, se necesita crear una nueva variable que decida cuánto debe ser embarcado de cada producto por cada mes. Esta variable vector será definida sobre los índices ficticios fromplant y toplant como también los índices product y month. Agregue la siguiente definición a la variable vector Ship de la sección VARIABLES:

     Ship[product, month, fromplant, toplant]
        WHERE (fromplant <> toplant);
    

Puesto que no queremos embarcar un producto de una planta a la misma planta, estamos usando la condición WHERE para eliminar todos los elementos del vector donde la planta orígen es la misma que la planta destino.

Paso 8: Agregue el costo Total de Embarque a la Función Objetivo

En la sección MACROS agregue una nueva definición para el costo total de embarque llamada TotalShipCost y actualice la macro TotalCost para incluir la nueva macro como sigue:

      TotalShipCost := SUM(product, month, fromplant, toplant: ShipCost * Ship);
      TotalCost     := TotalProdCost + TotalInvtCost + TotalShipCost;
    

Note que la actual función objetivo no necesita ser cambiada a la macro TotalCost que contiene todos los cambios.

Paso 9: Aumente la Restricción de Equilibrio de Inventario a la Restricción de Equilibrio de Planta, Agregando la Variable 'Ship'

Puesto que ahora se permiten embarques entre las plantas, se necesita aumentar la restricción de equilibrio de inventario del modelo anterior a la restricción de equilibrio de planta. Primero, cambie el nombre de la restricción de InvtBal a PlantBal y agregue el índice Plant a la declaración. Luego, puesto que la restricción está ahora declarada sobre el índice Plant no tenemos que sumar sobre el índice Plant para la variable Produce una vez más.

     PlantBal[plant, product, month] -> PBal:

               Produce + Inventory[month-1]
             + SUM (fromplant:Ship[fromplant, toplant:=plant])
           =
               Sales + Inventory
             + SUM(toplant: Ship[fromplant:=plant, toplant]);
    

Sobre el lado izquierdo, donde estamos poniendo junto todo lo que está llegando a la planta, agregue una suma para agregar todos los embarques desde cada una de las plantas a la planta actual de la restricción. Dentro de la suma, ingrese la variable Ship con la planta destino tomando el valor del actual índice plant.

Por el lado derecho, donde estamos poniendo junto todo lo que está saliendo de la planta, agregue otra suma para agregar todos los embarques de la planta actual a cada una de las otras plantas. Dentro de la suma ingrese la variable Ship esta vez con la planta orígen tomando el valor del índice actual plant de la restricción.


Resuelva el Modelo y Analice la Solución

El próximo paso es resolver el modelo Planning6 eligiendo Solve CPLEX del menú Run. Sí todo está bien MPL visualizará el mensaje "Optimal Solution Found"(Solución Optima Encontrada). Si hubiera algún error de sintáxis, por favor verifique y compare la formulación que ingresó con el modelo detallado anteriormente en esta sesión.

Usará la ventana de definiciones otra vez como en la Sesión 5 para mirar las partes de la solución en que estamos interesados. Para abrir la ventana de definición del modelo para el modelo Planning6 elija Model Definitions(Definiciones del Modelo) del menú View(Ver).

Ventana Arbol de Definición del Modelo Planning6 Model

Para mirar los valores de la variable Produce, haga doble click sobre el item Produce en el árbol, o seleccione el item y presione el botón View. Esto visualizará una ventana conteniendo solo los valores de la variable Produce como se muestra a continuación.

     VARIABLE Produce[plant,product,month] :

        plant  product  month           Activity     Reduced Cost
       -----------------------------------------------------------
        p1     A1       Jan              4300.0              0.0
        p1     A1       Feb              4200.0              0.0
        p1     A1       Mar              6400.0              0.0
        p1     A1       Apr              5300.0              0.0
        p1     A2       Jan              1080.0              0.0
        p1     A3       Jan              5400.0              0.0
        p1     A3       Feb              5220.0              0.0
        p1     A3       Mar              4590.0              0.0
        p1     A3       Apr              5130.0              0.0
        p2     A1       Jan              5100.0              0.0
        p2     A1       Feb              6200.0              0.0
        p2     A1       Mar              5400.0              0.0
        p2     A1       Apr              7600.0              0.0
        p2     A2       Jan              6177.3              0.0
        p2     A2       Feb              3927.3              0.0
        p2     A2       Mar              5931.8              0.0
        p2     A2       Apr              3681.8              0.0
        p3     A1       Jan              4100.0              0.0
        p3     A1       Feb              6100.0              0.0
        p3     A1       Mar              4700.0              0.0
        p3     A1       Apr              5800.0              0.0
        p3     A3       Jan              4166.7              0.0
        p3     A3       Feb              1933.3              0.0
        p3     A3       Mar              3766.7              0.0
        p3     A3       Apr              2733.3              0.0
        p4     A1       Jan              3850.0              0.0
        p4     A1       Feb              2828.6              0.0
        p4     A1       Mar              5300.0              0.0
        p4     A1       Apr              4500.0              0.0
        p4     A3       Jan              5600.0              0.0
        p4     A3       Feb              5200.0              0.0
        p4     A3       Mar              4677.3              0.0
        p4     A3       Apr              4836.4              0.0
       -----------------------------------------------------------
       

Como puede ver, la producción está ahora distribuída entre las plantas de una manera más efectiva. Ciertos productos son claramente mejores de producir en una planta en particular debido a que se toma en cuenta el costo de producción y el costo de embarque. Por ejemplo, el producto A2 es producido en las plantas p1 y p2, pero no en p3 y p4, mientras que el producto A3 es producido en las plantas p1, p3 y p4. El producto A1 es más económicamente producido en todas plantas.

Si va a la ventana del árbol otra vez y abre una ventana para la variable Ship obtendrá los siguientes valores en la solución:

     VARIABLE Ship[product,month,fromplant,toplant] :

        product  month  fromplant  toplant           Activity     Reduced Cost
       ------------------------------------------------------------------------
        A2       Mar    p2         p4                  331.8              0.0
        A3       Mar    p4         p3                  877.3              0.0
        A3       Apr    p4         p3                  736.4              0.0
       ------------------------------------------------------------------------
    

Como se puede ver, el modelo propone que debemos embarcar el producto A2 desde la planta p2 a la planta p4. De manera similar, A3 es embarcado desde la planta p4 a la planta p3. Claramente, las plantas p2 y p4 tienen capacidad extra a un costo bajo que puede ser usado para producir bienes que las plantas p4 y p3 necesitan.


Back To Top | Maximal Home Page | Overview | Previous Page | Next Page