Python:有没有比使用 numpy 的 polyfromroots 更快的替代方法?
Python: is there a faster alternative to using numpy's polyfromroots?
使用Python,我循环遍历大量根集(本质上表示为二维 numpy 数组),并每次形成具有根集的一元多项式(称为根)作为根,因此:
poly = np.polynomial.polynomial.polyfromroots(roots)
然而,当根集的数量很大(大约 40000)时,我的代码 运行 运行缓慢,即使每组根本身很小(仅包含 4 个根)。
举个例子,如果我 运行
import timeit
SETUP_CODE = '''
import numpy as np'''
TEST_CODE = '''
N, n = 40000, 4
collection_roots = np.random.random((N,n)) + 1.j*np.random.random((N,n))
polynomials = np.zeros((N, n + 1), dtype=complex)
for k in range(N):
roots = collection_roots[k, :]
polynomials[k, :] = np.polynomial.polynomial.polyfromroots(roots)'''
print(timeit.timeit(setup=SETUP_CODE,
stmt=TEST_CODE,
number=1))
我相对较旧的机器上的输出大约是 2.9 秒。有没有办法在 Python 内加速这段代码?
我的代码中还有其他地方可以使用一些优化。当然,我可以创建单独的 posts,但如果有人也可以 post 一些他们认为对优化 Python 科学计算代码有用的资源,这将对我(和其他人)有所帮助。
Sympy 可以预先计算给定根数的通用公式:
from sympy import Symbol, Product, poly, lambdify
num_roots = 4
x = Symbol('x')
roots = [Symbol(f'r{i}') for i in range(num_roots)]
prod = 1
for ri in roots:
prod *= (x - ri)
print(prod)
print(poly(prod, x).all_coeffs()[::-1])
np_poly_4_roots = lambdify(roots, poly(prod, x).all_coeffs()[::-1])
np_poly_4_roots(*[1, 2, 3, 4])
调用help(np_poly_4_roots)
显示其源代码:
def _lambdifygenerated(r0, r1, r2, r3):
return ([r0*r1*r2*r3,
-r0*r1*r2 - r0*r1*r3 - r0*r2*r3 - r1*r2*r3,
r0*r1 + r0*r2 + r0*r3 + r1*r2 + r1*r3 + r2*r3,
-r0 - r1 - r2 - r3,
1])
这已经运行得更快了,但是没有完全矢量化。但是您可以使用此源手动创建矢量化版本:
def fast_poly_4_roots(r):
r0, r1, r2, r3 = r[:, 0], r[:, 1], r[:, 2], r[:, 3]
return np.array([r0 * r1 * r2 * r3,
-r0 * r1 * r2 - r0 * r1 * r3 - r0 * r2 * r3 - r1 * r2 * r3,
r0 * r1 + r0 * r2 + r0 * r3 + r1 * r2 + r1 * r3 + r2 * r3,
-r0 - r1 - r2 - r3,
np.ones_like(r0)])
对于具有所有 4 个根的输入,这可以以矢量化方式执行:
N, n = 4000, 4
collection_roots = np.random.random((N,n)) + 1.j*np.random.random((N,n))
polynomials = fast_poly_4_roots(collection_roots)
因为现在没有 Python for 循环了,事情真的很快。
使用Python,我循环遍历大量根集(本质上表示为二维 numpy 数组),并每次形成具有根集的一元多项式(称为根)作为根,因此:
poly = np.polynomial.polynomial.polyfromroots(roots)
然而,当根集的数量很大(大约 40000)时,我的代码 运行 运行缓慢,即使每组根本身很小(仅包含 4 个根)。
举个例子,如果我 运行
import timeit
SETUP_CODE = '''
import numpy as np'''
TEST_CODE = '''
N, n = 40000, 4
collection_roots = np.random.random((N,n)) + 1.j*np.random.random((N,n))
polynomials = np.zeros((N, n + 1), dtype=complex)
for k in range(N):
roots = collection_roots[k, :]
polynomials[k, :] = np.polynomial.polynomial.polyfromroots(roots)'''
print(timeit.timeit(setup=SETUP_CODE,
stmt=TEST_CODE,
number=1))
我相对较旧的机器上的输出大约是 2.9 秒。有没有办法在 Python 内加速这段代码?
我的代码中还有其他地方可以使用一些优化。当然,我可以创建单独的 posts,但如果有人也可以 post 一些他们认为对优化 Python 科学计算代码有用的资源,这将对我(和其他人)有所帮助。
Sympy 可以预先计算给定根数的通用公式:
from sympy import Symbol, Product, poly, lambdify
num_roots = 4
x = Symbol('x')
roots = [Symbol(f'r{i}') for i in range(num_roots)]
prod = 1
for ri in roots:
prod *= (x - ri)
print(prod)
print(poly(prod, x).all_coeffs()[::-1])
np_poly_4_roots = lambdify(roots, poly(prod, x).all_coeffs()[::-1])
np_poly_4_roots(*[1, 2, 3, 4])
调用help(np_poly_4_roots)
显示其源代码:
def _lambdifygenerated(r0, r1, r2, r3):
return ([r0*r1*r2*r3,
-r0*r1*r2 - r0*r1*r3 - r0*r2*r3 - r1*r2*r3,
r0*r1 + r0*r2 + r0*r3 + r1*r2 + r1*r3 + r2*r3,
-r0 - r1 - r2 - r3,
1])
这已经运行得更快了,但是没有完全矢量化。但是您可以使用此源手动创建矢量化版本:
def fast_poly_4_roots(r):
r0, r1, r2, r3 = r[:, 0], r[:, 1], r[:, 2], r[:, 3]
return np.array([r0 * r1 * r2 * r3,
-r0 * r1 * r2 - r0 * r1 * r3 - r0 * r2 * r3 - r1 * r2 * r3,
r0 * r1 + r0 * r2 + r0 * r3 + r1 * r2 + r1 * r3 + r2 * r3,
-r0 - r1 - r2 - r3,
np.ones_like(r0)])
对于具有所有 4 个根的输入,这可以以矢量化方式执行:
N, n = 4000, 4
collection_roots = np.random.random((N,n)) + 1.j*np.random.random((N,n))
polynomials = fast_poly_4_roots(collection_roots)
因为现在没有 Python for 循环了,事情真的很快。