我目前正在致力于用 Python 实现 MINLP 优化问题。为了解决这个问题,我使用了 Pyomo 环境和 Couenne 求解器(版本 0.2.2)。
除以下限制外,到目前为止,所有限制均已制定,没有任何问题。具体来说,挑战是为优化变量制定约束,我们称之为
model.x = pyo.Var(range(0, 25), bounds=(Min_value, Max_value), domain=pyo.NonNegativeReals)
这样:
model.x
的最大值和最小值应具有最小间隔S。
换句话说,
max(model.x) - min(model.x) >= S
。
不幸的是,你不能直接使用内置的Python max() 和 min() 函数。
def Min_Max(model):
return max(model.x)- min(model.x) >= S
model.Const_MinMax = pyo.Constraint(rule=Min_Max)
出现以下错误:
ValueError: Invalid constraint expression.
The constraint expression resolved to a trivial Boolean (False) instead of a Pyomo object.
Please modify your rule to return Constraint.Infeasible instead of False.
在Python中,由于某种原因,它只取
model.x
的最大和最小索引(整数值)并减去它们。很明显,返回了一个布尔表达式,这是一个不正确的 Pyomo 数据类型。
我认为可能使用的数据类型是:
<class 'pyomo.core.expr.numeric_expr.LinearExpression'>
或者
<class 'pyomo.core.expr.relational_expr.EqualityExpression'>
<class 'pyomo.core.expr.relational_expr.InequalityExpression'>
使用
max(pyo.value(model.x[i]) for i in range(0, 25))
也是不可行的,因为它只在开始时检查model.x
的初始化值,并且在优化过程中不会检索该值。
此外,我尝试使用循环和 if 语句来找到最小值和最大值。这也不起作用,好像条件不允许(再次由于布尔上下文)。 错误信息:
PyomoException: Cannot convert non-constant Pyomo expression (x[1] < x[0]) to bool.
This error is usually caused by using a Var, unit, or mutable Param in a
Boolean context such as an "if" statement, or when checking container
membership or equality. For example,
m.x = Var()
if m.x >= 1:
pass
and
m.y = Var()
if m.y in [m.x, m.y]:
pass
would both cause this exception.
但是,Pyomo 提供了
pyo.Expr_if
条件。因此,我尝试按如下方式构建循环。
def Min_Max (model):
Min=model.x[0]
Max=model.x[0]
for i in range(0,25):
Max=pyo.Expr_if(model.x[i]>Max,model.x[i],Max)
Min=pyo.Expr_if(model.x[i]<Min,model.x[i],Min)
return Max-Min>= S
model.Const_MinMax = pyo.Constraint(rule=Min_Max)
不幸的是,这也没有取得成功。虽然求解器不再给出错误消息,但它也不会开始求解。造成这种情况的可能原因是循环创建的高度嵌套的 if 条件。
我现在的问题是是否有人有解决方法来实现这个条件? 如果我想实现这个条件,是否建议使用 Pyomo 以外的环境?
如果对病情仍有疑问或需要进一步解释,请告诉我。
好吧,你已经尝试了所有“非法”方式:
max(), min(), abs()
等,因为它们是非线性函数所以,挑战是如何使其线性。如果您想强制 x
值之间的
maximal分离,问题会容易得多。如果是这种情况,您将需要:
您的问题有点复杂,因为您想要强制执行最小间隔。下面是一个例子。我认为您可能会陷入进行成对比较的困境,正如我在约束中所示的那样。然后,您有一个次要约束来基本上强制分离约束至少一次有效。
为了使这个机制发挥作用,您还需要一个 Big-M 值来限制,在不是选定值的情况下使分离约束过低。您应该适当选择
M
。另外,您应该尽可能使用 pyomo Sets,而不是 range(),它更容易编写、排除故障或修改。
该示例只是尝试最小化
x
的总和,但强制执行最小增量。您可以看到x[4]
“为团队拿一份。”
import pyomo.environ as pyo
delta = 5 # the required sep between at least 2 elements
M = 100 # the maximum possible separation
m = pyo.ConcreteModel()
### SETS
m.S = pyo.Set(initialize=range(5))
### VARS
m.x = pyo.Var(m.S, domain=pyo.NonNegativeReals)
m.selected = pyo.Var(m.S, m.S, domain=pyo.Binary,
doc='Selected indices for the pair with required delta')
### OBJ: minimize sum of x
m.obj = pyo.Objective(expr=sum(m.x[s] for s in m.S))
### CONSTRAINTS
@m.Constraint(m.S, m.S)
def delta_met(m, s1, s2):
return m.x[s1] - m.x[s2] >= delta * m.selected[s1, s2] - M * (1 - m.selected[s1, s2])
m.requirement_met = pyo.Constraint(expr=sum(m.selected[s1, s2] for s1 in m.S for s2 in m.S) >= 1)
m.pprint()
### SOLVE
solver = pyo.SolverFactory('cbc')
res = solver.solve(m)
print(res)
m.x.display()
# m.selected.display()
x : Size=5, Index=S
Key : Lower : Value : Upper : Fixed : Stale : Domain
0 : 0 : 0.0 : None : False : False : NonNegativeReals
1 : 0 : 0.0 : None : False : False : NonNegativeReals
2 : 0 : 0.0 : None : False : False : NonNegativeReals
3 : 0 : 0.0 : None : False : False : NonNegativeReals
4 : 0 : 5.0 : None : False : False : NonNegativeReals