繁体   English   中英

使用 Mystic 优化编译硬约束

[英]Compiling hard constraints with Mystic optimisation

我正在编写一个受约束的 integer 优化并且在制定约束时遇到了麻烦。 下面是我的优化总结:(Schedule是我自己的function,它返回单个int值)

目标:MIN (1500 * x1) + (625 * x2) +(100 * x3)

约束:

  1. 时间表(x1,x2,x3) >=480

  2. x2 > x1

  3. x2 > x3

界限: (5<= x1 <=50), (5<= x2 <=100), (1<= x3 <=20)

将硬约束分组以放入 diffev2 的最佳方法是什么,因为 constraint1 使用 function 所以不能以符号方式编写?

下面是一个粗略的尝试。 我遇到的另一个小问题是违反了界限(值为负数),所以如果我的界限有任何危险信号,请说出来。 Mystic 也很新,所以不用担心用简单的术语来解释事情。

import mystic as ms
import mystic.symbolic as msym
import numpy as np

def objective(x): 
    rounded = np.around(x)
    integer= rounded.astype(int)
    x1,x2,x3 = integer
    return (1500 * x1) + (625 * x2) +(100 * x3)


bounds = [(5,50),(5,100),(1,20)]


def constraint1(x):
    rounded = np.around(x)
    integer= rounded.astype(int)
    x1,x2,x3 = integer
    return 240-schedule(x1,x2,x3)

eqns = '''
x2 > x1     
x2 > x3

'''
cons = msym.generate_constraint(msym.generate_solvers(msym.simplify(eqns)))

constraint = ms.constraints.and_(cons, constraint1) #I know this is wrong but I want to join them

from mystic.solvers import diffev2
from mystic.monitors import VerboseMonitor
mon = VerboseMonitor(10)

result = diffev2(objective,x0=bounds, bounds=bounds, constraints=constraint, npop=50, gtol=200, \
                  disp=False, full_output=True, itermon=mon)

我会像这样稍微重写它......

目标:MIN (1500 * x0) + (625 * x1) + (100 * x2)

约束: schedule(x0,x1,x2) >= 480 x1 > x0 x1 > x2 x0, x1, x2 是整数

界限:(5 <= x0 <=50), (5 <= x1 <=100), (1 <= x2 <=20)

在这里,我们将在 function 中定义计划,以及边界和目标。

>>> import mystic as my
>>> import mystic.symbolic as ms
>>> import numpy as np
>>>
>>> def objective(x):
...     x0,x1,x2 = x
...     return (1500 * x0) + (625 * x1) + (100 * x2)
...
>>> bounds = [(5,50),(5,100),(1,20)]
>>>
>>> def schedule(x0,x1,x2):
...     return x0 * x1 - x2 * x2
...

然后我们开始构建约束。 约束函数总是x' = constraints(x) (即它们接受一个参数向量,并返回一个参数向量)。 因此,我们在这里有两个特殊情况:(1)符号方程,我们将为此构建x' = cons(x) ,以及对schedule的 output 的约束——这需要一些迂回的逻辑来构建。

>>> eqns = '''
... x1 > x0
... x2 < x1
... '''
>>>
>>> ints = np.round
>>> and_ = my.constraints.and_
>>> cons = ms.generate_constraint(ms.generate_solvers(ms.simplify(eqns)), join=and_)
>>>
>>> cons([1,2,3])
[1, 2, 1.999999999999997]
>>> cons([5,5,1])
[5, 5.000000000000006, 1]
>>>

请注意,我已经重写了符号约束,每次在左侧都有一个不同的变量。 这是因为不使用and_ ,构建的约束将只使用最后一个。 因此,使用and_会强制运行优化,以便两者都得到尊重。 通过不在左侧重用变量,我更容易解决。 最后,我检查约束是否按预期工作。

另请注意,我还没有使用 integer 约束。 当我们将所有约束放在一起时,我们可以应用它。

要在 output 上应用约束,我们首先构建一个惩罚,然后将其转换为一个约束。 它效率不高,因为它再次需要内部优化。

>>> def penalty1(x):
...     x0,x1,x2 = x
...     return 480 - schedule(x0,x1,x2)
...
>>> @my.penalty.linear_inequality(penalty1)
... def penalty(x):
...     return 0.0
...
>>> lb,ub = zip(*bounds)
>>> c = my.constraints.as_constraint(penalty, lower_bounds=lb, upper_bounds=ub, nvars=3)
>>> c([5,5,1])
[13.126545665004528, 44.97820356778645, 1.0138152329128338]
>>> schedule(*_)
589.3806217359323
>>> c([50,50,10])
[50.0, 50.0, 10.0]
>>> schedule(*_)
2400.0
>>>

然后我们把它们放在一起,再次使用and_

>>> constraint = and_(c, cons, ints)
>>>
>>> constraint([5,5,1])
[23.0, 30.0, 2.0]
>>> c(_)
[23.0, 30.0, 2.0]
>>> cons(_)
[23.0, 30.0, 2.0]
>>> objective(_)
53450

最后,我们解决。

>>> from mystic.solvers import diffev2
>>> from mystic.monitors import VerboseMonitor
>>> mon = VerboseMonitor(10)
>>>
>>> result = diffev2(objective,x0=bounds, bounds=bounds, constraints=constraint, npop=50, gtol=100, disp=False, full_output=True, itermon=mon)
Generation 0 has ChiSquare: 43850.000000
Generation 10 has ChiSquare: 42725.000000
Generation 20 has ChiSquare: 42725.000000
Generation 30 has ChiSquare: 42725.000000
Generation 40 has ChiSquare: 42725.000000
Generation 50 has ChiSquare: 42725.000000
Generation 60 has ChiSquare: 42725.000000
Generation 70 has ChiSquare: 42725.000000
Generation 80 has ChiSquare: 42725.000000
Generation 90 has ChiSquare: 42725.000000
Generation 100 has ChiSquare: 42725.000000
STOP("ChangeOverGeneration with {'tolerance': 0.005, 'generations': 100}")
>>> result[0]
array([13., 37.,  1.])
>>> result[1]
42725.0

再次使用不同的求解器...

>>> from mystic.solvers import fmin
>>> mon = VerboseMonitor(10)
>>> result = fmin(objective, x0=[13,37,1], bounds=bounds, constraints=constraint, ftol=1e-6, disp=False, full_output=True, itermon=mon)
Generation 0 has ChiSquare: 42725.000000
Generation 10 has ChiSquare: 42725.000000
Generation 20 has ChiSquare: 42725.000000
STOP("CandidateRelativeTolerance with {'xtol': 0.0001, 'ftol': 1e-06}")

您会注意到优化器找到了比我们刚开始应用约束时更好的值,但没有进行太多搜索。 在严格限制的空间中,通常会立即找到解决方案。 您必须进行更多调查才能确定这是否确实是全局最小值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM