[英]Convert an expression with complex exponentials to a function using lambdify in Sympy
I have a Sympy expression of the form我有一个 Sympy 表达形式
exp = 0.5*y1**2 + 2*y1*y2 + 2.5*x5**2 + 5.0*x6**2 - 25.0*exp(2.0*I*x4)*exp(1.0*I*x5) - 25.0*exp(2.0*I*x4) + 100.0 - 25.0*exp(-2.0*I*x4) - 25.0*exp(-2.0*I*x4)*exp(-1.0*I*x5)
I would like to convert the above expression to a function using the variables as arguments.我想使用变量 arguments 将上述表达式转换为 function。 Further, the parameters take sparse scipy csc matrices as input in place of the variables.此外,参数采用稀疏 scipy csc 矩阵作为输入代替变量。 So, I used the following to convert it into a function.因此,我使用以下内容将其转换为 function。
func = lambdify((y1,y2,x4,x5,x6),exp,"scipy")
Though, this function is generated without any error the function does not work with csc sparse matrices.虽然,此 function 生成时没有任何错误,但 function 不适用于 csc 稀疏矩阵。 It gives the following error:它给出了以下错误:
from scipy import sparse
a = sparse.identity(12000,format="csc")
func(a,a,a,a,a) # just to test the output
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
~/.local/lib/python3.9/site-packages/scipy/sparse/base.py in __getattr__(self, attr)
686 else:
--> 687 raise AttributeError(attr + " not found")
688
AttributeError: exp not found
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
<ipython-input-321-ee4555e1ca2e> in <module>
1 a = sparse.identity(21,format="csc")
----> 2 func(a,a)
<lambdifygenerated-23> in _lambdifygenerated(x2, n2)
1 def _lambdifygenerated(x2, n2):
----> 2 return (0.125*n2**2 - 25.0*exp(2.0*1j*x2) - 25.0*exp(-2.0*1j*x2))
~/.local/lib/python3.9/site-packages/scipy/_lib/deprecation.py in call(*args, **kwargs)
18 warnings.warn(msg, category=DeprecationWarning,
19 stacklevel=stacklevel)
---> 20 return fun(*args, **kwargs)
21 call.__doc__ = msg
22 return call
TypeError: loop of ufunc does not support argument 0 of type csc_matrix which has no callable exp method
Which shows that the exponent of a sparse matrix is not defined.这表明未定义稀疏矩阵的指数。 So, I tried to replace the exp(I*x1) with a separate variable and then use that as a parameter.因此,我尝试将 exp(I*x1) 替换为单独的变量,然后将其用作参数。 But, when I use subs, I get the following result.但是,当我使用 subs 时,我得到以下结果。
$exp.subs(exp(I*x4),e4)
0.5*y1**2 + 2*y1*y2 + 2.5*x5**2 + 5.0*x6**2 - 25.0*e4**2.0*exp(1.0*I*x5) - 25.0*e4**2.0 + 100.0 - 25.0/e4**2.0 - 25.0/e4**2.0*exp(-1.0*I*x5)
The problem with the above result is that the negative powers of the exponential are replaced with variable e4 in the denominator.上述结果的问题在于,指数的负幂被分母中的变量 e4 代替了。 So, a lambdify version of the same does not work with matrices as the operation of division for a matrix is undefined.因此,相同的lambdify版本不适用于矩阵,因为矩阵的除法运算是未定义的。 I tried to use replace to replace the terms of the form exp(1.0*I*x5)
and exp(-1.0*I*x5)
separately, but this does not work well with terms such as exp(2.0*I*x5)
.我尝试使用 replace 分别替换exp(1.0*I*x5)
和exp(-1.0*I*x5)
形式的术语,但这不适用于诸如exp(2.0*I*x5)
之类的术语.
Can anything be done to work around this situation?有什么办法可以解决这种情况吗? Any help will be appreciated.任何帮助将不胜感激。
Edit: Some part of the above answer is modified to include a reproducible example.编辑:上述答案的某些部分已修改为包含一个可重现的示例。 Also, I am using square matrices with complex numbers, whose size can be much larger, like 12000 x 12000.此外,我正在使用具有复数的方阵,其大小可以更大,例如 12000 x 12000。
Thanks!谢谢!
np.exp
cannot work on a sparse matrix: np.exp
不能在稀疏矩阵上工作:
In [64]: from scipy import sparse
In [65]: M = sparse.random(10,10,.2, 'csc')
In [66]: np.exp(M)
Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/scipy/sparse/base.py", line 687, in __getattr__
raise AttributeError(attr + " not found")
AttributeError: exp not found
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<ipython-input-66-1b6c717c2aff>", line 1, in <module>
np.exp(M)
TypeError: loop of ufunc does not support argument 0 of type csc_matrix which has no callable exp method
np.exp
, like many numpy
functions, turns non-array arguments into arrays first: np.exp
,像许多numpy
函数一样,首先将非数组 arguments 转换为 arrays :
In [67]: np.array(M)
Out[67]:
array(<10x10 sparse matrix of type '<class 'numpy.float64'>'
with 20 stored elements in Compressed Sparse Column format>, dtype=object)
But that naive conversion just produces a 0d object dtpe array, without changing the sparse matrix.但是这种简单的转换只会产生一个 0d object dtpe 数组,而不会更改稀疏矩阵。 In turn it tries to use a non-existent exp
method.反过来,它尝试使用不存在的exp
方法。
Properly converting the sparse matrix to a (dense) array does work:将稀疏矩阵正确转换为(密集)数组确实有效:
np.exp(M.A)
producing an array result.产生一个数组结果。 You don't loose anything by switching to dense arrays, since exp(0)
is 1.切换到密集的 arrays 不会丢失任何东西,因为exp(0)
为 1。
Use help(f)
(or ipython f?
) to see the function's doc (and code), eg:使用help(f)
(或 ipython f?
)查看函数的文档(和代码),例如:
Created with lambdify. Signature:
func(x, y)
Expression:
0.5*x**2 + 25.0*exp(2*I*x)
Source code:
def _lambdifygenerated(x, y):
return (0.5*x**2 + 25.0*exp(2*1j*x))
np.expm1(M)
also works, because M.expm1()
is defined. np.expm1(M)
也有效,因为定义M.expm1()
。
Since exp(0)
is 1, doing exp
on a sparse matrix would produce an array with 1's where the original had 0s, ie a non-sparse array.由于exp(0)
为 1,因此在稀疏矩阵上执行exp
将产生一个数组,其中原始数组为 0,数组为 1,即非稀疏数组。 expm1
on the other hand preserves sparsity, in effect it can apply the function to all non-zero elements, ignoring the (default) 0s.另一方面, expm1
保留了稀疏性,实际上它可以将 function 应用于所有非零元素,忽略(默认)0。
In sum, change your x4
and x5
to dense arrays, and it should run.总之,将您的x4
和x5
更改为密集的 arrays,它应该可以运行。
I was able to make it work by editing the globals dictionary used by the lambdify function.我能够通过编辑lambdify function使用的全局字典来使其工作。 This function describes the functions which replace the mathematical functions used in a sympy expression.此 function 描述了替换 sympy 表达式中使用的数学函数的函数。 Since the problem here is with the operator of exp
, it can be replaced by expm
from scipy using the following command.由于这里的问题在于exp
的运算符,因此可以使用以下命令将其替换为expm
中的 expm。 The resultant function is now able to take csc sparse matrices as input.结果 function 现在能够将 csc 稀疏矩阵作为输入。
f = lambdify((symbols("v2,x2")),exp.expand(), [{'exp':scipy.linalg.expm},"scipy"])
Hope this helps anyone else facing a similar problem!希望这可以帮助其他面临类似问题的人!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.