如何在pyomo中添加一组SOS1约束

问题描述

我正在解决一个优化问题,我需要为每个产品分配一个纸箱类型,并确定应使用多少个相应类型的纸箱。每个产品只能分配一种纸箱类型。一个特定类型的纸箱可以容纳多少个特定产品单元。

我创建了如下决策变量:

import pyomo.environ as pyo
model = pyo.ConcreteModel(name="Pack_size_optim")
model.dv_prod_carton = pyo.Var(prod,cartons,within=pyo.NonNegativeIntegers)

产品,纸箱是具有独特产品和纸箱类型的列表

现在,对于我的问题,我想要的是决策变量:对于所有纸箱类型中的每种产品,都应设置SOS 1集,即,对于每种产品,只有一种纸箱类型中的值应大于0。

我正在尝试以下操作,但是它不起作用:

for i in prod:    
    pyo.soSConstraint(var = [model.dv_prod_carton[i,j] for j in cartons],sos = 1)

我认为上面的pyo.soSConstraint函数中的var参数应该是“ IndexedVar”,但是我有一个变量列表。

任何人都可以帮助我实现以上目标。谢谢。

解决方法

您在这里走错了路。您在这里不需要(也不应该使用)特殊订购集。

公开披露:我从未使用过它们,也许其他人对它们为什么适合这里有意见。但是,在您的情况下,您将有多个分配产品的纸箱,所以我看不到您如何适应这种情况。

您只需要做两件事...

  1. 声明一个由2组索引的二进制决策变量:产品,表示将产品p放入容器c的决策的容器。这将是您模型的基础
  2. 设置一个约束,对每个产品的所有容器求和,并将其设置为

...然后是其他必要的约束/ obj

,

(至少)有四种方法对此进行建模:

通过明确指定.ref和.sosno就可以使SOS1变量正常工作。我相信还有更好的方法,但是至少这似乎可行:

# SOS1 test with concrete model

import pyomo.environ as pyo

model = pyo.ConcreteModel()

model.x = pyo.Var([1,2],domain=pyo.PositiveReals,bounds=(0,1))

model.OBJ = pyo.Objective(expr = model.x[1] + model.x[2],sense=pyo.maximize)

# don't exactly know how to get these approaches to work
#pyomo.core.kernel.sos.sos1([model.x[1],model.x[2]])
#pyo.SOSConstraint(var = [model.x[1],model.x[2]],sos = 1)
#model.sos_constraint = pyo.SOSConstraint(var = model.x,sos = 1)
#Message: Solver does not support SOS level 1 constraints 

model.sosno = pyo.Suffix(direction=pyo.Suffix.EXPORT)
model.ref = pyo.Suffix(direction=pyo.Suffix.EXPORT)

# Add entry for each index of model.x
model.sosno.set_value(model.x,1)
model.ref[model.x[1]] = 1
model.ref[model.x[2]] = 2

# if SOS1 works correctly solution should have one of x[1],x[2] nonzero
# indeed we see with Cplex:
# 'Objective': {'OBJ': {'Value': 1.0}},'Variable': {'x[1]': {'Value': 1.0}}

这有点像您在AMPL中所做的。