背景是我正在尝试使用基于Python的对抗性优化包(PAO)来实现双层优化程序,该程序基于Pyomo。我是 Pyomo 的新手,尽管我之前使用过许多求解器,例如 Gurobi 和 Cplex。为了求解双层优化程序,我需要使用 pao.pyomo.MIBS 求解器。然而,我发现我的 Pyomo 程序甚至无法正确解决幼稚的不平等约束
z[0] != z[1]
。我的代码如下,它试图将值分配给满足约束z[0], z[1] \in {0, 1}
的z[0] != z[1]
:
import pyomo.environ as pyo
from pyomo.environ import *
from pao.pyomo import *
N = 2
M=1024
model = ConcreteModel()
model.z = Var(range(N), domain=Integers)
for i in range(N):
model.z[i].setlb(0)
model.z[i].setub(N-1)
model.delta = Var(range(N), range(N), domain=Binary)
model.unique_z = ConstraintList()
for i in range(N):
for j in range(i+1, N):
model.unique_z.add(model.z[i] - model.z[j] + M*(1-model.delta[i, j]) >= 1)
model.unique_z.add(model.z[i] - model.z[j] - M*model.delta[i, j] <= -1)
model.obj = Objective(expr=sum(model.z[i] for i in range(N)), sense=maximize)
model.L = SubModel(fixed=model.z)
with Solver('pao.pyomo.MIBS') as solver:
results = solver.solve(model)
print("obj =", model.obj.expr(), "z =", [model.z[i].value for i in range(N)])
所以基本约束就像这里,它借助二元变量
z[0] != z[1]
将不等约束delta
表示为线性约束。一个明显的解决方案是 z[0]
或 z[1]
为 1,另一个变量为 0。
但是,我打印了模型的输出,发现模型将
z[0]
和 z[1]
都设置为 0。
>>> model.z.pprint()
z : Size=2, Index=z_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
0 : 0 : 0 : 1 : False : False : Integers
1 : 0 : 0 : 1 : False : False : Integers
>>> model.delta.pprint()
delta : Size=4, Index=delta_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
(0, 0) : 0 : None : 1 : False : True : Binary
(0, 1) : 0 : 0 : 1 : False : False : Binary
(1, 0) : 0 : None : 1 : False : True : Binary
(1, 1) : 0 : None : 1 : False : True : Binary
>>> model.unique_z.pprint()
unique_z : Size=2, Index=unique_z_index, Active=True
Key : Lower : Body : Upper : Active
1 : 1.0 : z[0] - z[1] + 1024*(1 - delta[0,1]) : +Inf : True
2 : -Inf : z[0] - z[1] - 1024*delta[0,1] : -1.0 : True
那么当
z[0]
、z[1]
和delta(0,1)
都为0时,这不是违反了z[0] - z[1] - 1024*delta[0,1] <= -1
约束吗?我不明白为什么这可行。
我是 Pyomo 的初学者。如果我构建的模型或 Pyomo 输出中有任何误解,我将不胜感激任何澄清或建议。谢谢你。
编辑:感谢@AirSquid,问题似乎出在我的“pao.pyomo.MIBS”求解器上。任何人都可以对我当前执行的“pao.pyomo.MIBS”求解器的问题提出一些建议吗?我必须使用这个求解器来执行我的双层优化程序。
我怀疑您的求解代码有问题,并且您正在查看某种未解决或错误的解决方案。我不熟悉您在那里使用的代码序列。我通常:
SolverFactory
你的数学是正确的。我稍微调整了你的模型并使用了不同的解算器,但它有效。您正在双重导入。您应该能够使用第一个 或 第二个导入行。我更喜欢
pyo
前缀,但无论如何。我注释掉了 pao
,因为它在我的示例中没有使用。
请注意,在
pyomo
中,pprint
显示带有变量名称的构造,并且 display
可用于填写(或显示)已求解的值
# import pyomo.environ as pyo
from pyomo.environ import *
# from pao.pyomo import *
N = 6
M=1024
model = ConcreteModel()
model.z = Var(range(N), domain=Integers)
for i in range(N):
model.z[i].setlb(0)
model.z[i].setub(N-1)
model.delta = Var(range(N), range(N), domain=Binary)
model.unique_z = ConstraintList()
for i in range(N):
for j in range(i+1, N):
model.unique_z.add(model.z[i] - model.z[j] + M*(1-model.delta[i, j]) >= 1)
model.unique_z.add(model.z[i] - model.z[j] - M*model.delta[i, j] <= -1)
model.obj = Objective(expr=sum(model.z[i] for i in range(N)), sense=maximize)
# model.L = SubModel(fixed=model.z)
solver = SolverFactory('cbc')
results = solver.solve(model)
# DO THIS. Check for "OPTIMAL"
print(results)
print("obj =", model.obj.expr(), "z =", [model.z[i].value for i in range(N)])
# easy way to inspect the output of a variable (or the whole model)
model.z.display()
# model.display()
Problem:
- Name: unknown
Lower bound: 15.0
Upper bound: 15.0
Number of objectives: 1
Number of constraints: 30
Number of variables: 21
Number of binary variables: 15
Number of integer variables: 21
Number of nonzeros: 6
Sense: maximize
Solver:
- Status: ok
User time: -1.0
System time: 0.27
Wallclock time: 0.46
Termination condition: optimal
Termination message: Model was solved to optimality (subject to tolerances), and an optimal solution is available.
Statistics:
Branch and bound:
Number of bounded subproblems: 270
Number of created subproblems: 270
Black box:
Number of iterations: 4106
Error rc: 0
Time: 0.47368288040161133
Solution:
- number of solutions: 0
number of solutions displayed: 0
obj = 15.0 z = [2.0, 4.0, 0.0, 1.0, 3.0, 5.0]
z : Size=6, Index=z_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
0 : 0 : 2.0 : 5 : False : False : Integers
1 : 0 : 4.0 : 5 : False : False : Integers
2 : 0 : 0.0 : 5 : False : False : Integers
3 : 0 : 1.0 : 5 : False : False : Integers
4 : 0 : 3.0 : 5 : False : False : Integers
5 : 0 : 5.0 : 5 : False : False : Integers