AnyMath 文档
Notebook

基于优化肥料生产实例的多阶段库存管理模型

导言

此示例演示如何使用Engee创建智能生产和库存计划模型。 有必要为未来一年做出战略决策。

让我们想象一下,我们经营一家生产两种类型肥料的工厂。 我们有几种类型的原材料(成分)可供使用,其价格根据众所周知的时间表(例如季节性)每月变化。 与此同时,我们确切地知道每个月客户将订购多少吨每种类型的肥料。 该
目标是实现利润最大化。 要做到这一点,你需要找到之间的完美平衡:

*生产完全一样多,你需要(或者你可以出售它盈利);
*在最便宜的月份购买原材料;
*在经济上可行的情况下将成品存放在仓库中。

对于这样的长期策略,您可以使用金融工具(例如,期货合约)来固定未来的商品价格并保护自己免受风险。 我们的数学模型将帮助您计算最有利可图的计划,考虑到所有这些因素。

我们将连接必要的库。

In [ ]:
using JuMP, DataFrames, GLPK, NamedArrays, Measures

肥料及其组成

颗粒肥料含有三种关键营养素:氮,磷和钾。 在工厂,我们不是从头开始生产它们,而是混合现成的原料,以获得具有正确成分的商业品牌肥料。
我们有几种"成分"-每种都有自己独特的营养成分。 通过以正确的比例组合它们,我们创造了一个成品-一个平衡的肥料,我们的客户需要。

初始数据

我们将在此基础上确定优化生产的数据。:

*对肥料的需求量;
*一年中的月份列表;
*初始股票价值;
*每种肥料中养分的百分比;
*肥料订单的大小;
*肥料价格;
*储存容量;
*存储成本;
*生产能力;
*原材料成本;
*原料中营养成分的含量。

In [ ]:
对食物的需求=DataFrame(
    平衡的= [750, 800, 900, 850, 700, 700, 700, 600, 600, 550, 550, 550],
    高氮= [300, 310, 600, 400, 350, 300, 200, 200, 200, 200, 200, 200]
)
месяцы = ["一月", "二月", "三月", "四月", "五月", "六月", 
          "七月份", "八月份", "9月", "10月", "11月", "12月"]
初始储备=DataFrame(
    平衡=[200,200],
    高氮=[200,200]
)
肥料中的营养成分=DataFrame(
    平衡=[10,10,10],
    高氮=[20,10,10]
)
食品订单=DataFrame(
    平衡的= [200, 400, 400, 400, 400, 400, 200, 0, 0, 0, 0, 0],
    高氮= [0, 100, 200, 200, 200, 200, 200, 0, 0, 0, 0, 0]
)
肥料价格=DataFrame(
    平衡=[400],
    高氮=[550]
)
存储容量=1000
单位存储成本=10
生产功率=1200

原材料成本=DataFrame(
    磷酸一铵= [350, 360, 350, 350, 320, 320, 320, 320, 320, 310, 310, 340],
    氯化钾_= [610, 630, 630, 610, 600, 600, 600, 600, 600, 600, 600, 600],
    Ammiachna_选择器= [300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300],
    硫酸铵_铵= [135, 140, 135, 125, 125, 125, 125, 125, 125, 125, 125, 125],
    三过磷酸钙= [250, 275, 275, 250, 250, 250, 250, 240, 240, 240, 240, 240],
    沙子= [80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80]
)

feed_containment_in原料=DataFrame(
    磷酸一铵=[11,48,0],
    氯化钾=[0,0,60],
    Ammoniacal_seliter=[35,0,0],
    硫酸铵=[21,0,0],
    Ternar_superphosphate=[0,46,0],
    =[0,0,0]
)
肥料类型=名称(肥料需求量)
вещества = ["氮", "磷,磷", "钾"]
原料种类=名称(原料成本) 
肥料种类数=长度(肥料种类)
原料种类数=长度(原料种类)
营养素的数量=长度(物质)
月数=长度(月)
每月需求量=副本(肥料需求量)
插入!(需求以月为单位,1,:月=>)
以月为单位的原材料成本=副本(原材料成本)
插入!(以月为单位的原材料成本,1,:月=>月)
名称=副本的肥料的含量(营养肥料的含量)
插入!(名称为,1,:Nutrition_material=>物质的肥料的含量)
名称的原料含量=副本(营养原料的含量)
插入!(名称为,1,:Nutrition_material=>substances的原料含量)

