Как заменить переменную 2D IndexedBase в Sympy

#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))