我正在处理一个大小为J
的符号雅可比矩阵QxQ
。该矩阵的每个系数包含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秒,而jacobian矩阵的计算只需0.6秒。在另一个(更长的)代码中,替换需要使用Q=37
的360s(对于雅可比计算需要20秒)!
此外,当我查看正在运行的进程时,我可以看到Python进程有时会在矩阵替换期间停止工作。
答案 0 :(得分:4)
您可能想尝试Theano。它实现了jacobian函数,该函数与sympy
并行且速度更快。
以下版本实现了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