pyomo:根据条件定义客观规则

时间:2019-07-18 13:08:45

标签: python-3.x pyomo

在运输问题中,我试图将以下规则插入目标函数:

如果BC的供应量<19,000吨,那么我们将处以每吨125美元的罚款

我添加了一个约束来检查条件,但想在目标函数中应用惩罚。

我能够在Excel Solver中执行此操作,但是值不匹配。我已经检查了两者,并调试了代码,但是我无法弄清楚出了什么问题。

这里是约束:

def bc_rule(model):
    return sum(model.x[supplier, market] for supplier in model.suppliers \
                                       for market in model.markets \
                                       if 'BC' in supplier) >= 19000  
model.bc_rules = Constraint(rule=bc_rule, doc='Minimum production')

问题出在客观规则上

def objective_rule(model):
    PENALTY_THRESHOLD = 19000
    PENALTY_COST = 125

    cost = sum(model.costs[supplier, market] * model.x[supplier, market] for supplier in model.suppliers for market in model.markets)

    # what is the problem here?
    bc = sum(model.x[supplier, market] for supplier in model.suppliers \
                                       for market in model.markets \
                                       if 'BC' in supplier)
    if bc < PENALTY_THRESHOLD:
        cost += (PENALTY_THRESHOLD - bc) * PENALTY_COST

    return cost

model.objective = Objective(rule=objective_rule, sense=minimize, doc='Define objective function')

我得到的值比Excel Solver中的值低得多。

1 个答案:

答案 0 :(得分:0)

您的条件(if)取决于模型中的变量。

通常,if永远不要在数学模型中使用,不仅限于Pyomo。即使在Excel中,如果在优化之前简单地将公式中的语句转换为标量值,那么在说它是真正的最佳值时我会非常小心。

好消息是if语句很容易转换为数学约束。

为此,您需要向模型添加一个二进制变量(0/1)。如果bc <= PENALTY_TRESHOLD将取值为1。我们将此变量称为y,并将其定义为model.y = Var(domain=Binary)

您将添加model.y * PENALTY_COST作为目标函数的一项,以包括罚款成本。

然后,作为约束,添加以下代码:

def y_big_M(model):
    bigM = 10000 # Should be a big number, big enough that it will be bigger than any number in your 
                 # model, but small enough that it will stay around the same order of magnitude. Avoid 
                 # utterly big number like 1e12 and + if you don't need to, since having numbers too 
                 # large causes problems. 
    PENALTY_TRESHOLD = 19000
    return PENALTY_TRESHOLD - sum(
        model.x[supplier, market]
        for supplier in model.suppliers
        for market in model.markets
        if 'BC' in supplier
    ) <= model.y * bigM
model.y_big_M = Constraint(rule=y_big_M)

先前的约束确保当计算bc的总和小于PENALTY_TRESHOLD时y的值将大于0(即1)。此差的任何大于0的值都将迫使模型将1放入变量y的值中,因为如果使用y=1,则约束的右侧将为1 * bigM ,这是一个非常大的数字,足够大,使得bc总是小于bigM

也请检查您的Excel模型,看看您的if语句在求解器计算期间是否确实有效。上次检查时,Excel求解器不会将if语句转换为bigM约束。我向您展示的建模技术几乎适用于所有编程方法,即使在Excel中也是如此。