Комментарии 9
Удивительное дело, но в русскоязычном сегменте интернета почти нет материала, разъясняющего понятным языком соглашение Эйнштейна о суммировании
Любой нормальный учебник по ОТО или ТеорМеху =)
Всегда можно использовать цепочки вложенных циклов
Это в Python то? Возьмите достаточно большие многомерные массивы и посчитайте что-нибудь на них через "цепочки вложенных циклов". Сколько чашек чая вы успеете выпить до получения результата? Если уж пишете про функции numpy, не над описать такую глупость про "цепочки вложенных циклов", ведь кто-то может действительно подумать, что с numpy-массивами в питоне надо работать через циклы, потому что привычнее и проще, а не то что эти ваши векторизованные операции над массивами вроде всяких непонятных einsum.
Я с тензорами разбирался по книжке Борисенко и Тарапова, но там это подробно не рассмотрено.
Замечу, что у функции einsum
есть параметр optimize
, который отвечает за то, будут ли ваши суммы считаться эффективно или как придётся. По дефолту оптимизация выключена, поэтому при неудачном стечении обстоятельств вычисления могут получиться очень неоптимальными. В примере ниже вычисляется вектор A*A*x
. Без оптимизации сначала перемножаются две матрицы n x n
за O(n^3)
, а потом уже произойдёт умножение на вектор. С оптимизацией всё будет хорошо: произойдёт два умножения матрицы на вектор и сложность будет O(n^2)
.
import numpy as np
n = 1000
x = np.ones((n,))
A = np.ones((n,n))
%time _ = np.einsum("ij,jk,k->i", A,A,x)
> CPU times: user 2.51 s, sys: 3 µs, total: 2.51 s
> Wall time: 2.51 s
%time _ = np.einsum("ij,jk,k->i", A,A,x, optimize=True)
> CPU times: user 635 µs, sys: 8.01 ms, total: 8.65 ms
> Wall time: 8.55 ms
Можно ещё указывать optimize="optimal"
, тогда из всех вариантов вычисления суммы будет выбран оптимальный, в то время как optimize=True
(алиас для optimize="greedy"
) означает использование жадного алгоритма для оптимизации.
Более того, optimize="optimal"
почему-то умеет заставлять einsum работать с тензорами, у которых компоненты — произвольные объекты (например из sympy).
Например, код
x,y = symbols("x y")
coords = np.array([x,y])
g = np.identity(2)
print(np.einsum("ij,i,j", g, coords, coords))
выдает ошибку TypeError: invalid data type for einsum
Но если сделать
print(np.einsum("ij,i,j", g, coords, coords, optimize="optimal"))
внезапно получается правильный ответ 1.0*x**2 + 1.0*y**2
.
Соглашение Эйнштейна и einsum