Ускоренная симплексно-ламинированная и векторизованная функция

Я использую sympy для создания некоторых функций для численных расчетов. Поэтому я обвязываю выражение, чтобы векторизовать его, чтобы использовать его с массивами numpy. Вот пример:

import numpy as np import sympy as sp def numpy_function(): x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j] T = (1 - np.cos(2*np.pi*x))*(1 - np.cos(2*np.pi*y))*np.sin(np.pi*z)*0.1 return T def sympy_function(): x, y, z = sp.Symbol("x"), sp.Symbol("y"), sp.Symbol("z") T = (1 - sp.cos(2*sp.pi*x))*(1 - sp.cos(2*sp.pi*y))*sp.sin(sp.pi*z)*0.1 lambda_function = np.vectorize(sp.lambdify((x, y, z), T, "numpy")) x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j] T = lambda_function(x,y,z) return T 

Проблема между версией sympy и версией pure numpy – это скорость, т.е.

 In [3]: timeit test.numpy_function() 100 loops, best of 3: 11.9 ms per loop 

против

 In [4]: timeit test.sympy_function() 1 loops, best of 3: 634 ms per loop 

Итак, есть ли способ приблизиться к скорости версии numpy? Я думаю, что np.vectorize довольно медленный, но каким-то образом часть моего кода не работает без него. Благодарим вас за любые предложения.

EDIT : Итак, я нашел причину, почему нужна функция векторизации, то есть:

 In [35]: y = np.arange(10) In [36]: f = sp.lambdify(x,sin(x),"numpy") In [37]: f(y) Out[37]: array([ 0. , 0.84147098, 0.90929743, 0.14112001, -0.7568025 , -0.95892427, -0.2794155 , 0.6569866 , 0.98935825, 0.41211849]) 

это, похоже, отлично работает:

 In [38]: y = np.arange(10) In [39]: f = sp.lambdify(x,1,"numpy") In [40]: f(y) Out[40]: 1 

Таким образом, для простого выражения типа 1 эта функция не возвращает массив. Есть ли способ исправить это и разве это не какая-то ошибка или, по крайней мере, непоследовательный дизайн?

    lambdify возвращает одно значение для констант, потому что не задействованы функции numpy. Это связано с тем, как работает lambdify (см. https://stackoverflow.com/a/25514007/161801 ).

    Но это, как правило, не проблема, потому что константа будет автоматически транслироваться в правильную форму в любой операции, в которой вы ее используете, с массивом. С другой стороны, если вы явно работали с массивом одной и той же константы, это было бы намного менее эффективно, потому что вы могли бы вычислять одни и те же операции несколько раз.

    Использование np.vectorize() в этом случае похоже на цикл по первому размеру x , y и z , и поэтому он становится медленнее. Вам не нужен np.vectorize() Если вы скажете lambdify() чтобы использовать функции NumPy, что именно вы делаете. Затем, используя:

     def sympy_function(): x, y, z = sp.Symbol("x"), sp.Symbol("y"), sp.Symbol("z") T = (1 - sp.cos(2*sp.pi*x))*(1 - sp.cos(2*sp.pi*y))*sp.sin(sp.pi*z)*0.1 lambda_function = sp.lambdify((x, y, z), T, "numpy") x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j] T = lambda_function(x,y,z) return T 

    делает производительность сопоставимой:

     In [26]: np.allclose(numpy_function(), sympy_function()) Out[26]: True In [27]: timeit numpy_function() 100 loops, best of 3: 4.08 ms per loop In [28]: timeit sympy_function() 100 loops, best of 3: 5.52 ms per loop