让我们定义一个以表格形式显示数据的函数。

In [ ]:
function вывести_таблицу(df::DataFrame, заголовок::String="")
    如果!isempty(标头)
        println("\n$标题:")
    end
    列名=名称(df)
    列width_=[]
    对于列名中的列_
        宽度=长度(字符串(列))
        for i in 1:nrow(df)
            =df[i,]
            如果isa(值,数字)
                string_values=string(round(Int,value))
            else
                string_values=字符串(值)
            end
            宽度=最大(宽度,长度(string_values))
        end
        推!(列width_,宽度+2 
    end
    заголовок_таблицы = ""
    for(i,column)in enumerate(column name_)
        表heading_=rpad(列,列width_[i]
    end
    println(表头)
    разделитель = ""
    用于列宽中的宽度_
        разделитель *= repeat("-", ширина)
    end
    println(分隔符)
    for i in 1:nrow(df)
        строка = ""
        for(j,column)in enumerate(column name_)
            =df[i,]
            如果isa(值,数字)
                string_values=string(round(Int,value))
            else
                string_values=字符串(值)
            end
            *=rpad(row_values,列width_[j])
        end
        println(字符串)
    end
    println()
end

有两种类型的肥料可用:

*平衡-标准成分是10%氮,10%磷,10%钾。

*高氮-氮-增强版:20%氮,10%磷,10%钾。

唯一的区别是"高氮"中氮的比例增加了一倍,这使得生产更昂贵。

In [ ]:
println("肥料中的养分含量(以百分比计):")
查看表(包含名称的改进内容)
肥料中的养分含量(以百分比计):

营养-物质平衡、高氮  
-------------------------------------------------------
氮1020             
磷10 10             
钾10 10             

原料及其营养成分(以重量百分比计):

In [ ]:
println("原料中营养成分的含量(以百分比计):")
查看表(带名称的原料内容)
原料中营养物质的含量(以百分比计):

营养磷酸一铵氯化钾硫酸亚铵超磷酸钙砂  
-----------------------------------------------------------------------------------------------------------------------
氮110352100      
磷48 0 0 0 46 0      
钾0 60 0 0 0 0      

砂是中性填料。 里面没有营养素。 它用作"稀释剂",以在活性成分过于浓缩时准确地保持成品混合物中所需的百分比。

化肥订单量和价格

在整个计划期间,我们知道每个品牌肥料的每月订单的确切数量。

In [ ]:
println("订购量:")
检查表(需求以月为单位)
订购量:
月平衡高氮  
-------------------------------------------
一月750300            
二月800310            
三月900600            
四月850400            
五月700350            
六月700300            
7月700 200            
8月600 200            
9月600 200            
十月550200            
十一月550 200            
十二月550200            

价格是固定的全年。 这意味着我们的收入只取决于销售量,而不是时间。 这种稳定性简化了规划,使您能够专注于成本优化。

In [ ]:
println("化肥价格:")
查看表(肥料价格)
化肥价格:
平衡高氮  
---------------------------------
400               550            

原材料的成本

原材料价格是我们模型中的一个关键变量。 与成品的稳定价格不同,成分成本每个月都会发生变化(例如,由于季节性或市场条件)。

In [ ]:
println("原材料的成本:")
查看表(以月为单位的原材料成本)
原材料的成本:
月磷酸一铵氯化钾硫酸亚铵超磷砂  
-----------------------------------------------------------------------------------------------------------
一月35061030013525080     
二月36063030014027580     
三月35063030013527580     
四月35061030012525080     
5月32060030012525080     
六月32060030012525080     
7月32060030012525080     
8月32060030012524080     
9月32060030012524080     
十月31060030012524080     
十一月31060030012524080     
十二月34060030012524080     

生产及储存

我们将显示单位存储成本,仓库容量和生产能力。

In [ ]:
println("单位存储成本:$单位存储成本")
println("仓库容量:▪仓库容量")
println("生产能力:$production_power")
单位存储成本:10
仓库容量:1000
生产能力:1200

如果我们无法在一个月内生产和运送全部订单,余额将不会转移到下个月。 这迫使模型始终在需求之前计划生产。 因此,该模型正在寻找一个平衡点:生产足够的订单并达到目标余额,但不能生产太多,以免产生存储成本。

设置任务

该模型基于需要最大化的目标函数。 在我们的情况下,这是一个利润。

In [ ]:
模型=模型(GLPK。优化器)
Out[0]:
A JuMP Model
├ solver: GLPK
├ objective_sense: FEASIBILITY_SENSE
├ num_variables: 0
├ num_constraints: 0
└ Names registered in the model: none

变量

任务中的变量是我们每个月生产和销售的肥料混合物的体积,以及用于制造它们的原材料。

In [ ]:
@variable(model,produce[1:月数,1:改进类型数]>=0)
@variable(model,sell[1:月数,1:改进类型数]>=0)
@变量(型号,用途[1:月数,1:原料种类数,1:肥料种类数]>=0

此外,我们将创建一个变量,表示每个时间点的库存量。

In [ ]:
@变量(型号,0<=库存[1:月数,1:肥料种类数]<=仓库容量)

销售上限是每个时间段和每个品牌肥料的需求量。

In [ ]:
对于i in1:月数,b in1:肥料类型的数量
    set_upper_bound(sell[i,b],demand for fertilities[i,b])
end

表达方式

要使用任务变量计算目标函数,您需要计算收入和成本。 收入是每种类型肥料的销售量乘以其价格,在所有时间段和所有类型的肥料中总结。 让我们定义一个收入表达式。

In [ ]:
@expression(model,revenue,sum(prices for fertilizers[1,j]*sum(sell[i,j]for i in1:number of months)for j in1:肥料种类的数量))

让我们定义一个原材料成本的表达式。 原材料成本是在每个时间点使用的每种成分的成本,在所有时期内总结。 由于每个时刻使用的原料体积除以每种肥料的使用量,因此求和也按肥料的类型进行。

In [ ]:
@expression(model,raw materials used[i=1:月数,r=1:原料种类数],sum(use[i,r,b]for b in1:肥料种类数))
@expression(model,total cost of raw materials,sum(cost of raw materials[i,r]*raw materials used[i,r]for i in1:number of months for r in1:number of types of raw materials))

让我们定义一个存储成本的表达式。 储存成本是在每个时间段内维持库存的成本,由时间和肥料类型总结。

In [ ]:
@表达式(模型、总存储成本、单位存储成本*总和(股票))

目标功能

让我们定义目标函数。

In [ ]:
@objective(模型,最大值,收入-原材料的一般价值-存储的一般价值)

限制

模型必须符合关键生产规则。:

*库存余额:仓库中的余额是上个月余额与生产和销售的产品数量差异之和;
*目标股票:到年底,有必要达到设定的平衡水平;
*限制:仓库容量和工厂容量有限;
*物料平衡:成品量等于消耗的原料量;
*质量:每批次的化学成分必须严格符合配方。

所有这些规则都形式化为数学约束并加载到模型中以找到最优计划。

In [ ]:
@constraint(model,material_balance1[i=2:月数,b=1:肥料种类数], 
    stocks[i,b]==stocks[i-1,b]+produce[i,b]-sell[i,b])
@constraint(model,material_balance2[b=1:改进类型数],
    stocks[1,b]==初始股票[1,b]+produce[1,b]-sell[1,b]
@constraint(model,final stocks[b=1:肥料种类数],stocks[月数,b]==initial stocks[2,b])
@constraint(model,storage limite_[i=1:月数],sum(stocks[i,:])<=存储容量)
@constraint(model,capacity limite_[i=1:月数],sum(produce[i,:])<=生产能力)
@约束(型号,原料用量[i=1:月数,b=1:肥料种类数], 
    sum(use[i,r,b]for r in1:quantity of raw materials)==produce[i,b])
@约束(模型,肥料的质量[i=1:月数,n=1:养分数量,b=1:肥料种类数量],
    sum(原料中的营养含量[n,r]*use[i,r,b]for r in1:quantity of raw materials)==肥料中的营养含量[n,b]*produce[i,b])

解决和可视化结果

让我们开始解决优化问题。

In [ ]:
优化!(型号)

让我们将解决方案显示为表格(如果表格的宽度不适合,请在浏览器中缩小)。

In [ ]:
状态=termination_status(模型);
如果状态==MOI。最佳
    利润=(Int,objective_value(模型))
    println("\找到最优解")
    println("利润:$利润")
    value_product=值。(生产)
    value_sell=值。(卖出)
    stock_values=值。(股票)
    产生圆形=圆形。(Int,要产生的值)
    sell_rounded=圆形。(Int,卖出值)
    stock_四舍五入=圆形。(Int,stock_values)
    生产table_=DataFrame()
    对于1中的b:肥料类型的数量
        таблица_производства[!, Symbol("生产_" * replace(виды_удобрений[b], " " => "_"))] = производить_округленные[:, b]
    end
    销售表_=DataFrame()
    对于1中的b:肥料类型的数量
        таблица_продаж[!, Symbol("出售_" * replace(виды_удобрений[b], " " => "_"))] = продавать_округленные[:, b]
    end
    库存表_=DataFrame()
    对于1中的b:肥料类型的数量
        таблица_запасов[!, Symbol("股票_" * replace(виды_удобрений[b], " " => "_"))] = запасы_округленные[:, b]
    end
    生产计划=hcat(生产表,销售表,库存表)
    生产计划[,:月]=
    生产计划=生产计划[:,[end,1:end-1...]]
    println("\生产计划:")
    查看表(生产计划)
end
产生平衡=产生圆角[:,1];
产生高氮=产生圆角[:,2];
卖出平衡=卖出四舍五入[:,1];
卖出高氮=卖出四舍五入[:,2];
stock_balanced=stock_四舍五入[:,1];
高氮股=圆形股[:,2];
已找到最优解
利润:2247394

生产计划:
生产月高氮油高氮库存高氮储备高氮  
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
一月11001007503005500                     
二月6003108003103500                     
3月550650900600050                    
四月85035085040000                     
5月70035070035000                     
6月700 300 700 300 0 0                     
7月700 200 700 200 0 0                     
8月600 200 600 200 0 0                     
9月600 200 600 200 0 0                     
10月550 200 550 200 0 0                     
十一月550 200 550 200 0 0                     
十二月750400550200200200                   

我们将显示a平衡肥料的最佳生产,销售和库存的直方图。

In [ ]:
p1 = bar(месяцы, производить_сбалансированное, title="制作人", xlabel="", color=:green, ylabel="数量")
p2 = bar(месяцы, продавать_сбалансированное, title="已售出", xlabel="", color=:green, ylabel="数量")
p3 = bar(месяцы, запасы_сбалансированное, title="股票", color=:green, ylabel="数量")
graph1=plot(p1,p2,p3,layout=(3,1),size=(1000,900),margin=10mm,legend=false)
显示(图1)

我们将显示高氮肥料的最佳生产,销售和库存的直方图。

In [ ]:
p1 = bar(месяцы, производить_высокоазотное, title="制作人", xlabel="", color=:orange, ylabel="数量")
p2 = bar(месяцы, продавать_высокоазотное, title="已售出", xlabel="", color=:orange, ylabel="数量")
p3 = bar(месяцы, запасы_высокоазотное, title="股票", color=:orange, ylabel="数量")
graph2=plot(p1,p2,p3,layout=(3,1),size=(1000,900),margin=10mm,legend=false)
显示(图2)

结论

对多阶段生产任务进行的建模证明了优化方法在动态市场中的战略规划的有效性。 该解决方案提供了一个准确和实用的计划。

主要调查结果:

  1. 发布策略:该模型确定了在需求高峰期生产高利润产品的优先级,而基础产品支持整体产能利用率。 这与利润最大化的目标直接一致。

  2. 储备的动态作用:分析表明,储备不是作为储备,而是作为一个积极的缓冲,平滑可变需求和固定能力之间的不平衡。 采用计划积累和随后减少库存的策略来最大限度地减少总成本。

  3. 约束的影响:对产能和目标端平衡的严格约束形成计划的特定结构,导致生产尖峰满足边界条件。 这证实了系统对控制参数的高灵敏度。

因此,该模型充分地将复杂的规划任务形式化,并将其转化为优化任务。 其结果是一个战略地图,确定利润增长点和系统瓶颈,这使得这种方法成为证明管理决策合理的有价值的工具。