【问题标题】:How to combine 2 constraints to minimise cost and maximise capacity using DOcplex.mp in Python如何在 Python 中使用 DOcplex.mp 结合 2 个约束以最小化成本和最大化容量
【发布时间】:2020-07-13 00:00:51
【问题描述】:

我有以下OF 以最小化供应链成本:

mdl.minimize(mdl.sum((cs+ch+cf+cv*d[j])*q[j] for j in arcs) + mdl.sum(α*(eh+et*d[j])*q[j] for j in arcs) + mdl.sum(β*(gh+gt*d[j])*q[j] for j in arcs) + mdl.sum(X[f]*cjf for f in comb))

其中cs, ch, cf, cv, eh, et, gh, gt, cjf, α and β是一系列常量参数。

d[j] 是在arcs 或元组列表中组合的起点 i 和终点 j 之间的距离。

q[j]arcs 中起点i 和终点j 之间的流变量。

X[f] 是一个二进制变量,用于在目标j 中打开容量为f 的设施,jf 的可能组合在comb 中列出。

第一个constraint 1 确保来自源i 的流q[i,j] 不超过i 中材料dQ 的最大可用性。 D[(i, j)] 是一个二进制参数,如果起点 i 和终点 j 之间的距离小于或等于阈值,则为 1,否则 D[(i, j)] 的值是 0。 (这个参数可以帮助我们限制传输距离。)

for i in I: mdl.add_constraint(mdl.sum(q[(i, j)]*D[(i, j)] for j in J) <= Qi[i])

第二个constraint 2 确保流向目标jq[i,j] 等于目标j 中已打开设施的容量和容量f

for j in J: mdl.add_constraint(mdl.sum(q[(i, j)]for i in I) == mdl.sum(X[(j,f)] for f in F))

但是,我们需要另一个constraint 3,以确保在目的地j 开设的设施中的容量总和f 必须尽可能接近容量总需求E。假设有 100 MW E = 100 的能源需求,那么我们想降低 OF 的供应成本,但也要确保我们达到需求 E。否则最小化成本将为 0。这个约束可以表述为:

mdl.add_constraint(mdl.sum(X[j,f]for j in J for f in F) == E)

不幸的是,这个解决方案永远不可行。如果我们将== 替换为<= 是可行的,但成本最低且容量远未达到最大值。 我们不需要这是一个严格的限制,但我们确实希望通过在目的地j 开设多个具有不同容量f 的设施来尽可能接近E。 (例如,我们可以有一个 20 MW、一个 5 MW、两个 30 MW 和另一个 15 MW 的目的地,通过开放 5 个目的地达到 100 MW)

一种方法是强制模型打开N 位置数量j,但是,我们有一组 128 个位置。要从N=1N=128 的一系列场景中找到最小成本和最大容量,意味着我们需要运行这个模型 128 次。

在上述约束之上,我们还有 3 个额外的约束:

  • 我们只能选择目的地j来建造一个设施,并且只开放一个容量f
  • 要打开的目的地j 的总和大于0。
  • 起点i 和终点j 之间没有负流q

有没有办法:

  • 减少constraint 3 的绑定,但仍尝试在保持最低成本的同时达到E
  • 重新制定OF 以将最小成本与最大容量相结合?

重要的是,我们不想让模型运行 128 次。我们要建模选择目的地j 开设设施并相应地选择容量f,以最小化总供应成本并最大化装机容量。在我们的例子中,也不太可能只打开一个目的地j 来满足所有需求E。相反,我们将有多个 j 与较小的 f 容量相加时接近 E

