python - 具有多个边界、约束和连续字段的 scipy.optimize

标签 python numpy optimization scipy

我想根据请求的电源配置文件优化 CHP plant 的操作。因此,我定义了一个功率配置文件,热电联产电厂应尽可能遵循该功率配置文件。 必须应用多个边界和约束来代表热电联产电厂的实际运行。例如,这包括 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 。但我可以指定下限上限。仅指定上限就不可能“关闭 CHP”,而将下限设置为 bnds_lo = opt.Bounds(0, 1)
    将使热电联产电厂能够在不现实的运行点(功率调制的 0% 到 30% 之间)运行。
    有什么方法可以使其在最小工作示例中指定的范围内工作吗?具体来说:我可以同时设置两种边界,例如 bounds=[bnds_lo, bnds_hi] 吗?
    我猜这是一个混合整数线性规划问题,但 COBYLA 或 SLSQP 不应该能够处理这个问题吗?如果没有:有什么解决方法吗?

以及我想使用的约束:

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

    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')
    

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

  • 设置热电联产电厂的最短连续运行时间。这意味着至少有 5 个连续的 x != 0 应该是有利的。我想过尝试与上一点类似的方法(限制启动次数),但也无法找到有用的方法。这是迄今为止最不重要的问题。

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

有什么办法可以让我完成这项工作吗?特别是指定多个边界很重要。

提前致谢!

真诚的, 斯科蒂

最佳答案

profile * x0在你的代码中给出
“ValueError:操作数无法与形状 (131,) (​​200,) 一起广播”。

只是猜测,是x_t一个产品onoff_t * xon_t
onoff_t = 0 或 1
0.3 <= xon_t <= 1在每个 t0 .. T
IE。对于 T = 5有 2^5 种可能 onoff序列,00000 00001 00010 .. 11111?

如果是这样,则最大化 sum 0:T w_t * onoff_t * xon_t 具有固定权重函数w_t是微不足道的:
哪里w_t <= 0 :onoff_t = 0 , 关闭
哪里w_t > 0 :onoff_t = 1 、关于、以及xon_t = 1 ,最大
所以这不是你的问题——请澄清一下。

如果onoff_t进一步限制只能切换两次,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

切换4次,0...1...0...1...0...,类似。 (对于给定的 T 有多少个这样的脉冲? 请参阅维基百科 Stars and bars -- 太棒了。)

<小时/> 补充:我不是专家,但也不是断断续续的 bang-bang control 对微小的变化非常敏感,早一点还是晚一点? 程序可能会花费大量时间在噪音中犹豫不决。 两阶段怎么样,粗网格然后细网格 --

  1. 将时间 0:T 分成 10 部分,运行所有 2^10 = 1024 个开关序列
    1a.仔细观察最好的——有什么模式吗?
  2. 将其边缘移动半步,T/20。

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

关于python - 具有多个边界、约束和连续字段的 scipy.optimize,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52781901/

相关文章:

python - 按位修改 Numpy float32 并返回修改后的 np.float32 值

c++ - 在 C++ 中用 avx 实现 numpy 的 triu_indices

c++ - 在展开的链表上运行大约需要 40% 的代码运行时间——有什么明显的方法可以优化它吗?

python - 如何让字典乘法更快?

python - OpenCV TypeError:参数 'src' 的预期 cv::UMat - 这是什么?

Python 3-谷歌驱动器 API : AttributeError: 'Resource' object has no attribute 'children'

python - 如何下载 XML 文件避免弹出窗口这种类型的文件可能会通过 ChromeDriver 和 Chrome 使用 Python 中的 Selenium 损害您的计算机

python - 在tensorflow的输入中放入什么才能起作用

python - 从两个 numpy 数组中删除重复元素

php - 让 MySQL 找出日期间隔与 PHP