PYOMO:使用集合和参数定义数据集以解决优化问题
Posted
技术标签:
【中文标题】PYOMO:使用集合和参数定义数据集以解决优化问题【英文标题】:PYOMO: Defining dataset using Sets and Parameters for solving an optimization problem 【发布时间】:2021-03-19 21:44:18 【问题描述】:我正在尝试将一些数据公式化为 PYOMO 模型以解决优化问题。
materials = ['steel', 'alum', 'carbon', 'cheese']
每种材料都有 2 个属性 - 密度和电导率,它们的值定义如下。
density = 'steel' : 1.2,
'alum' : 0.8,
'carbon': 1.8,
'cheese': 0.7
conductivity = 'steel' : 6.4,
'alum' : 3.1,
'carbon': 4.4,
'cheese': 0.3
目标函数计算 2 个矩形板的重量,如下所示:
Objective function = Area_1 * thickness_1 * density_1 + Area_2 * thickness_2 * density_2
其中,Area_1、thickness_1、density_1分别为板块1的面积、厚度和密度。
每个板的面积和厚度都是固定的。但是密度值取决于求解器选择的材料以获得最佳结果。该模型还有一个约束定义如下:
(conductivity_1/thickness_1) + (conductivity_2/thickness_2) => 22
所以,求解器在为板选择密度值时,还必须选择相同材料的电导率值。
如果有人能帮助我解决这个问题,我将不胜感激。如果您有不同的想法来解决这个问题,我也欢迎。谢谢。
【问题讨论】:
解决这个问题并不费力。您刚刚从其他问题中回收了我的大部分示例。看看这个网站上的 pyomo dox 或其他几个 pyomo 问题的例子。我已经发布了一些使用双索引的方法,它们可能会帮助您入门。让我们看一下对此的最小功能示例更新。现在你的问题太宽泛了。 一个好的第一步是确定如何以数学方式表示您的问题(您的决策变量是什么,您如何根据决策变量和参数来表示您的约束和目标函数?)跨度> @AirSquid 谢谢你的信息。我会尝试这种方式。 @cookesd 我的决策变量是面积、厚度、电导率和密度。在 4 个变量中,面积和厚度是板的固定值。但是,电导率和密度由求解器确定以获得最佳解。所以当求解器选择一个板的密度值时,它也必须选择相同材料的电导率值。谢谢。 【参考方案1】:这是一个我认为可以满足您所有问题的示例模型。
一旦您将第二个索引设置为板 P = 1, 2, 3
在这种情况下为 3 个板,那么我们需要对我们的决策变量进行双重索引以表示材料 m
到板 p
的分配。在这个例子中,4 种材料,3 块板。
这里可能有许多其他的约束变体,但我添加的约束总体上回答了您关于电导率的问题。请注意,我还添加了一个约束以确保为每个板分配 1 种且只有 1 种材料。根据模型中的其他约束,您可能需要/可能不需要这个,但它可以很好地防止虚假答案。这也是使用 pyomo
中的函数 - 规则组合的“for each”约束样式的示例。
结果...铝和奶酪三明治...:)
# material selection model
import pyomo.environ as pyo
# data
materials = ['steel', 'alum', 'carbon', 'cheese']
density = 'steel' : 1.2,
'alum' : 0.8,
'carbon': 1.8,
'cheese': 0.7
conductivity = 'steel' : 40.8,
'alum' : 30.1,
'carbon': 42.4,
'cheese': 15.3
price = 'steel' : 2.3,
'alum' : 3.5,
'carbon': 5.8,
'cheese': 6.0
# t area
plate_dims = 1: (10, 150),
2: (12.5, 200),
3: (8, 125)
mdl = pyo.ConcreteModel('material selector')
# SETS (used to index the decision variable and the parameters)
mdl.M = pyo.Set(initialize=materials)
mdl.P = pyo.Set(initialize=plate_dims.keys())
# VARIABLES
mdl.x = pyo.Var(mdl.M, mdl.P, domain=pyo.Binary) # select material M for plate P
# PARAMETERS
mdl.density = pyo.Param(mdl.M, initialize=density)
mdl.conductivity = pyo.Param(mdl.M, initialize=conductivity)
mdl.price = pyo.Param(mdl.M, initialize=price)
mdl.p_thickness = pyo.Param(mdl.P, initialize= k:v[0] for k,v in plate_dims.items())
mdl.p_area = pyo.Param(mdl.P, initialize= k:v[1] for k,v in plate_dims.items())
# OBJ (minimize total density)
mdl.obj = pyo.Objective(expr=sum(mdl.x[m, p] * mdl.p_thickness[p]
* mdl.p_area[p] * mdl.density[m]
for m in mdl.M for p in mdl.P))
# CONSTRAINTS
# minimum conductivity
mdl.c1 = pyo.Constraint(expr=sum(mdl.x[m, p] * mdl.conductivity[m]/mdl.p_thickness[p]
for m in mdl.M for p in mdl.P) >= 5.0)
# must populate all plates with 1 material
def c2(model, plate):
return sum(mdl.x[m, plate] for m in mdl.M) == 1
mdl.c2 = pyo.Constraint(mdl.P, rule=c2)
# solve it
solver = pyo.SolverFactory('glpk')
result = solver.solve(mdl)
mdl.display()
产量:
Model material selector
Variables:
x : Size=12, Index=x_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
('alum', 1) : 0 : 0.0 : 1 : False : False : Binary
('alum', 2) : 0 : 0.0 : 1 : False : False : Binary
('alum', 3) : 0 : 1.0 : 1 : False : False : Binary
('carbon', 1) : 0 : 0.0 : 1 : False : False : Binary
('carbon', 2) : 0 : 0.0 : 1 : False : False : Binary
('carbon', 3) : 0 : 0.0 : 1 : False : False : Binary
('cheese', 1) : 0 : 1.0 : 1 : False : False : Binary
('cheese', 2) : 0 : 1.0 : 1 : False : False : Binary
('cheese', 3) : 0 : 0.0 : 1 : False : False : Binary
('steel', 1) : 0 : 0.0 : 1 : False : False : Binary
('steel', 2) : 0 : 0.0 : 1 : False : False : Binary
('steel', 3) : 0 : 0.0 : 1 : False : False : Binary
Objectives:
obj : Size=1, Index=None, Active=True
Key : Active : Value
None : True : 3600.0
Constraints:
c1 : Size=1
Key : Lower : Body : Upper
None : 5.0 : 6.516500000000001 : None
c2 : Size=3
Key : Lower : Body : Upper
1 : 1.0 : 1.0 : 1.0
2 : 1.0 : 1.0 : 1.0
3 : 1.0 : 1.0 : 1.0
【讨论】:
我有一个关于您使用 Sets 和 Params 的问题。您是否看到在具体模型中使用它们而不是在其他 python 对象(列表、numpy 数组、pandas 数据帧)中使用模型数据有什么好处?我通常使用后者,但我不确定我是否错过了功能 @cookesd 我不知道没有将参数和集合放入模型中会错过太多,我只是认为模型中的故障排除(尤其是集合)更容易,并且使用mdl.pprint()
并查看 everything 很好,并且声明子集和稀疏集 within
更大的集也有利于错误检测。
@RuaGoa 我认为您需要找到一些关于线性规划/整数规划的教程材料或文本,因为您似乎没有 pyomo 问题,而是数学编程的基本问题。这就是它的完成方式,并且使用二进制变量是正确的。写出数学并检查它。求解器引擎将为 x[m, p]
选择 1/0 值以最小化目标。如果您想查看目标的表达式,可以将行 mdl.obj.pprint()
添加到代码中并查看表达式并插入二进制值以查看数学。
@AirSquid 你能解释一下如何打印从目标函数中获得的每个板块的最小值吗?
@AirSquid 我对表达式中的“sum()”命令持怀疑态度。它是指所有组合的总和还是仅仅意味着一个数组?以上是关于PYOMO:使用集合和参数定义数据集以解决优化问题的主要内容,如果未能解决你的问题,请参考以下文章
从 pandas DataFrame 在 pyomo 中定义参数