Python:带约束的多元非线性求解器

2024-06-03 00:58:30 发布

您现在位置:Python中文网/ 问答频道 /正文

给定一个接受输入向量x并返回相同长度向量的函数f(x),那么如何找到{}上函数设置约束的根呢?(例如,x的每个组件的一个范围。)

令我惊讶的是,我找不到很多有用的信息。在Optimization and Root finding algorithms的scipy列表中,似乎有一些标量函数的选项,例如brentq。但我找不到任何算法支持这种多变量情况下的选择。在

当然,我们可以做一些工作,比如将返回向量的每个分量平方,然后使用一个最小值,比如differential_evolution(这是我认为的唯一一个)。但我不能想象这是一个好的策略,因为它扼杀了牛顿算法的二次收敛性。另外,我觉得很奇怪,似乎没有一个选择,因为这肯定是一个非常普遍的问题。我错过什么了吗?在


Tags: and函数算法信息列表选项组件root
3条回答

如果你想处理一个有约束的优化,你可以使用方便的lirbary,这比scipy.optimize公司在

以下是指向程序包的链接:

https://pypi.python.org/pypi/facile/1.2

以图书馆为例。你需要改进我在这里写的东西,这只是一般性的。如果你有错误,告诉我是哪一个。在

import facile

# Your vector x 

x = [ facile.variable('name', min, max) for i in range(Size) ]


# I give an example here of your vector being ordered and each component in a range
# You could as well put in the range where declaring variables

for i in range(len(x)-1):
    facile.constraint( x[i] < x[i+1])
    facile.constraint( range[i,0] < x[i] < range[i,1] ) #Supposed you have a 'range' array where you store the range for each variable


def function(...)
 # Define here the function you want to find roots of


 # Add as constraint that you want the vector to be a root of function
facile.constraint(function(x) == 0)


# Use facile solver
if facile.solve(x):
    print [x[i].value() for i in range(len(x))]
else:
    print "Impossible to find roots"

解决这个问题的一个方法(不是特别好,但希望是有效的)是给解算器一个只在约束区域有根的函数,并且以确保解算器被推回适当区域(有点像here但在多个维度中)继续。在

要实现这一点(至少对于矩形约束),可以实现一个constrainedFunction,它从函数的边界值开始线性连续:

import numpy as np

def constrainedFunction(x, f, lower, upper, minIncr=0.001):
     x = np.asarray(x)
     lower = np.asarray(lower)
     upper = np.asarray(upper)
     xBorder = np.where(x<lower, lower, x)
     xBorder = np.where(x>upper, upper, xBorder)
     fBorder = f(xBorder)
     distFromBorder = (np.sum(np.where(x<lower, lower-x, 0.))
                      +np.sum(np.where(x>upper, x-upper, 0.)))
     return (fBorder + (fBorder
                       +np.where(fBorder>0, minIncr, -minIncr))*distFromBorder)

您可以传递给这个函数一个x值,您想要继续的函数f,以及两个形状相同的数组lower和{},就像{}一样,给出了所有维度的上下限。现在可以将此函数而不是原始函数传递给解算器以查找根。在

为了防止边界处的标志变化出现陡跳,只需将延拓的陡度作为边界值。为了防止根超出约束区域,在正/负边界值上添加/减去一些小值。我同意这不是一个很好的方法来处理这个问题,但它似乎是有效的。在

这里有两个例子。对于这两种情况,初始猜测都在约束区域之外,但在约束区域中找到了正确的根。在

求约束为[-2,-1]x[1,2]的多维余弦的根可以得到:

^{pr2}$

给出:

    fjac: array([[ -9.99999975e-01,   2.22992740e-04],
       [  2.22992740e-04,   9.99999975e-01]])
     fun: array([  6.12323400e-17,   6.12323400e-17])
 message: 'The solution converged.'
    nfev: 11
     qtf: array([ -2.50050470e-10,  -1.98160617e-11])
       r: array([-1.00281376,  0.03518108, -0.9971942 ])
  status: 1
 success: True
       x: array([-1.57079633,  1.57079633])

这也适用于非对角函数:

def f(x):
    return np.asarray([0., np.cos(x.sum())])

opt.root(constrainedFunction, x0=np.zeros(2),
         args=(f, np.asarray([-2., 2.]), np.asarray([-1, 4.])))

给出:

    fjac: array([[ 0.00254922,  0.99999675],
       [-0.99999675,  0.00254922]])
     fun: array([  0.00000000e+00,   6.12323400e-17])
 message: 'The solution converged.'
    nfev: 11
     qtf: array([  1.63189544e-11,   4.16007911e-14])
       r: array([-0.75738638, -0.99212138, -0.00246647])
  status: 1
 success: True
       x: array([-1.65863336,  3.22942968])

冒着暗示你可能已经划掉的东西的风险,我相信只要scipy.minimize这应该是可行的。问题是函数必须只有一个参数,但是该参数可以是向量/列表。在

所以f(x,y)就变成了f(z),其中z=[x,y]。在

如果您没有遇到过一个很好的例子,here。在

如前所述,如果要对2x1向量施加边界,可以使用:

# Specify a (lower, upper) tuple for each component of the vector    
bnds = [(0., 1.) for i in len(x)]

并将其用作bounds内的bounds参数。在

相关问题 更多 >