#python #numpy #sympy
Вопрос:
Могу ли я заменить 2D-индексированную базу, которая находится в выражении, для массива numpy с помощью sympy.subs()
или sympy.evalf(subs=())
?
Так что что-то вроде:
i, j, m, n = sp.symbols('i j m n', integer=True) x = sp.IndexedBase('x') a = sp.IndexedBase('a') b = sp.IndexedBase('b') f = sp.ln(sp.Sum(sp.exp(sp.Sum(a[i, j]*x[j] b[i], (j, 1, n))), (i, 1, m)))
который в настоящее время выводит: вывод выражения
Обратите внимание, что A-это 2D-индексируемая база, а B-1D-индексируемая база. Я хотел бы иметь возможность заменить индексированные базы, определенные выше, массивами numpy, чем-то вроде
A = np.random.uniform(MIN, MAX, (M, N)) B = np.random.uniform(MIN, MAX, M) f.evalf(subs={a:A, b:B, x:(1,5), m:M, n:N}
Как бы я смог достичь чего-то подобного?
Комментарии:
1. Чтобы использовать массивы numpy, вам нужно сначала перевести выражение на python/numpy с
lambdify
помощью . Я не знаю, как это работаетIndexedBase
. Переменные Sympy могут использоваться в массивах numpy, но результатом является тип объекта dtype, а результаты вычислений зависят от попадания или промаха.
Ответ №1:
Вы можете сделать это lambdify
вот так:
In [36]: i, j, m, n = sp.symbols('i j m n', integer=True) ...: x = sp.IndexedBase('x') ...: a = sp.IndexedBase('a') ...: b = sp.IndexedBase('b') ...: ...: f = sp.ln(sp.Sum(sp.exp(sp.Sum(a[i, j]*x[j] b[i], (j, 0, n-1))), (i, 0, m-1))) In [37]: f_lam = lambdify((a, b, x, m, n), f, 'numpy') In [38]: MIN, MAX, M, N = 0, 1, 3, 4 In [39]: A = np.random.uniform(MIN, MAX, (M, N)) ...: B = np.random.uniform(MIN, MAX, M) In [40]: X = np.random.uniform(MIN, MAX, N) In [41]: f_lam(A, B, X, M, N) Out[41]: 4.727558334863294
Обратите внимание, что я изменил пределы Sum
перехода, например 0
n-1
, на, чтобы соответствовать правилам индексации numpy.
Также обратите внимание, что при этом используется обычный Python sum
и выражение генератора с двойным циклом, а не более эффективные операции numpy:
In [42]: import inspect In [44]: print(inspect.getsource(f_lam)) def _lambdifygenerated(Dummy_34, Dummy_33, Dummy_32, m, n): return log((builtins.sum(exp((builtins.sum(Dummy_32[j]*Dummy_34[i, j] Dummy_33[i] for j in range(0, n - 1 1)))) for i in range(0, m - 1 1))))
Сгенерированный код более эффективен, если вы настроите его с использованием матричных символов, а не явных выражений, включающих IndexedBase
:
In [22]: m, n = symbols('m, n') In [23]: a = MatrixSymbol('a', m, n) In [24]: b = MatrixSymbol('b', m, 1) In [25]: x = MatrixSymbol('x', n, 1) In [26]: one = OneMatrix(1, m) In [28]: f = log(one*(a*x b)) In [29]: f_lam = lambdify((a, b, x, m, n), f, 'numpy') In [30]: f_lam(A, B, X, M, N) Out[30]: array([1.52220638]) In [33]: print(inspect.getsource(f_lam)) def _lambdifygenerated(a, b, x, m, n): return log((ones((1, m))).dot((a).dot(x) b))