首页 > 解决方案 > 皮莫 | Couenne 求解器 | 将索引变量域限制为两个整数值

问题描述

我是 Pyomo 的新手,正在努力理解 Pyomo 语法背后的直觉以及它如何构建模型。这可能就是为什么我无法弄清楚如何使用 Pyomo 和 Couenne 求解器定义和解决N个变量必须仅取 ±1 值的“二元”问题。

首先,我尝试了Integersbounds=(-1, 1)并尝试添加严格的不等式:

import pyomo.environ as pyo
import numpy as np
N = 5
w = np.ones(range(N))
pyoModel = pyo.ConcreteModel('binary model')
pyoModel.o = pyo.Var(range(N), bounds=(-1, 1), within=pyo.Integers, initialize=1)
pyoModel.binaryConstraintP = pyo.Constraint(range(N), rule=strictlyPositive)
pyoModel.binaryConstraintN = pyo.Constraint(range(N), rule=strictlyNegative)
pyoModel.objective = pyo.Objective(expr=pyo.sum_product(pyoModel.o, w, index=range(N)), sense=pyo.maximize)
def strictlyPositive(model, i):
    return model.o[i] > 0
def strictlyNegative(model, i):
    return model.o[i] < 0

这最终得到:

ValueError:约束 'binaryConstraintP[0]' 遇到严格的不等式表达式('>' 或 '<')。所有约束都必须使用“<=”、“>=”或“==”来表示。

好的,不允许严格的不等式(不知道为什么!),我尝试切换到Binary域并通过操纵目标中的变量来解决问题,使其位于 {-1, 1} - 即,如果o ∈ {0, 1} 然后 2 xo - 1 ∈ {-1, 1}

import pyomo.environ as pyo
import numpy as np
N = 5
w = np.ones(range(N))
pyoModel = pyo.ConcreteModel('binary model')
pyoModel.o = pyo.Var(range(N), within=pyo.Binary, initialize=1)
pyoModel.objective = pyo.Objective(expr=pyo.sum_product(2 * pyoModel.o - 1, w, index=range(N)), sense=pyo.maximize)

拿到:

TypeError: *: 'int' 和 'IndexedVar' 的不支持的操作数类型

所以我使用了一个二和一的数组,而不是 2 和 1,但又遇到了关于形状广播的错误。我确定我在这里遗漏了一些东西,因为在目标中构建线性方程应该很容易,对吧?

我还尝试将域更改为用户定义的域:

...
pyoModel.domain = pyo.Set(initialize=[-1, 1])
...
pyoModel.o = pyo.Var(range(N), domain=pyoModel.domain, initialize=1)
...
with SolverFactory('couenne') as opt:
    results = opt.solve(pyoModel, load_solutions=False)
    ...

并以Couenne错误告终:

TypeError:名称为“%s”的变量的域类型无效。变量不是连续的、整数的或二进制的。

我也想过使用 SOS,但更难理解它们是如何工作的!

同样,我必须在每种方法中遗漏一些东西。任何帮助都将不胜感激。

旁注:我尽可能简化了原始代码以使其更易于阅读。

标签: pythonpyomomixed-integer-programming

解决方案


不允许严格不等式的原因是它可能不受底层解决方案理论的支持。我相信这适用于 MIP。您是否尝试在您定义的约束范围内将限制设置为非常小的值?例如

def strictlyPositive(model, i):
    return model.o[i] >= 0.000000000000001
def strictlyNegative(model, i):
    return model.o[i] <= -0.000000000000001

以这种方式模拟严格的不等式并不理想,因为它可能会导致数值问题,但值得一试。


推荐阅读