Esta página aún no se ha traducido para esta versión. Puede ver la versión más reciente de esta página en inglés.

Crear modelo de inventario Multiperíodo en el marco basado en problemas

En este ejemplo se muestra cómo crear un modelo de inventario de varios períodos en el marco basado en problemas. El problema es programar la producción de mezclas de fertilizantes durante un período de tiempo utilizando una variedad de ingredientes cuyos costos dependen del tiempo de una manera predecible. Supongamos que usted sabe de antemano la demanda de los fertilizantes. El objetivo es maximizar las ganancias mientras se reúne la demanda, donde los costos son para la compra de ingredientes crudos y para almacenar fertilizantes en el tiempo. Puede determinar los costos por adelantado utilizando futuros u otros contratos.

Fertilizantes e ingredientes

Los fertilizantes granulares tienen nutrientes nitrógeno (N), fósforo (P) y potasio (K). Puede mezclar las siguientes materias primas para obtener mezclas de fertilizantes con los nutrientes necesarios.

load fertilizer blends = blendDemand.Properties.VariableNames % Fertilizers to produce
blends = 1x2 cell array
    {'Balanced'}    {'HighN'}

nutrients = rawNutrients.Properties.RowNames
nutrients = 3x1 cell array
    {'N'}
    {'P'}
    {'K'}

raws = rawNutrients.Properties.VariableNames % Raw materials
raws = 1x6 cell array
    {'MAP'}    {'Potash'}    {'AN'}    {'AS'}    {'TSP'}    {'Sand'}

Las dos mezclas de fertilizantes tienen los mismos requisitos de nutrientes (10% N, 10% P, y 10% K en peso), excepto que la mezcla "HighN" tiene un 10% N adicional para un total de 20% N.

disp(blendNutrients) % Table is in percentage
         Balanced    HighN          ________    _____      N       10        20       P       10        10       K       10        10   

Las materias primas tienen los siguientes nombres y porcentajes de nutrientes en peso.

disp(rawNutrients) % Table is in percentage
         MAP    Potash    AN    AS    TSP    Sand          ___    ______    __    __    ___    ____      N    11        0      35    21     0      0       P    48        0       0     0    46      0       K     0       60       0     0     0      0   

La materia prima no tiene contenido nutricional.Sand La arena diluye otros ingredientes, si es necesario, para obtener los porcentajes requeridos de nutrientes por peso.

Almacene los números de cada una de estas cantidades en variables.

nBlends = length(blends); nRaws = length(raws); nNutrients = length(nutrients);

Previsión de demanda e ingresos

Supongamos que usted sabe de antemano la demanda de peso (toneladas) para las dos mezclas de fertilizantes para los períodos de tiempo en el problema.

disp(blendDemand)
                 Balanced    HighN                  ________    _____      January        750        300      February       800        310      March          900        600      April          850        400      May            700        350      June           700        300      July           700        200      August         600        200      September      600        200      October        550        200      November       550        200      December       550        200  

Usted sabe los precios por tonelada en la que se venden las mezclas de fertilizantes. Estos precios por tonelada no dependen del tiempo.

disp(blendPrice)
    Balanced    HighN     ________    _____        400        550  

Los precios de las materias primas

Supongamos que usted sabe de antemano los precios en toneladas para las materias primas. Estos precios por tonelada dependen del tiempo de acuerdo con la siguiente tabla.

disp(rawCost)
                 MAP    Potash    AN     AS     TSP    Sand                  ___    ______    ___    ___    ___    ____      January      350     610      300    135    250     80      February     360     630      300    140    275     80      March        350     630      300    135    275     80      April        350     610      300    125    250     80      May          320     600      300    125    250     80      June         320     600      300    125    250     80      July         320     600      300    125    250     80      August       320     600      300    125    240     80      September    320     600      300    125    240     80      October      310     600      300    125    240     80      November     310     600      300    125    240     80      December     340     600      300    125    240     80  

Costo de almacenamiento

El costo para almacenar fertilizante mezclado se aplica por tonelada y por período de tiempo.

