Создайте модель материально-технических ресурсов мультипериода в основанной на проблеме среде

В этом примере показано, как создать модель материально-технических ресурсов мультипериода в основанной на проблеме среде. Проблема состоит в том, чтобы запланировать производство смешений удобрения в течение времени с помощью множества компонентов, затраты которых зависят вовремя предсказуемым способом. Примите, что вы знаете заранее спрос на удобрения. Цель состоит в том, чтобы максимизировать прибыль при удовлетворении требованию, где затраты для покупательных необработанных компонентов и для хранения удобрения в зависимости от времени. Можно определить затраты заранее при помощи фьючерсов или других контрактов.

Удобрения и компоненты

Гранулированные удобрения имеют азот питательных веществ (N), фосфор (P), и калий (K). Можно смешать следующее сырье, чтобы получить смешения удобрения с необходимыми питательными веществами.

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'}

Два смешения удобрения имеют те же питательные требования (10% Н, 10% P и 10% K в развес), кроме "HighN", смешение имеет дополнительные 10% Н для в общей сложности 20% Н.

disp(blendNutrients) % Table is in percentage
         Balanced    HighN
         ________    _____

    N       10        20  
    P       10        10  
    K       10        10  

Сырье имеет следующие имена и питательные проценты в развес.

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  

Сырье Sand не имеет никакого содержания питательных веществ. Песок растворяет другие компоненты, при необходимости, чтобы получить необходимые проценты питательных веществ в развес.

Сохраните количества каждого из этих количеств в переменных.

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

Предскажите спрос и доход

Примите, что вы знаете заранее спрос в весе (тонны) для двух смешений удобрения для периодов времени в проблеме.

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 

Вы знаете цены на тонну, на уровне которой вы продаете смешения удобрения. Эти цены на тонну не зависят вовремя.

disp(blendPrice)
    Balanced    HighN
    ________    _____

      400        550 

Цены на сырье

Примите, что вы знаете заранее цены в тоннах для сырья. Эти цены на тонну зависят вовремя согласно следующей таблице.

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 

Затраты на хранение

Стоимость для хранения смешанного удобрения применяется на тонну и на период времени.

disp(inventoryCost)
    10

Полные ограничения

Можно сохранить не больше, чем inventoryCapacity тонны всего удобрения смешивают в любое время период.

disp(inventoryCapacity)
        1000

Можно произвести в общей сложности не больше, чем productionCapacity тонны в любом периоде времени.

disp(productionCapacity)
        1200

Связь среди производства, продаж и материально-технических ресурсов

Вы запускаете расписание с определенной суммы или материально-технические ресурсы, доступных смешений удобрения. У вас есть определенная цель для этих материально-технических ресурсов в итоговый период. В каждом периоде времени сумма смешения удобрения является суммой в конце предыдущего периода времени, плюс произведенная сумма, минус проданная сумма. Другими словами, в течение многих времен, больше, чем 1:

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

Это уравнение подразумевает, что материально-технические ресурсы считаются в конце периода времени. Периоды времени в проблеме следующие.

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

Первоначальные материально-технические ресурсы влияют на материально-технические ресурсы во время 1 можно следующим образом.

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

Первоначальные материально-технические ресурсы находятся в данных blendInventory{'Initial',:}. Итоговые материально-технические ресурсы находятся в данных blendInventory{'Final',:}.

Примите, что спрос, которому не встречают, потерян. Другими словами, если вы не можете заполнить все порядки в периоде времени, избыточные порядки не переносят в следующий период времени.

Формулировка задачи оптимизации

Целевая функция для этой проблемы является прибылью, которую вы хотите максимизировать. Поэтому создайте проблему максимизации в основанной на проблеме среде.

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

Переменные для проблемы являются количествами смешений удобрения, которые вы делаете и продаете каждый месяц, и необработанные компоненты, которые вы используете, чтобы сделать те смешения. Верхняя граница на sell спрос, blendDemand, для каждого периода времени и каждого смешения удобрения.

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);

Кроме того, создайте переменную, которая представляет материально-технические ресурсы каждый раз.

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

Чтобы вычислить целевую функцию в терминах переменных задачи, вычислите доход и затраты. Доход является суммой, вы продаете каждого смешения удобрения временам цену, добавленную по всем периодам времени и смешениям.

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

Стоимость компонентов является стоимостью для каждого компонента, используемого каждый раз, добавленного по всем периодам времени. Поскольку сумма, используемая каждый раз, разделена на сумму, используемую в каждом смешении, также добавьте по смешениям.

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

Затраты на хранение являются стоимостью для хранения материально-технических ресурсов по каждому периоду времени, добавляемому в зависимости от времени и смешения.

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

Теперь поместите целевую функцию в Objective свойство проблемы при помощи записи через точку.

inventoryProblem.Objective = revenue - ingredientCost - storageCost;

Ограничения задач

Проблема имеет несколько ограничений. Во-первых, выразите уравнение материально-технических ресурсов как набор ограничений на переменные задачи.

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,:);

Выразите ограничение, что итоговые материально-технические ресурсы фиксируются также.

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

Общие материально-технические ресурсы каждый раз ограничены.

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

Можно произвести ограниченную сумму в каждом периоде времени.

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

Сумма, которую вы производите каждый месяц каждого смешения, является количеством сырья, которое вы используете. squeeze функция преобразует сумму от nmonths- by-1-by-nblends массив к nmonths- nblends массив.

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

Питательные вещества в каждом смешении должны иметь необходимые значения. В следующем внутреннем операторе, умножение 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

Поместите ограничения в проблему.

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

Решите задачу

Формулировка задачи завершена. Решите задачу.

[sol,fval,exitflag,output] = solve(inventoryProblem)
Solving problem using linprog.

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'

Отобразите результаты в табличной и графической форме.

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