Sympy lambdify数组形状(n,)

时间:2022-06-19 20:20:43

I have the following 'issue' with sympy at the moment:

我此刻有以下“问题”:

I have a symbolic expression like M = matrix([pi*a, sin(1)*b]) which I want to lambdify and pass to a numerical optimizer. The issue is that the optimizer needs the function to input/output numpy arrays of shape (n,) and specifically NOT (n,1).

我有一个象征性的表达式,如M =矩阵([pi * a,sin(1)* b])我想要lambdify并传递给数值优化器。问题是优化器需要函数来输入/输出形状(n,)的numpy数组,特别是NOT(n,1)。

Now I have been able to achieve this with the following code (MWE):

现在我已经能够使用以下代码(MWE)实现此目的:

import numpy as np
import sympy as sp
a, b = sp.symbols('a, b')
M = sp.Matrix([2*a, b])
f_tmp = sp.lambdify([[a,b]], M, 'numpy')
fun   = lambda x: np.reshape( f_tmp(x), (2,))

Now, this is of course extremely ugly, since the reshape needs to be applied every time fun is evaluated (which might be LOTS of times). Is there a way to avoid this problem? The Matrix class is by definition always 2 dimensional. I tried using sympy's MutableDenseNDimArray-class, but they don't work in conjunction with lambdify. (symbolic variables don't get recognized)

现在,这当然非常难看,因为每次评估乐趣时都需要应用重塑(这可能很多次)。有没有办法避免这个问题?根据定义,Matrix类始终是2维的。我尝试使用sympy的MutableDenseNDimArray-class,但它们与lambdify不兼容。 (符号变量无法识别)

1 个解决方案

#1


1  

One way is to convert a matrix to a nested list and take the first row:

一种方法是将矩阵转换为嵌套列表并获取第一行:

fun = sp.lambdify([[a, b]], M.T.tolist()[0], 'numpy')

Now fun([2, 3]) is [4, 3]. This is a Python list, not a NumPy array, but optimizers (at least those in SciPy) should be okay with that.

现在好玩([2,3])是[4,3]。这是一个Python列表,而不是NumPy数组,但优化器(至少在SciPy中)应该没问题。

One can also do

人们也可以这样做

fun = sp.lambdify([[a, b]], np.squeeze(M), 'numpy')

which also returns a list.

这也返回一个列表。

In my test the above were equally fast, and faster than the version with a wrapping function (be it np.squeeze or np.reshape): about 6 µs vs 9 µs. It seems the gain is in eliminating one function call.

在我的测试中,上面同样快,并且比具有包装功能的版本(比如np.squeeze或np.reshape)更快:大约6μs对9μs。似乎增益是消除一个函数调用。

#1


1  

One way is to convert a matrix to a nested list and take the first row:

一种方法是将矩阵转换为嵌套列表并获取第一行:

fun = sp.lambdify([[a, b]], M.T.tolist()[0], 'numpy')

Now fun([2, 3]) is [4, 3]. This is a Python list, not a NumPy array, but optimizers (at least those in SciPy) should be okay with that.

现在好玩([2,3])是[4,3]。这是一个Python列表,而不是NumPy数组,但优化器(至少在SciPy中)应该没问题。

One can also do

人们也可以这样做

fun = sp.lambdify([[a, b]], np.squeeze(M), 'numpy')

which also returns a list.

这也返回一个列表。

In my test the above were equally fast, and faster than the version with a wrapping function (be it np.squeeze or np.reshape): about 6 µs vs 9 µs. It seems the gain is in eliminating one function call.

在我的测试中,上面同样快,并且比具有包装功能的版本(比如np.squeeze或np.reshape)更快:大约6μs对9μs。似乎增益是消除一个函数调用。