disp(inventoryCost)
    10 

Restricciones de capacidad

Usted puede almacenar no más de toneladas de mezclas de fertilizantes totales en cualquier período de tiempo.inventoryCapacity

disp(inventoryCapacity)
        1000 

Puede producir un total de no más de toneladas en cualquier período de tiempo.productionCapacity

disp(productionCapacity)
        1200 

Conexión entre producción, ventas e inventario

Se inicia la programación con una cierta cantidad, o inventario, de mezclas de fertilizantes disponibles. Usted tiene un determinado objetivo para este inventario en el período final. En cada período de tiempo, la cantidad de fertilizante mezcla es la cantidad al final del período de tiempo anterior, más la cantidad producida, menos la cantidad vendida. En otras palabras, para veces mayor que 1:

inventory(time,product) = inventory(time-1,product) + production(time,product) - sales(time,product)

Esta ecuación implica que el inventario se contabiliza al final del período de tiempo. Los periodos de tiempo en el problema son los siguientes.

months = blendDemand.Properties.RowNames; nMonths = length(months);

El inventario inicial afecta al inventario en el momento 1 como se indica a continuación.

inventory(1,product) = initialInventory(product) + production(1,product) - sales(1,product)

El inventario inicial está en los datos.blendInventory{'Initial',:} El inventario final está en los datos.blendInventory{'Final',:}

Supongamos que la demanda no satisfechas se pierde. En otras palabras, si no puede rellenar todos los pedidos en un período de tiempo, los pedidos sobran no se llevan al siguiente período de tiempo.

Optimización problema formulación

La función objetiva para este problema es el beneficio, que desea maximizar. Por lo tanto, cree un problema de maximización en el marco basado en problemas.

inventoryProblem = optimproblem('ObjectiveSense','maximize');

Las variables para el problema son las cantidades de mezclas de fertilizantes que usted hace y vende cada mes, y los ingredientes crudos que utiliza para hacer esas mezclas. El límite superior es la demanda, para cada período de tiempo y cada mezcla de fertilizantes.sellblendDemand

make = optimvar('make',months,blends,'LowerBound',0); sell = optimvar('sell',months,blends,'LowerBound',0,'UpperBound',blendDemand{months,blends}); use  = optimvar('use',months,raws,blends,'LowerBound',0);

Además, cree una variable que represente el inventario en cada momento.

inventory = optimvar('inventory',months,blends,'LowerBound',0,'UpperBound',inventoryCapacity);

Para calcular la función objetiva en términos de variables problemáticas, calcule los ingresos y costes. Los ingresos son la cantidad que se vende de cada fertilizante mezcla veces el precio, añadido a lo largo de todos los períodos de tiempo y mezclas.

revenue = sum(blendPrice{1,:}.*sum(sell(months,blends),1));

El costo de los ingredientes es el costo de cada ingrediente utilizado en cada momento, añadido a lo largo de todos los periodos de tiempo. Debido a que la cantidad utilizada en cada momento se separa en la cantidad utilizada para cada mezcla, también agrega sobre las mezclas.

blendsUsed = sum(use(months,raws,blends),3); ingredientCost = sum(sum(rawCost{months,raws}.*blendsUsed));

El costo de almacenamiento es el costo para almacenar el inventario a lo largo de cada período de tiempo, agregado a lo largo del tiempo y mezclas.

storageCost = inventoryCost*sum(inventory(:));

Ahora coloque la función objetiva en la propiedad del problema usando la notación de puntos.Objective

inventoryProblem.Objective = revenue - ingredientCost - storageCost;

Restricciones de problemas

El problema tiene varias restricciones. En primer lugar, exprese la ecuación de inventario como un conjunto de restricciones en las variables de problema.

materialBalance = optimconstr(months,blends); timeAbove1 = months(2:end); previousTime = months(1:end-1); materialBalance(timeAbove1,:) = inventory(timeAbove1,:) == inventory(previousTime,:) +...     make(timeAbove1,:) - sell(timeAbove1,:); materialBalance(1,:) = inventory(1,:) == blendInventory{'Initial',:} +...     make(1,:) - sell(1,:);

