Python Pyomo | Couenne solver |将索引变量域限制为两个整数值

Python Pyomo | Couenne solver |将索引变量域限制为两个整数值,python,pyomo,mixed-integer-programming,Python,Pyomo,Mixed Integer Programming,我是Pyomo的新手,正在努力理解Pyomo语法背后的直觉以及它是如何构建模型的。这可能就是为什么我无法使用Pyomo和Couenne解算器来定义和解决“二进制”问题,其中N变量只能取±1个值 首先,我尝试使用边界=(-1,1)的整数域,并尝试添加一个严格的不等式: import pyomo.environ as pyo import numpy as np N = 5 w = np.ones(range(N)) pyoModel = pyo.ConcreteModel('binary mode

我是Pyomo的新手,正在努力理解Pyomo语法背后的直觉以及它是如何构建模型的。这可能就是为什么我无法使用Pyomo和Couenne解算器来定义和解决“二进制”问题,其中N变量只能取±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), 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
得到:

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

所以我用了一个由2和1组成的数组,而不是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)
    ...
最终导致库恩错误:

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

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

同样,我肯定在每种方法中都遗漏了一些东西。任何帮助都将受到感谢


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

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

def strictlyPositive(model, i):
    return model.o[i] >= 0.000000000000001
def strictlyNegative(model, i):
    return model.o[i] <= -0.000000000000001
def严格阳性(i型):
返回模型.o[i]>=0.000000000000001
def严格负性(i型):

返回模型。o[i]由于使用了严格不等式,您的第一次尝试失败了,这是一个禁忌。这背后有一个理论,因为这类问题的求解者在问题空间的“凸包”上工作。要了解更多信息,请选择一篇关于线性规划的文章——它超出了堆栈溢出答案的范围

你的第二次尝试是正确的。如果您正在寻找±1的数学等价物,则将x设为二进制变量并使用线性转换2x-1是完全合适的。您在那里的尝试失败,因为您通过在
Var()
构造中提供索引,将
x
变量声明为索引变量,但您没有在目标中使用索引

下面是一个使用索引变量的示例。如果您只有一个单例,那么只需删除索引集引用即可

from pyomo.environ import *

some_constants = {  0: 100,
                    1: 200,
                    2: -50,
                    3: 300,
                    4: 50}

m = ConcreteModel('plus & minus ones project')

m.S = Set(initialize=range(5))
m.c = Param(m.S, initialize=some_constants)
m.x = Var(m.S, within=Binary)    # creates {m.x[0], m.x[1], ... , m.x[4]}

# try to maximize the sum of x*c
m.obj = Objective(expr=sum((2*m.x[s] - 1)*m.c[s] for s in m.S), sense=maximize)

# some constraint to limit the number of "+1 picks" to 2...easy with binary vars.
m.C1 = Constraint(expr=sum(m.x[s] for s in m.S) <= 2)

m.pprint()

谢谢你的快速回答!因此,我错过的是我宣布目标的方式。事实上,我想避免for循环,因为我的“真实”情况更复杂:
xt*M*x
。顺便说一句,你们的解决方案是否可以扩展到param
m.c
的矩阵形式?你们认为这适用于整数吗?老实说,我不太确定这是一个猜测,对不起。
from pyomo.environ import *

some_constants = {  0: 100,
                    1: 200,
                    2: -50,
                    3: 300,
                    4: 50}

m = ConcreteModel('plus & minus ones project')

m.S = Set(initialize=range(5))
m.c = Param(m.S, initialize=some_constants)
m.x = Var(m.S, within=Binary)    # creates {m.x[0], m.x[1], ... , m.x[4]}

# try to maximize the sum of x*c
m.obj = Objective(expr=sum((2*m.x[s] - 1)*m.c[s] for s in m.S), sense=maximize)

# some constraint to limit the number of "+1 picks" to 2...easy with binary vars.
m.C1 = Constraint(expr=sum(m.x[s] for s in m.S) <= 2)

m.pprint()
1 Set Declarations
    S : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    5 : {0, 1, 2, 3, 4}

1 Param Declarations
    c : Size=5, Index=S, Domain=Any, Default=None, Mutable=False
        Key : Value
          0 :   100
          1 :   200
          2 :   -50
          3 :   300
          4 :    50

1 Var Declarations
    x : Size=5, Index=S
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          0 :     0 :  None :     1 : False :  True : Binary
          1 :     0 :  None :     1 : False :  True : Binary
          2 :     0 :  None :     1 : False :  True : Binary
          3 :     0 :  None :     1 : False :  True : Binary
          4 :     0 :  None :     1 : False :  True : Binary

1 Objective Declarations
    obj : Size=1, Index=None, Active=True
        Key  : Active : Sense    : Expression
        None :   True : maximize : (2*x[0] - 1)*100 + (2*x[1] - 1)*200 + (2*x[2] - 1)*-50 + (2*x[3] - 1)*300 + (2*x[4] - 1)*50

1 Constraint Declarations
    C1 : Size=1, Index=None, Active=True
        Key  : Lower : Body                             : Upper : Active
        None :  -Inf : x[0] + x[1] + x[2] + x[3] + x[4] :   2.0 :   True

5 Declarations: S c x obj C1