【问题标题】:sympy lambdify with sympy matrix and numpy vector inputs带有 sympy 矩阵和 numpy 向量输入的 sympy lambdify
【发布时间】:2021-07-16 00:12:52
【问题描述】:

我想用 sympy 计算一个符号梯度,例如,

import sympy as sym
x, y, z  = sym.symbols("x y z", real=True)

T = sym.cos(x**2+y**2)

gradT = sym.Matrix([sym.diff(T, x), sym.diff(T,y), sym.diff(T,z)])

现在我想用这个表达式创建一个 lamddify 函数:

func = lambdify((x,y,z), gradT,'numpy')

要使用我拥有的功能:

gradT_exact = func(np.linspace(0,2,100), np.linspace(0,2,100), np.linspace(0,2,100))

我收到以下错误:

<lambdifygenerated-3>:2: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
  return (array([[-2*x*sin(x**2 + y**2)], [-2*y*sin(x**2 + y**2)], [0]]))

如果我将 T 更改为 x,y,z 的函数,它不会给我带来任何问题... 为什么当 T 仅取决于 x 和 y 并且 z 设置为零时会发出警告。

提前致谢!

【问题讨论】:

  • 这是 sympy 中的一个错误:github.com/sympy/sympy/issues/21613
  • @OscarBenjamin,我不明白 lambdify 如何调整 [0] 以准确反映其他术语的可能形状(一般为 x,y,z)。跨度>
  • 一般来说,当将数组的符号替换为矩阵值表达式时,lambdify 不可能知道用户想要什么。额外的数组维度应该去哪里?定义一些合理的东西是可能的,但它可能需要是与 lambdify 不同的函数,该函数将具有控制如何使其工作的参数。

标签: python-3.x sympy lambdify


【解决方案1】:

gradT 表达式:

In [84]: gradT
Out[84]: 
⎡        ⎛ 2    2⎞⎤
⎢-2⋅x⋅sin⎝x  + y ⎠⎥
⎢                 ⎥
⎢        ⎛ 2    2⎞⎥
⎢-2⋅y⋅sin⎝x  + y ⎠⎥
⎢                 ⎥
⎣        0        ⎦

及其转换为numpy:

In [87]: print(func.__doc__)
Created with lambdify. Signature:

func(x, y, z)

Expression:

Matrix([[-2*x*sin(x**2 + y**2)], [-2*y*sin(x**2 + y**2)], [0]])

Source code:

def _lambdifygenerated(x, y, z):
    return (array([[-2*x*sin(x**2 + y**2)], [-2*y*sin(x**2 + y**2)], [0]]))

如果 xy 是数组,则 2 个项将反映它们的维度,但最后一个是 [0]。这就是您收到ragged 警告的原因。

lambdify 做了一个相当简单的词法翻译。它没有实现对numpy 数组的任何深入理解。在某种程度上,您有责任检查 numpy 代码是否合理。

标量输入:

In [88]: func(1,2,3)
Out[88]: 
array([[1.91784855],
       [3.8356971 ],
       [0.        ]])

但如果一个输入是一个数组:

In [90]: func(np.array([1,2]),2,3)
<lambdifygenerated-1>:2: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
  return (array([[-2*x*sin(x**2 + y**2)], [-2*y*sin(x**2 + y**2)], [0]]))
Out[90]: 
array([[array([ 1.91784855, -3.95743299])],
       [array([ 3.8356971 , -3.95743299])],
       [0]], dtype=object)

结果是包含 2 个数组以及 [0] 列表的对象 dtype。

为避免此问题,lambdify 必须生成如下函数:

In [95]: def f(x,y,z):
    ...:     temp = 0*x*y
    ...:     return np.array([-2*x*np.sin(x**2 + y**2), -2*y*np.sin(x**2 + y**2)
    ...: , temp])

其中temp 旨在赋予0 值,但其形状反映了xy 在其他术语中的广播操作。我认为这对lambdify 要求过高。

In [96]: 

In [96]: f(np.array([1,2]),2,3)
Out[96]: 
array([[ 1.91784855, -3.95743299],
       [ 3.8356971 , -3.95743299],
       [ 0.        ,  0.        ]])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多