如何使用Pyomo进行指标功能?

时间:2018-08-23 23:17:33

标签: pyomo

我正在寻找在Pyomo中创建一个简单的指标变量。假设我有一个变量x,如果x> 0,则该指标函数的取值为1,否则为0。

这是我尝试执行的操作:

model = ConcreteModel()  
model.A = Set(initialize=[1,2,3])
model.B = Set(initialize=['J', 'K'])

model.x = Var(model.A, model.B, domain = NonNegativeIntegers)
model.ix = Var(model.A, model.B, domain = Binary)

def ix_indicator_rule(model, a, b):
    return model.ix[a, b] == int(model.x[a, b] > 0)

model.ix_constraint = Constraint(model.A, model.B,
                             rule = ix_indicator_rule)

我收到的错误消息与Avoid this error by using Pyomo-provided math functions相似,根据this link可以在pyomo.environ找到……但是我不确定如何执行此操作。我尝试使用validate_PositiveValues(),如下所示:

def ix_indicator_rule(model, a, b):
    return model.ix[a, b] == validate_PositiveValues(model.x[a, b])

model.ix_constraint = Constraint(model.A, model.B,
                             rule = ix_indicator_rule)

没有运气。任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:2)

您可以使用“ big-M”约束来实现此目标,如下所示:

model = ConcreteModel()  
model.A = Set(initialize=[1, 2, 3])
model.B = Set(initialize=['J', 'K'])

# m must be larger than largest allowed value of x, but it should
# also be as small as possible to improve numerical stability
model.m = Param(initialize=1e9)

model.x = Var(model.A, model.B, domain=NonNegativeIntegers)
model.ix = Var(model.A, model.B, domain=Binary)

# force model.ix to be 1 if model.x > 0
def ix_indicator_rule(model, a, b):
    return model.x <= model.ix[a, b] * model.m

model.ix_constraint = Constraint(
    model.A, model.B, rule=ix_indicator_rule
)

但是请注意,big-M约束是单方面的。在此示例中,它在model.ix时强制model.x > 0开启,但在model.x == 0时不强制关闭。通过将不等式翻转为model.x >= model.ix[a, b] * model.m,可以实现后者(但不能达到前者)。但是您不能在同一模型中同时做这两个事情。通常,您只是选择适合您模型的版本,例如,如果将model.ix设置为1会使目标函数恶化,那么您将选择上面显示的版本,求解器将负责设置{{ 1}}到model.ix

Pyomo还提供了可能适合您需求的析取编程功能(请参阅herehere)。 cplex解算器提供了indicator constraints,但我不知道Pyomo是否支持它们。

答案 1 :(得分:0)

我最终使用了分段功能,并做了如下操作:

DOMAIN_PTS = [0,0,1,1000000000]
RANGE_PTS  = [0,0,1,1]
model.ix_constraint = Piecewise(
     model.A, model.B,
     model.ix, model.x,
     pw_pts=DOMAIN_PTS,
     pw_repn='INC',
     pw_constr_type = 'EQ',
     f_rule = RANGE_PTS,
     unbounded_domain_var = True)

def objective_rule(model):
    return sum(model.ix[a,b] for a in model.A for b in model.B)

model.objective = Objective(rule = objective_rule, sense=minimize)

似乎工作正常。