简体   繁体   English

在 Sympy 中使用 lambdify 将具有复指数的表达式转换为 function

[英]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.总之,将您的x4x5更改为密集的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM