Цитирование со страницы документации einsum
:
Для включения и контроля трансляции используйте многоточие. Трансляция в стиле NumPy по умолчанию выполняется путем добавления многоточия слева от каждого термина, например np.einsum('...ii->...i', a)
. Чтобы провести трассировку вдоль первой и последней осей, вы можете сделать np.einsum('i...i', a)
, или сделать матрично-матричный продукт с крайними левыми индексами вместо правого, можно сделать np.einsum('ij...,jk...->ik...', a, b)
.
Позже приведен пример:
>>> a = np.arange(25).reshape(5,5)
>>> np.einsum('...j->...', a)
array([ 10, 35, 60, 85, 110])
Эквивалентный MATLAB-код для этого примера:
>> a = reshape(0:24, [5,5]).';
>> sum(a,2).'
ans =
10 35 60 85 110
Несколько замечаний:
- Оператор с многоточием (
...
) следует понимать не как «диапазон», а как «все, что должно быть там». - " Broadcasting " относится к автоматической c репликации массива по соответствующему измерению для определения математической операции. Эта функция существует в MATLAB начиная с R2016b (так называемое «неявное расширение»).
- Вы можете заметить несколько операций транспонирования (
.'
) в эквиваленте MATLAB. Это связано с тем, что массивы numpy являются основными по строкам, а массивы MATLAB - основными по столбцам. Практически, в то время как базовые данные имеют тот же последовательный порядок, массив numpy выглядит транспонированным по сравнению с MATLAB. Транспонирование было сделано так, чтобы массивы выглядели одинаково на промежуточных этапах.
Другой пример из этих документов:
>>> a = np.arange(6).reshape((3,2))
>>> b = np.arange(12).reshape((4,3))
>>> np.einsum('ki,jk->ij', a, b)
array([[10, 28, 46, 64],
[13, 40, 67, 94]])
>>> np.einsum('ki,...k->i...', a, b)
array([[10, 28, 46, 64],
[13, 40, 67, 94]])
>>> np.einsum('k...,jk', a, b)
array([[10, 28, 46, 64],
[13, 40, 67, 94]])
, который можно записать в MATLAB следующим образом :
A = reshape(0:5, [2 3]).';
B = reshape(0:11, [3 4]).';
A.' * B.'
permute(sum( permute(A, [3 1 2]) .* B,2), [3 1 2])
shiftdim(sum( shiftdim(A, -1) .* B, 2), 2)
Несколько замечаний:
- При переходе от
np.einsum('ki,jk->ij', a, b)
к np.einsum('ki,...k->i...', a, b)
видно, что j
-ое измерение заменено на ...
. Тот факт, что оба эти примера содержат ->
, означает, что он находится в явном режиме . - При переходе от
np.einsum('ki,jk->ij', a, b)
к np.einsum('k...,jk', a, b)
вы можете видеть, что теперь i
-ое измерение заменено на ...
. Пропуск ->...j
просто демонстрирует неявный режим (где выходные размеры упорядочены в алфавитном порядке).