代码之家  ›  专栏  ›  技术社区  ›  akhil

Python约束的非线性优化

  •  37
  • akhil  · 技术社区  · 11 年前

    对于python中的约束非线性优化,推荐的软件包是什么?

    我要解决的具体问题是:

    我有一个未知 X (Nx1),我有 M (Nx1) u 矢量和 M (NxN) s 矩阵。

    max [5th percentile of (ui_T*X), i in 1 to M]
    st 
    0<=X<=1 and
    [95th percentile of (X_T*si*X), i in 1 to M]<= constant
    

    当我开始做这道题时,我只估计了一分 u s 我能够用 cvxpy .

    我意识到 u s ,我有整个值的分布,所以我想改变我的目标函数,这样我就可以使用整个分布。上面的问题描述是我试图以有意义的方式包含这些信息。

    cvxpy公司 不能用来解决这个问题,我已经试过了 scipy.optimize.anneal ,但我似乎无法设置未知值的边界。我看过 pulp 但它不允许非线性约束。

    4 回复  |  直到 7 年前
        1
  •  30
  •   Mike McKerns    8 年前

    SLSQP 中的算法 scipy.optimize.minimize 很好,它有很多局限性。第一个是 QP 因此,它将适用于符合二次规划范式的方程。但是如果你有功能限制会发生什么呢?而且 科学优化最小化 不是全局优化器,因此您通常需要非常接近最终结果。

    有一个受约束的非线性优化包(称为 mystic )它已经存在了将近 scipy.optimize 我建议将其作为处理任何一般约束非线性优化的工具。

    例如,如果我理解你的伪代码,你的问题看起来像这样:

    import numpy as np
    
    M = 10
    N = 3
    Q = 10
    C = 10
    
    # let's be lazy, and generate s and u randomly...
    s = np.random.randint(-Q,Q, size=(M,N,N))
    u = np.random.randint(-Q,Q, size=(M,N))
    
    def percentile(p, x):
        x = np.sort(x)
        p = 0.01 * p * len(x)
        if int(p) != p:
            return x[int(np.floor(p))]
        p = int(p)
        return x[p:p+2].mean()
    
    def objective(x, p=5): # inverted objective, to find the max
        return -1*percentile(p, [np.dot(np.atleast_2d(u[i]), x)[0] for i in range(0,M-1)])
    
    
    def constraint(x, p=95, v=C): # 95%(xTsx) - v <= 0
        x = np.atleast_2d(x)
        return percentile(p, [np.dot(np.dot(x,s[i]),x.T)[0,0] for i in range(0,M-1)]) - v
    
    bounds = [(0,1) for i in range(0,N)]
    

    所以,在 神秘的 ,您只需要指定边界和约束。

    from mystic.penalty import quadratic_inequality
    @quadratic_inequality(constraint, k=1e4)
    def penalty(x):
      return 0.0
    
    from mystic.solvers import diffev2
    from mystic.monitors import VerboseMonitor
    mon = VerboseMonitor(10)
    
    result = diffev2(objective, x0=bounds, penalty=penalty, npop=10, gtol=200, \
                     disp=False, full_output=True, itermon=mon, maxiter=M*N*100)
    
    print result[0]
    print result[1]
    

    结果如下:

    Generation 0 has Chi-Squared: -0.434718
    Generation 10 has Chi-Squared: -1.733787
    Generation 20 has Chi-Squared: -1.859787
    Generation 30 has Chi-Squared: -1.860533
    Generation 40 has Chi-Squared: -1.860533
    Generation 50 has Chi-Squared: -1.860533
    Generation 60 has Chi-Squared: -1.860533
    Generation 70 has Chi-Squared: -1.860533
    Generation 80 has Chi-Squared: -1.860533
    Generation 90 has Chi-Squared: -1.860533
    Generation 100 has Chi-Squared: -1.860533
    Generation 110 has Chi-Squared: -1.860533
    Generation 120 has Chi-Squared: -1.860533
    Generation 130 has Chi-Squared: -1.860533
    Generation 140 has Chi-Squared: -1.860533
    Generation 150 has Chi-Squared: -1.860533
    Generation 160 has Chi-Squared: -1.860533
    Generation 170 has Chi-Squared: -1.860533
    Generation 180 has Chi-Squared: -1.860533
    Generation 190 has Chi-Squared: -1.860533
    Generation 200 has Chi-Squared: -1.860533
    Generation 210 has Chi-Squared: -1.860533
    STOP("ChangeOverGeneration with {'tolerance': 0.005, 'generations': 200}")
    [-0.17207128  0.73183465 -0.28218955]
    -1.86053344078
    

    神秘的 非常灵活,可以处理任何类型的约束(例如等式、不等式),包括符号和函数约束。 我将约束指定为上面的“惩罚”,这是传统的方式,因为当违反约束时,它们会对目标施加惩罚。 神秘的 还提供了非线性核变换,其通过减少有效解的空间(即通过空间映射或核变换)来约束解空间。

    例如 神秘的 因为约束不是以约束矩阵的形式,所以解决了一个打破了许多QP求解器的问题。它在优化压力容器的设计。

    "Pressure Vessel Design"
    
    def objective(x):
        x0,x1,x2,x3 = x
        return 0.6224*x0*x2*x3 + 1.7781*x1*x2**2 + 3.1661*x0**2*x3 + 19.84*x0**2*x2
    
    bounds = [(0,1e6)]*4
    # with penalty='penalty' applied, solution is:
    xs = [0.72759093, 0.35964857, 37.69901188, 240.0]
    ys = 5804.3762083
    
    from mystic.symbolic import generate_constraint, generate_solvers, simplify
    from mystic.symbolic import generate_penalty, generate_conditions
    
    equations = """
    -x0 + 0.0193*x2 <= 0.0
    -x1 + 0.00954*x2 <= 0.0
    -pi*x2**2*x3 - (4/3.)*pi*x2**3 + 1296000.0 <= 0.0
    x3 - 240.0 <= 0.0
    """
    cf = generate_constraint(generate_solvers(simplify(equations)))
    pf = generate_penalty(generate_conditions(equations), k=1e12)
    
    
    if __name__ == '__main__':
    
        from mystic.solvers import diffev2
        from mystic.math import almostEqual
        from mystic.monitors import VerboseMonitor
        mon = VerboseMonitor(10)
    
        result = diffev2(objective, x0=bounds, bounds=bounds, constraints=cf, penalty=pf, \ 
                         npop=40, gtol=50, disp=False, full_output=True, itermon=mon)
    
        assert almostEqual(result[0], xs, rel=1e-2)
        assert almostEqual(result[1], ys, rel=1e-2)
    

    在这里找到这个和大约100个类似的例子: https://github.com/uqfoundation/mystic .

    我是作者,所以我有点偏见。然而,这种偏差很小。 神秘的 成熟且支持良好,在解决硬约束非线性优化问题方面具有无与伦比的能力。

        2
  •  16
  •   Slater Victoroff    11 年前

    scipy 有一个壮观的包,用于约束非线性优化。

    您可以通过阅读 optimize doc ,但这里有一个SLSQP示例:

    minimize(func, [-1.0,1.0], args=(-1.0,), jac=func_deriv, constraints=cons, method='SLSQP', options={'disp': True})
    
        3
  •  15
  •   John Hedengren    4 年前

    正如其他人所评论的,SciPy最小化包是一个很好的开始。我们还回顾了 Python Gekko paper (见第4节)。我在下面的示例(Hock Schittkowski#71基准测试)中包含了一个目标函数、等式约束和不等式约束 Scipy.optimize.minimize .

    import numpy as np
    from scipy.optimize import minimize
    
    def objective(x):
        return x[0]*x[3]*(x[0]+x[1]+x[2])+x[2]
    
    def constraint1(x):
        return x[0]*x[1]*x[2]*x[3]-25.0
    
    def constraint2(x):
        sum_eq = 40.0
        for i in range(4):
            sum_eq = sum_eq - x[i]**2
        return sum_eq
    
    # initial guesses
    n = 4
    x0 = np.zeros(n)
    x0[0] = 1.0
    x0[1] = 5.0
    x0[2] = 5.0
    x0[3] = 1.0
    
    # show initial objective
    print('Initial SSE Objective: ' + str(objective(x0)))
    
    # optimize
    b = (1.0,5.0)
    bnds = (b, b, b, b)
    con1 = {'type': 'ineq', 'fun': constraint1} 
    con2 = {'type': 'eq', 'fun': constraint2}
    cons = ([con1,con2])
    solution = minimize(objective,x0,method='SLSQP',\
                        bounds=bnds,constraints=cons)
    x = solution.x
    
    # 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('x3 = ' + str(x[2]))
    print('x4 = ' + str(x[3]))
    

    Python Gekko也存在同样的问题:

    from gekko import GEKKO
    m = GEKKO()
    x1,x2,x3,x4 = m.Array(m.Var,4,lb=1,ub=5)
    x1.value = 1; x2.value = 5; x3.value = 5; x4.value = 1
    
    m.Equation(x1*x2*x3*x4>=25)
    m.Equation(x1**2+x2**2+x3**2+x4**2==40)
    m.Minimize(x1*x4*(x1+x2+x3)+x3)
    
    m.solve(disp=False)
    print(x1.value,x2.value,x3.value,x4.value)
    

    还有一个更全面的讨论主题 nonlinear programming solvers for Python 如果SLSQP不能解决您的问题。我的课程材料 Engineering Design Optimization 如果需要有关解算器方法的其他信息,可以使用。

        4
  •  3
  •   pseudocubic    11 年前

    通常用于您可以使用的配件 scipy.optimize 功能,或 lmfit 它只是扩展了scipy.optimize包,使其更容易传递边界之类的内容。就我个人而言,我喜欢使用 kmpfit ,是kapteyn库的一部分,基于MPFIT的C实现。

    scipy.optimize.minimize() 可能是最容易获得且最常用的。

    推荐文章