【问题讨论】:

    标签: python mathematical-optimization cplex docplex docplexcloud


    【解决方案1】:

    这是“多目标优化”。下面概述了实现此目的的两种可能方法。

    第一种方法是获得一个组合的单一目标函数。如果两个术语都朝着相同的方向工作,这会更容易,例如两者都在最小化条款。因此,对于您的“约束 3”,请尝试在目标中使用一个术语来表示相对于需求的缺口,因此缺口类似于:

    短缺 == E - mdl.sum(X[j,f]for j in J for f in F)

    然后将差额添加到目标中,并为这两个术语使用一些权重因子,例如:

    w * 成本 + (1-w) * 不足

    如果 w 为 1,您只是在最小化成本,而如果 w 为零,您只是在最小化不足。当然,如果您使用一个介于 0 和 1 之间的权重值,那么您将获得两个目标的平衡。您需要特别注意两个术语之间的权重分配值。

    这种方法的一个变体是赋予一个术语比另一个更大的权重,因此该术语在目标中占主导地位。然后求解器将尝试最小化那个更重要的项(例如短缺),而另一个项将帮助选择成本较低的选项来实现这一点。 在实践中,这通常不会像人们期望的那样工作 - 在目标中添加非常大和非常小的项可能会导致求解器出现数值问题,并且通常会导致目标值的真正差异无论如何,不​​同的解决方案可能会迷失在求解器的公差中。例如,我们已经看到有些人使用 100 万比 1 的相对权重,而仍然使用 1e-6 的最优差距;在这种情况下,第二项实际上在噪音中消失了,因为许多(可能非常不同)备选方案在求解器看来几乎相同并且落在公差范围内,因此有效地被忽略了。

    第二种方法是“词汇多目标”求解,它稍微复杂一些,但不依赖于一些麻烦的加权因子。实际上,您需要解决您的问题两次 - 一次是为了找到您可以提供的最大容量,然后在您的第二个问题中通过限制来解决该问题,并最大限度地降低提供该容量的成本。

    在实践中,您可能会调整这种纯粹的方法,并在您的第二个模型中接受足够接近实现最大容量的解决方案。因此,例如,您可以将第二个模型中的总容量固定为例如第一个模型可实现的计算最大容量的至少 99%。这反映了可能只有几种(昂贵的)方法可以达到绝对最大容量的情况,但如果我们探索接近该最大值的解决方案,可能会有值得节省的费用。

    请注意,有几个求解器使用这种“词法”方法为多目标模型提供现成的支持,这可能避免您为每种情况显式求解模型两次。

    【讨论】:

    • 非常感谢,我相信其他评论提供了词法多对象的代码。我会尝试你的两个建议,看看什么能带来最好的结果。
    【解决方案2】:

    您可以尝试在 docplex 中使用 CPLEX 多目标功能。

    参见https://www.linkedin.com/pulse/making-optimization-simple-python-alex-fleischer/中的基本示例

    from docplex.mp.model import Model
    
    mdl = Model(name='buses')
    
    nbbus50 = mdl.integer_var(name='nbBus50')
    nbbus40 = mdl.integer_var(name='nbBus40')
    nbbus30 = mdl.integer_var(name='nbBus30')
    
    cost = mdl.continuous_var(name='cost')
    co2emission = mdl.continuous_var(name='co2emission')
    
    mdl.add_constraint(nbbus50*50+nbbus40*40 + nbbus30*30 >= 200, 'kids')
    mdl.add_constraint(co2emission==nbbus50+nbbus40*1.1+nbbus30*1.2)
    mdl.add_constraint(cost==nbbus40*500 + nbbus30*400+nbbus50*625)
                    
    sense="min"
    exprs=[cost,co2emission]
    priorities=[1,2]
    weights=[1,1]
    mdl.set_multi_objective(sense, exprs, priorities, weights, abstols=None, reltols=None, names=None)
    
    mdl.solve(lex_mipgaps = [0.001, 0.05], log_output=True)
    
    for v in mdl.iter_integer_vars():
        print(v," = ",v.solution_value)
    
    print("The minimum cost is ",cost.solution_value);
    print("CO2 emission is ",co2emission.solution_value);
    
    '''
    which gives
    
    nbBus50  =  4.0
    nbBus40  =  0
    nbBus30  =  0
    The minimum cost is  2500.0
    CO2 emission is  4.0
    
    '''
    

    【讨论】:

    • 这很有帮助。我实现了鳕鱼,但得到了以下TypeError: set_lex_multi_objective() got multiple values for argument 'abstols' 任何可能导致这种情况的建议?
    • 我建议您首先确保您拥有最新版本的 DOcplex (2.14.186)。
    【解决方案3】:

    您还可以考虑使用更简单的 API,即 Model.minimize_static_lex,向其传递要以字典顺序最小化的表达式列表:

    #mdl.set_multi_objective(sense, exprs, priorities, weights, abstols=None, reltols=None, names=None)
    mdl.minimize_static_lex(exprs=[cost, co2emission])
    mdl.solve(lex_mipgaps=[0.001, 0.05], log_output=True)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 2021-09-27
      • 2020-08-08
      • 2021-04-11
      • 1970-01-01
      相关资源
      最近更新 更多