【问题标题】:Scipy.optimize - minimize not respecting constraintsScipy.optimize - 尽量减少不尊重约束
【发布时间】:2020-02-13 07:12:51
【问题描述】:

使用下面的代码来了解 Scipy 优化/最小化的工作原理。结果与我的预期不符。

"""
Minimize: f = 2*x[0]*x[1] + 2*x[0] - x[0]**2 - 2*x[1]**2

Subject to: -2*x[0] + 2*x[1] <= -2
             2*x[0] - 4*x[1] <= 0
               x[0]**3 -x[1] == 0

where: 0 <= x[0] <= inf
       1 <= x[1] <= inf
"""
import numpy as np
from scipy.optimize import minimize

def objective(x):
    return 2.0*x[0]*x[1] + 2.0*x[0] - x[0]**2 - 2.0*x[1]**2

def constraint1(x):
    return +2.0*x[0] - 2.0*x[1] - 2.0

def constraint2(x):
    return -2.0*x[0] + 4.0*x[1] 

def constraint3(x):
    sum_eq = x[0]**3.0 -x[1]
    return sum_eq

# initial guesses
n = 2
x0 = np.zeros(n)
x0[0] =  10.0
x0[1] = 100.0

# show initial objective
print('Initial SSE Objective: ' + str(objective(x0)))

# optimize
#b = (1.0,None)
bnds = ((0.0,1000.0), (1.0,1000.0))
con1 = {'type': 'ineq', 'fun': constraint1} 
con2 = {'type': 'ineq', 'fun': constraint2} 
con3 = {'type': 'eq', 'fun': constraint3}
cons = ([con1, con2, con3])
solution = minimize(objective,
                    x0,
                    method='SLSQP',
                    bounds=bnds,
                    constraints=cons)
x = solution.x

print(solution)

# show final objective
print('Final SSE Objective: ' + str(objective(x)))

# print solution
print('Solution')
print('x1 = ' + str(x[0]))
print('x2 = ' + str(x[1]))
print('\n')
print('x', x)
print('constraint1', constraint1(x))
print('constraint2', constraint2(x))
print('constraint3', constraint3(x))

当我运行时,这是 Python 在其输出控制台上抛出的内容:

Initial SSE Objective: -18080.0
     fun: 2.0
     jac: array([ 0.00000000e+00, -2.98023224e-08])
 message: 'Optimization terminated successfully.'
    nfev: 122
     nit: 17
    njev: 13
  status: 0
 success: True
       x: array([2., 1.])
Final SSE Objective: 2.0
Solution
x1 = 2.0000000000010196
x2 = 1.0000000000012386


x [2. 1.]
constraint1 -4.3787196091216174e-13
constraint2  2.915001573455811e-12
constraint3 7.000000000010997

尽管优化器说结果是成功的,但由于结果应该为零,因此不遵守约束 3。我错过了什么?

【问题讨论】:

    标签: scipy-optimize-minimize


    【解决方案1】:

    您的问题不兼容。您可以消除第三个约束(这首先使您的问题更简单 - 只有一个标量优化),之后更清楚地看到问题是什么。从约束 3 和原始 x1 的下界可以看出,x0 从 0 到 1 是不可行的,所以一维问题中的下界应该是 1。容易看出约束 2 总是正的,当 x0 大于 1 时,它永远不会被满足。

    当我为我运行您的原始问题时,它会以正向导数停止(并且对于“不等式约束不兼容”的重写问题)。 您使用的是哪种 SciPy?对我来说是 1.4.1。

    在下图中,您可以看到一维问题的目标和剩余约束(横轴是原始 x0 变量)

    """ 最小化:f = 2*x[0]*x1 + 2*x[0] - x[0]**2 - 2*x1**2

    Subject to: -2*x[0] + 2*x[1] <= -2
                 2*x[0] - 4*x[1] <= 0
                   x[0]**3 -x[1] == 0
    
    where: 0 <= x[0] <= inf
           1 <= x[1] <= inf
    """
    import numpy as np
    from scipy.optimize import minimize
    
    def objective(x):
        return 2*x**4 + 2*x - x**2 - 2*x**6
    
    def constraint1(x):
        return x - x**3 - 1
    
    def constraint2(x):
        return 2 * x**3 - x
    #
    # def constraint3(x):
    #     sum_eq = x[0]**3.0 -x[1]
    #     return sum_eq
    
    # initial guesses
    n = 1
    x0 = np.zeros(n)
    x0[0] =  2.
    # x0[1] = 100.0
    
    # show initial objective
    print('Initial SSE Objective: ' + str(objective(x0)))
    
    # optimize
    #b = (1.0,None)
    bnds = ((1.0,1000.0),)
    con1 = {'type': 'ineq', 'fun': constraint1}
    con2 = {'type': 'ineq', 'fun': constraint2}
    # con3 = {'type': 'eq', 'fun': constraint3}
    cons = [
        # con1,
        con2,
        # con3,
            ]
    solution = minimize(objective,
                        x0,
                        method='SLSQP',
                        bounds=bnds,
                        constraints=cons)
    x = solution.x
    
    print(solution)
    
    # show final objective
    print('Final SSE Objective: ' + str(objective(x)))
    
    # print solution
    print('Solution')
    print('x1 = ' + str(x[0]))
    # print('x2 = ' + str(x[1]))
    print('\n')
    print('x', x)
    print('constraint1', constraint1(x))
    print('constraint2', constraint2(x))
    # print('constraint3', constraint3(x))
    
    x_a = np.linspace(1, 2, 200)
    f = objective(x_a)
    c1 = constraint1(x_a)
    c2 = constraint2(x_a)
    
    import matplotlib.pyplot as plt
    
    plt.figure()
    
    plt.plot(x_a, f, label="f")
    plt.plot(x_a, c1, label="c1")
    plt.plot(x_a, c2, label="c2")
    plt.legend()
    plt.show()
    

    【讨论】:

    • 您的数学分析完全合理!我认为我的问题是我的 scipy 太旧了,它说 0.19.0。几个月前我安装了 Anaconda 3x,我将重新安装。对于约束 3,很明显它在边界内是不可行的(很好!)但是,我不明白为什么您确实更改了示例中的约束。我在你的解释中遗漏了什么吗?
    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 2019-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多