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