Python优化使用sympy lambdify和scipy

时间:2022-01-10 21:21:10

I'm trying to maximize a function defined by sympy but cannot make it work. The basic idea can be summarized as follows:

我试图最大化由sympy定义的函数但不能使它工作。基本思路可归纳如下:

    import sympy
    from scipy.optimize import minimize
    from sympy.utilities.lambdify import lambdify

    a,b,G = sympy.symbols('a b G')
    func = (G - a)**2 + b
    my_func = lambdify((G,a,b), -1*func)
    results = minimize(my_func,[0.1,0.1,0.1])

The code works if I define a single-variable function, but as long as I have more than one variable, I receive the following error message.

如果我定义单变量函数,代码可以工作,但只要我有多个变量,我收到以下错误消息。

    TypeError: <lambda>() takes exactly 3 arguments (1 given)

Can someone help me to identify where went wrong?

有人可以帮我确定哪里出了问题?

1 个解决方案

#1


3  

As @Dair pointed out, sympy's lambdify in general requires more than one arguments, while scipy expects only one argument, a list (or an array) that contains all the values of each variable. Because my objective function is most conveniently defined using sympy, I need to find a way to get around this incompatibility of sympy and scipy.

正如@Dair指出的那样,sympy的lambdify通常需要多个参数,而scipy只需要一个参数,一个包含每个变量的所有值的列表(或数组)。因为我的目标函数最方便地使用sympy来定义,所以我需要找到一种方法来解决sympy和scipy之间的这种不兼容问题。

@lhcgeneva pointed out the answer to a similar question. This answer does not conveniently handle a large number of independent variables, especially when the number of independent variables can change, requiring writing out the "vectorized" version of the objective function to be redefined. However, inspired by this post, I figured out the following solution using *tuple():

@lhcgeneva指出了类似问题的答案。这个答案不方便处理大量的自变量,特别是当自变量的数量可以改变时,需要写出要重新定义的目标函数的“矢量化”版本。但是,受到这篇文章的启发,我使用* tuple()找出了以下解决方案:

    import sympy
    from scipy.optimize import minimize
    from sympy.utilities.lambdify import lambdify

    a,b,G = sympy.symbols('a b G')
    func = -1*((G - a)**2 + b)
    my_func = lambdify((G,a,b), func)

    def my_func_v(x):
        return my_func(*tuple(x))

    results = minimize(my_func_v,[0.1,0.1,0.1])

In the example I gave, it seems unnecessary to use *tuple(), but for the problem I want to solve, it saves a lot of hassle. Here's an example that is more similar to the question that I want to solve

在我给出的示例中,似乎没有必要使用* tuple(),但对于我想要解决的问题,它可以节省很多麻烦。这是一个与我想要解决的问题更相似的例子

NUM_VAR = 10
x = np.array(sympy.symbols('x0:%d'%NUM_VAR))
func = np.sum((x-1)**2)
my_func = lambdify(x, func)


def my_func_v(x):
    return my_func(*tuple(x))

results = minimize(my_func_v,np.zeros(NUM_VAR))

This *tuple() thing can save me from writing out all the elements of x like the following (for the case of NUM_VAR=10):

这个* tuple()的东西可以省去写出x的所有元素,如下所示(对于NUM_VAR = 10的情况):

def my_func_v(x):
    return my_func(x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9])

Also, we don't need to change my_func_v when NUM_VAR changes.

此外,当NUM_VAR更改时,我们无需更改my_func_v。

#1


3  

As @Dair pointed out, sympy's lambdify in general requires more than one arguments, while scipy expects only one argument, a list (or an array) that contains all the values of each variable. Because my objective function is most conveniently defined using sympy, I need to find a way to get around this incompatibility of sympy and scipy.

正如@Dair指出的那样,sympy的lambdify通常需要多个参数,而scipy只需要一个参数,一个包含每个变量的所有值的列表(或数组)。因为我的目标函数最方便地使用sympy来定义,所以我需要找到一种方法来解决sympy和scipy之间的这种不兼容问题。

@lhcgeneva pointed out the answer to a similar question. This answer does not conveniently handle a large number of independent variables, especially when the number of independent variables can change, requiring writing out the "vectorized" version of the objective function to be redefined. However, inspired by this post, I figured out the following solution using *tuple():

@lhcgeneva指出了类似问题的答案。这个答案不方便处理大量的自变量,特别是当自变量的数量可以改变时,需要写出要重新定义的目标函数的“矢量化”版本。但是,受到这篇文章的启发,我使用* tuple()找出了以下解决方案:

    import sympy
    from scipy.optimize import minimize
    from sympy.utilities.lambdify import lambdify

    a,b,G = sympy.symbols('a b G')
    func = -1*((G - a)**2 + b)
    my_func = lambdify((G,a,b), func)

    def my_func_v(x):
        return my_func(*tuple(x))

    results = minimize(my_func_v,[0.1,0.1,0.1])

In the example I gave, it seems unnecessary to use *tuple(), but for the problem I want to solve, it saves a lot of hassle. Here's an example that is more similar to the question that I want to solve

在我给出的示例中,似乎没有必要使用* tuple(),但对于我想要解决的问题,它可以节省很多麻烦。这是一个与我想要解决的问题更相似的例子

NUM_VAR = 10
x = np.array(sympy.symbols('x0:%d'%NUM_VAR))
func = np.sum((x-1)**2)
my_func = lambdify(x, func)


def my_func_v(x):
    return my_func(*tuple(x))

results = minimize(my_func_v,np.zeros(NUM_VAR))

This *tuple() thing can save me from writing out all the elements of x like the following (for the case of NUM_VAR=10):

这个* tuple()的东西可以省去写出x的所有元素,如下所示(对于NUM_VAR = 10的情况):

def my_func_v(x):
    return my_func(x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9])

Also, we don't need to change my_func_v when NUM_VAR changes.

此外,当NUM_VAR更改时,我们无需更改my_func_v。