scipy.optimize具有多个边界,约束和连续字段

时间:2018-10-12 14:40:10

标签: python numpy optimization scipy

我想根据请求的电源配置文件优化CHP plant的操作。因此,我定义了功率曲线,CHP工厂应尽可能地遵循该功率曲线。 必须应用多个界限和约束条件来代表CHP工厂的实际运行。例如,这包括CHP可以打开或关闭,并且在打开时,其功率调制只能设置为特定的百分比范围。

这是一个最小的工作示例,并带有简短说明:

import scipy.optimize as opt
import numpy as np

x = np.arange(200)  # dummy x vector
poly_profile = np.array(  # 7th degree polynome fit of profile
    [-2.14104340e-11,  1.85108903e-08, -6.66697810e-06,  1.29239710e-03,
     -1.45110876e-01,  9.40324129e+00, -3.24548750e+02,  4.60006330e+03])
poly_fun = np.poly1d(poly_profile)  # make poly fun
profile = poly_fun(x[65:196])
x0 = np.zeros_like(profile)  # all zeros as starting values

def optifun(x, profile):  # define minimization fun
    return - np.sum(profile * x)

bnds_hi = opt.Bounds(0.3, 1)  # upper bounds
bnds_lo = opt.Bounds(0, 0)  # lower bounds

res = opt.minimize(
    optifun, x0, args=(profile), bounds=bnds_hi,
    constraints={'type': 'eq', 'fun': lambda x:  np.sum(x*40) - 2000},
    method='SLSQP')
plt.plot(res.x)
plt.plot(profile)

这些就是我要使用的范围:

  • (x == 0) or (0.3 <= x <= 1),用于数组x中的任何值
    这意味着总CHP功率的调制度x可以为0(关闭),也可以为>0.3<= 1。但是我可以指定下限 OR 。仅指定上限,就不可能将“ CHP关闭”,而将下限设置为 bnds_lo = opt.Bounds(0, 1)
    将使热电联产工厂能够在不切实际的运行点(功率调制的0%到30%之间)下运行。
    有什么方法可以按照最小工作示例中指定的范围进行这项工作?具体来说:是否可以同时设置两种边界,例如bounds=[bnds_lo, bnds_hi]
    我猜这是一个混合整数线性编程问题,但是COBYLA或SLSQP是否应该能够解决这个问题?如果没有:有任何解决方法吗?

以及我要使用的约束:

  • np.sum(x*40) - 450
    将热量输出限制为一定的热量存储容量。这里40是热输出功率,而450是剩余存储容量。这相当容易实现。
  • 限制CHP工厂的启动次数。作为一个例子,我们假设

    bnds_lo = opt.Bounds(0, 1)  # lower bounds
    res = opt.minimize(
        optifun, x0, args=(profile), bounds=bnds_lo,
        constraints={'type': 'eq', 'fun': lambda x:  np.sum(x*40) - 1000},
        method='SLSQP')
    

    这将导致热电联产工厂运行三个阶段。有什么办法可以限制这个?我当时正在考虑添加一个特定的约束函数,该函数在前导0之后对正差值进行计数,但是我无法进行类似的工作(例如,由于大多数x都不完全是0,因为将边界设置为(0, 1)。但是其他问题也可能是原因)...

  • 设置CHP工厂的最小连续运行时间。这意味着至少有5个连续的x != 0是有利的。我考虑过尝试与上一点类似的操作(限制启动次数),但也无法解决一些有用的问题。这是迄今为止最不重要的问题。

为了解决这些问题,我也尝试使用 scipy.optimize.LinearConstraingsNonlinearConstraings 但是method='trust-constr'需要一个jac(就我在github上阅读的内容来看,这似乎是一个错误),因此我无法使其正常工作。

有什么办法可以使我工作?特别是指定多个边界很重要。

谢谢!

此致, 斯科蒂

1 个答案:

答案 0 :(得分:2)

代码中的

profile * x0给出了
“ ValueError:操作数不能与形状(131,)(200,)一起广播”。

仅凭猜测,x_t是产品onoff_t * xon_t
onoff_t = 0或1
和{{1}中每个0.3 <= xon_t <= 1处的t吗?
即对于0 .. T,有2 ^ 5个可能的T = 5序列,00000 00001 00010 .. 11111吗?

如果是,则最大化onoff 具有固定权重函数sum 0:T w_t * onoff_t * xon_t的方法很简单:
其中w_tw_t <= 0,关闭
其中onoff_t = 0w_t > 0,最大和onoff_t = 1
所以这不是您的问题-请澄清。

如果进一步限制xon_t = 1仅切换两次,则0 ... 1 ... 0 ..., 那么可能序列的数量就很小,可以全部尝试, 大致而言:

onoff_t

切换4次,0 ... 1 ... 0 ... 1 ... 0 ...是相似的。 (给定的def pulse_generator( T=200, minwidth=5 ): """ -> arrays of T floats, 0... 1... 0... """ for t0 in xrange( 1, T ): for t1 in xrange( t0 + minwidth, T ): pulse = np.zeros( T ) pulse[t0:t1] = 1 yield pulse for pulse in pulse_generator( T ): print "pulse:", pulse optimize myfunction( pulse * xon ), 0.3 <= xon <= 1 有多少个这样的脉冲? 参见维基百科Stars and bars- 很棒。)


补充:我不是专家,但又不是开关 bang-bang control 非常对微小变化敏感,是早一点还是晚一点? 一个程序(mer)可能花很多时间抖动,从而降低噪音。 分为两个阶段,粗网格然后细网格-

  1. 将时间0:T分成10个片段,全部运行2 ^ 10 = 1024个开关序列
    1a。仔细观察最好的-任何模式?
  2. 将边缘移动一半,T / 20。

另请参阅: 谷歌“离散优化”多重网格...和 Grid search