0

我有以下几点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]是在或元组列表中组合的起点i和终点之间的距离。jarcs

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

X[f]是一个二元变量,用于在目的地打开设施j,容量为 ,和f的可能组合在中列出。jfcomb

第一个constraint 1确保q[i,j]来自原产地的流量i不超过其材料的最大dQ可用性iD[(i, j)]是一个二进制参数,如果起点和终点1之间的距离小于或等于阈值,则 的值为。(这个参数帮助我们限制传输距离。)ijD[(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确保流向q[i,j]目的地的流量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来确保f在目的地开放的设施的容量总和j必须尽可能接近容量的总需求E。假设有 100 兆瓦的能源需求E = 100,那么我们希望降低OF供应成本,同时确保满足需求E。否则,最小化成本将为 0。这个约束可以表述为:

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

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

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

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

  • 我们只能选择目的地j来建造设施,并且只能以一种能力开放f
  • 要打开的目的地之和j大于 0。
  • 始发地和目的地q之间没有负流ij

有没有办法:

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

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

4

3 回答 3

0

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

第一种方法是获得一个组合的单一目标函数。如果两个术语都在相同的方向上工作,这会更容易,例如,两者都在最小化术语。因此,对于您的“约束 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%。这反映了可能只有几种(昂贵的)方法可以实现绝对最大容量的情况,但如果我们探索接近该最大值的解决方案,可能会有值得的节省。

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

于 2020-07-13T07:23:39.360 回答
0

您还可以考虑一个更简单的 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)
于 2020-07-15T07:50:28.577 回答
0

您可以尝试在 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

'''
于 2020-07-13T07:46:14.860 回答