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

Python 具有多个边界、约束和连续字段的scipy.optimize,python,numpy,optimization,scipy,Python,Numpy,Optimization,Scipy,我想根据请求的电源配置文件优化电源的操作。因此,我定义了热电厂应尽可能遵循的功率曲线。 必须应用多个边界和约束来表示热电联产装置的实际运行。例如,这包括CHP可以打开或关闭,并且在打开时,其功率调制只能设置为特定的百分比范围 下面是一个简单的工作示例,并附有简短的说明: import scipy.optimize as opt import numpy as np x = np.arange(200) # dummy x vector poly_profile = np.array( #

我想根据请求的电源配置文件优化电源的操作。因此,我定义了热电厂应尽可能遵循的功率曲线。 必须应用多个边界和约束来表示热电联产装置的实际运行。例如,这包括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)或(0.3
    profile*x0
    给出了
    ValueError:操作数无法与形状(131、)(200、)一起广播

    仅凭猜测,
    x\u t
    是一种产品
    onoff\u t*xon\t

    onoff\u t
    =0或1时

    由于问题(开关决策)的离散性,这些类型的电力调度模型通常采用混合整数规划模型进行求解(0.3感谢您的回答。我希望避免使用诸如pyomo之类的MILP工具,以减少我的程序对其他模块的依赖性。这种优化在一个更大的模拟程序中每隔几步就被称为一次,并将用于在模拟中设置一些变量。因此,我确实希望避免使用过于复杂的优化,而无法同时使用保持良好的性能。如果没有直接的方法来实现离散边界,我仍然可以在优化后手动剪裁这些边界。这当然是最坏的情况,但仍然可以,因为优化每隔几步执行一次,因此错误将很小。但我也无法确定如何限制启动次数。有没有关于如何o这?只关注约束
    (x==0)或(0.3好吧,我想我只能用
    0来做了。嗨,丹尼斯。非常感谢你的帮助。是的,现在你给了我一个例子,在
    onoff\t
    xon\u t
    中分离
    x
    ,这看起来很小。但我在试图自己解决它时没有考虑到这种可能性。)脉冲发生器也非常有用。但是我不能让它在任意数量的脉冲下工作,因为只有最大数量的脉冲是有限的,但允许使用较少的脉冲。例如,最多4个脉冲,但最佳解决方案仅使用2个脉冲。我是否要就此主题提出一个新问题?
    profile*x0
    does在我的代码中没有引起任何错误。看起来您使用的是python 2.x。在python 3和2.x之间使用numpy数组可能有一些不同。因为行
    profile=poly_-fun(x[65:196])
    x0=np.zeros\u like(profile)
    应该清楚地避免
    轮廓
    x0
    @Scotty1的任何形状不匹配-假设您如上所述定义
    pulsegen2
    pulsegen3
    。运行它们的一种方法是:
    用于列表中的脉冲(pulsegene2)+列表(pulsegen3):…
    对于大型发电机来说,使用更少内存的一种更奇特的方法是
    itertools.chain
    ,请参见。任何数量的脉冲都是code golf,首先要做2 3 4。此外,“固定权重函数…微不足道”?感谢您提供的更多信息。是的,砰砰控制并不是处理控制的好方法,但在许多领域,它仍然是一种常见的控制策略。此外,正如您所建议的,叠加“砰砰”具有连续变量的脉冲发生器听起来像是一个可接受的解决方法,因为这种情况下的优化问题相当小,并且结果被输入到一个具有高惯性的非刚性常微分方程系统中,导致整个系统对优化结果突变的灵敏度较低。关于功能pr编程:在我的理解中,函数编程意味着编写一个通用的脉冲发生器函数,可以在脉冲发生器中为任意数量的脉冲重复使用,而不必为特定数量的脉冲编写脉冲发生器。
    Itertools.chain
    似乎仍然是处理脉冲发生器的好方法对于特定数量的脉冲。
    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')
    
    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