在运输问题中,我试图将以下规则插入目标函数:
如果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中的值低得多。
答案 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中也是如此。