python - 用sympy缓慢替换符号矩阵

标签 python numpy sympy substitution differential-equations

我正在使用 sympy 处理大小为 QxQ 的符号雅可比矩阵 J。该矩阵的每个系数包含Q 个符号,从f[0]f[Q-1]。 我想做的是将 J 的每个系数中的每个符号替换为已知值 g[0]g[Q-1](不再是符号)。我发现最快的方法如下:

for k in range(Q):
    J = J.subs(f[k], g[k])

但是,我觉得这个“基本”操作很长!例如,对于这个 MCVE:

import sympy
import numpy as np
import time

Q = 17
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16 = \
    sympy.symbols("f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 f16")
f = [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16]
e = np.array([0., 1., 0., -1., 0., 1., -1., -1., 1.,
              2., -2., -2., 2., 3., 0., -3., 0.])
u = np.sum(f * e) / np.sum(f)
function = e * np.sum(f) * (1. + u * e + (u * e)**2 - u * u)
F = sympy.Matrix(function)
g = e * (1. + 0.2 * e + (0.2 * e)**2)

start_time = time.time()
J = F.jacobian(f)
print("--- %s seconds ---" % (time.time() - start_time))

start_time = time.time()
for k in range(Q):
    J = J.subs(f[k], g[k])
print("--- %s seconds ---" % (time.time() - start_time))

在我的电脑上替换大约需要 5 秒,而雅可比矩阵的计算只需要 0.6 秒。在另一个(更长的)代码上,使用 Q=37 替换需要 360 秒(而雅可比计算需要 20 秒)!

此外,当我查看正在运行的进程时,我可以看到 Python 进程有时会在矩阵替换期间停止工作。

  1. 有人知道这可能来自哪里吗?
  2. 有没有办法使这个操作更快?

最佳答案

您可能想尝试 Theano为了那个原因。它实现了一个 jacobiansympy 并行且更快的函数。

以下版本实现了3.88的加速!现在换人时间不如第二个。

import numpy as np
import sympy as sp
import theano as th
import time


def main_sympy():
    start_time = time.time()

    Q = 17
    f = sp.symbols(('f{} ' * Q).format(*range(Q)))

    e = np.array([0., 1., 0., -1., 0., 1., -1., -1., 1.,
                  2., -2., -2., 2., 3., 0., -3., 0.])
    u = np.sum(f * e) / np.sum(f)
    ue = u * e
    phi = e * np.sum(f) * (1. + ue + ue*ue - u*u)
    F = sp.Matrix(phi)
    J = F.jacobian(f)

    g = e * (1. + 0.2*e + (0.2*e)**2)

    for k in range(Q):
        J = J.subs(f[k], g[k])

    print("--- %s seconds ---" % (time.time() - start_time))
    return J


def main_theano():
    start_time = time.time()

    Q = 17
    f = th.tensor.dvector('f')

    e = np.array([0., 1., 0., -1., 0., 1., -1., -1., 1., 2.,
                  -2., -2., 2., 3., 0., -3., 0.])
    u = (f * e).sum() / f.sum()
    ue = u * e
    phi = e * f.sum() * (1. + ue + ue*ue - u*u)
    jacobi = th.gradient.jacobian(phi, f)
    J = th.function([f], jacobi)

    g = e * (1. + 0.2*e + (0.2*e)**2)
    Jg = J(g)  # evaluate expression

    print("--- %s seconds ---" % (time.time() - start_time))
    return Jg


J0 = np.array(main_sympy().tolist(), dtype='float64')
J1 = main_theano()

print(np.allclose(J0, J1))  # compare results

关于python - 用sympy缓慢替换符号矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45755816/

相关文章:

python - 实现与 numpy 一起使用的奇异复数

python - 在 python 代码中输入一个符号函数

python - Webapp2 strict_slash 返回 KeyError : 'Missing Argument' for url with trailing slash when method has 2 or more args. .. Bug?

Python:有向图中的所有简单路径

python - 如何处理密码中的@符号 - sqlalchemy

将 numpy 数组转换为另一个具有列索引的数组的 Pythonic 方法

python - 如何增加 Theano 保存模型的训练?

python - 使用 np.triu_indices 生成索引

python - 在 Sympy 中生成勒让德多项式

python - 简化使用 sympy codegen 生成的表达式