Exprese la restricción de que el inventario final también es fijo.

finalC = inventory(end,:) == blendInventory{'Final',:};

El inventario total en cada momento está delimitado.

boundedInv = sum(inventory,2) <= inventoryCapacity;

Puede producir un importe limitado en cada período de tiempo.

processLimit = sum(make,2) <= productionCapacity;

La cantidad que se produce cada mes de cada mezcla es la cantidad de materias primas que se utilizan. La función convierte la suma de un-por-1-por-array a a-por-Array.squeezenmonthsnblendsnmonthsnblends

rawMaterialUse = squeeze(sum(use(months,raws,blends),2)) == make(months,blends);

Los nutrientes de cada mezcla deben tener los valores requeridos. En la siguiente declaración interna, la multiplicación agrega los valores de nutrientes en cada momento sobre las materias primas utilizadas.rawNutrients{n,raws}*use(m,raws,b)'

blendNutrientsQuality = optimconstr(months,nutrients,blends); for m = 1:nMonths     for b = 1:nBlends         for n = 1:nNutrients             blendNutrientsQuality(m,n,b) = rawNutrients{n,raws}*use(m,raws,b)' == blendNutrients{n,b}*make(m,b);         end     end end

Coloque las restricciones en el problema.

inventoryProblem.Constraints.materialBalance = materialBalance; inventoryProblem.Constraints.finalC = finalC; inventoryProblem.Constraints.boundedInv = boundedInv; inventoryProblem.Constraints.processLimit = processLimit; inventoryProblem.Constraints.rawMaterialUse = rawMaterialUse; inventoryProblem.Constraints.blendNutrientsQuality = blendNutrientsQuality;

Resuelve el problema

La formulación del problema está completa. Resuelve el problema.

[sol,fval,exitflag,output] = solve(inventoryProblem)
Optimal solution found. 
sol = struct with fields:
    inventory: [12x2 double]
         make: [12x2 double]
         sell: [12x2 double]
          use: [12x6x2 double]

fval = 2.2474e+06 
exitflag =      OptimalSolution  
output = struct with fields:
         iterations: 162
    constrviolation: 5.4570e-12
            message: 'Optimal solution found.'
          algorithm: 'dual-simplex'
      firstorderopt: 6.5235e-12
             solver: 'linprog'

Mostrar los resultados en forma tabular y gráfica.

if exitflag > 0     fprintf('Profit: %g\n',fval);     makeT = array2table(sol.make,'RowNames',months,'VariableNames',strcat('make',blends));     sellT = array2table(sol.sell,'RowNames',months,'VariableNames',strcat('sell',blends));     storeT = array2table(sol.inventory,'RowNames',months,'VariableNames',strcat('store',blends));     productionPlanT = [makeT sellT storeT]     figure     subplot(3,1,1)     bar(sol.make)     legend('Balanced','HighN','Location','eastoutside')     title('Amount Made')     subplot(3,1,2)     bar(sol.sell)     legend('Balanced','HighN','Location','eastoutside')     title('Amount Sold')     subplot(3,1,3)     bar(sol.inventory)     legend('Balanced','HighN','Location','eastoutside')     title('Amount Stored')     xlabel('Time') end
Profit: 2.24739e+06 
productionPlanT=12×6 table
                 makeBalanced    makeHighN    sellBalanced    sellHighN    storeBalanced    storeHighN
                 ____________    _________    ____________    _________    _____________    __________

    January          1100           100           750            300            550              0    
    February          600           310           800            310            350              0    
    March             550           650           900            600              0             50    
    April             850           350           850            400              0              0    
    May               700           350           700            350              0              0    
    June              700           300           700            300              0              0    
    July              700           200           700            200              0              0    
    August            600           200           600            200              0              0    
    September         600           200           600            200              0              0    
    October           550           200           550            200              0              0    
    November          550           200           550            200              0              0    
    December          750           400           550            200            200            200