SymPy: lambdify с двумерными входами - PullRequest
1 голос
/ 30 мая 2020

Я вычисляю квадратную матрицу V, каждый элемент которой представляет собой интеграл, который я вычисляю с помощью sympy. Я вычисляю только один определенный интеграл V_nm, результатом которого является числовое выражение с символами c индексами m и n. Скажем, V_nm выглядит так:

>>> V_nm
sin(3*n)*cos(m)

Теперь я буду sh, чтобы сделать двумерную числовую (не символическую c!) Матрицу из V_nm используя m и n в качестве индексов массива. Скажем, для матрицы 2 x 2 результат для данного V_nm будет:

[[sin(3)cos(1) sin(3)cos(2)]
 [sin(6)cos(1) sin(6)cos(2)]]

, то есть n указывает столбец, а m указывает строки. (Примечание: я начинаю m и n с 1 , а не 0 , но это не важно).

Как мне этого добиться?
Я знаю, что могу использовать V_nm.subs([(n, ...), (m, ...)]) в понимании списка, за которым следует evalf(), но это длинный путь. Я использую sh для этого, используя lambdify. Я знаю, как использовать lambdify для одномерных массивов. Подскажите, пожалуйста, как это реализовать для двумерных массивов?

Ответы [ 2 ]

2 голосов
/ 31 мая 2020

Есть sympy's FunctionMatrix, который предназначен для такого рода случаев. Обратите внимание, что он использует индексирование с нуля:

In [1]: m, n, i, j = symbols('m, n, i, j')                                                                                        

In [2]: V_nm = FunctionMatrix(m, n, Lambda((i, j), 100*(i+1) + (j+1)))                                                            

In [3]: V_nm                                                                                                                      
Out[3]: [100⋅i + j + 101]

In [4]: V_nm.subs({m:2, n:3}).as_explicit()                                                                                       
Out[4]: 
⎡101  102  103⎤
⎢             ⎥
⎣201  202  203⎦

In [5]: lambdify((m, n), V_nm)(2, 3)                                                                                              
Out[5]: 
array([[101., 102., 103.],
       [201., 202., 203.]])
1 голос
/ 30 мая 2020

То, что вы спрашиваете, не похоже на стандартную функциональность. Но в два этапа это возможно. Сначала lambdify выражение, а затем создайте функцию, которая генерирует предполагаемый 2D-массив через numpy s широковещательную рассылку :

from sympy import sin, cos, lambdify
from sympy.abc import m, n
import numpy as np

V_mn = sin(3 * n) * cos(m)

V_mn_np = lambdify((m, n), V_mn)
# using list comprehension:
# V_mn_np2D = lambda m, n: np.array([[V_mn_np(i, j) for j in range(n)] for i in range(m)])
# using numpy's broadcasting (faster for large arrays):
V_mn_np2D = lambda m, n: V_mn_np(np.arange(m)[:, None], np.arange(n))

V_mn_np2D(2, 2)

Чтобы начать нумерацию при 1 вместо 0 используйте np.arange(1, m+1) и np.arange(1, n+1).

В качестве теста функция, такая как 100 * m + n, позволяет легко проверить, работает ли подход должным образом.

W_mn = 100 * m + n

W_mn_np = lambdify((m, n), W_mn)
W_mn_np2D = lambda m, n: W_mn_np(np.arange(1, m+1)[:, None], np.arange(1, n+1))

W_mn_np2D(2, 3)

Вывод:

array([[101, 102, 103],
       [201, 202, 203]])
...