Умножьте тензоры, содержащие матрицы, следуя правилу умножения матриц

Скажем, у меня есть тензор, где A, B, C и D все матрицы 2x2:

M = [[A, B],
     [C, D]]

Как мне получить мощность n, например, с n=2, с Python или MATLAB

M^2 = [[A@A + B@C, A@B + B@D],
       [C@A + D@C, C@B + D@D]]

Здесь мощность просто следует обычному правилу умножения матриц; просто элементы сами по себе являются матрицами. Я пробовал matmul, matrix_power и pagemtimes, но ничего не работает.

Пробовали использовать asmatrix() и power() NumPy?

B Remmelzwaal 15.02.2023 22:39

Например, я попытался a = [0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3]; b = reshape(a,2,2,2,2); c = pagemtimes(b,b); disp(c(:,:,1,1)) дать верхнему левому углу элемента c все нули, что должно быть неправильно, поскольку это A@A + B@C.

Kim Dong 15.02.2023 22:58

Расскажите нам больше о формах A, B, C, D и M. np.matmul/@ может работать с более высокими измерениями, чем 2 - прочитайте его документы.

hpaulj 15.02.2023 23:36

Я отредактировал вопрос. A,B,C,D — матрицы 2x2, а M — матрицы 2x2 из матриц 2x2.

Kim Dong 15.02.2023 23:42
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
55
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вероятно, не самое эффективное, но вот ручное решение:

M = np.random.randint(0, 10, (2, 2, 2, 2))

def matmatmul(a, b):
    
    output = np.zeros((a.shape[0], b.shape[1]), dtype = object)
    
    for i in range(output.shape[0]):
        for j in range(output.shape[1]):
            row = a[i]
            col = b[:, j]
            
            output[i,j] = sum([r @ c for r,c in zip(row, col)])
            
    return output

def matmatpow(a, n):
    if n == 1:
        return a
    else:
        output = matmatmul(a, a)
        
        for i in range(2, n):
            output = matmatmul(output, a)
        
        return output
    
M2 = matmatpow(M, 2)

print(M2)

[[A, B], [C, D]] = M

assert np.all(M2[0,0] == A@A + B@C)
assert np.all(M2[0,1] == A@B + B@D)
assert np.all(M2[1,0] == C@A + D@C)
assert np.all(M2[1,1] == C@B + D@D)

Определение набора массивов (2,2) и их составных частей:

In [45]: A,B,C,D = [np.arange(i,i+4).reshape(2,2) for i in range(4)]    
In [46]: M=np.array([[A,B],[C,D]])

Ваш желаемый массив M^2:

In [47]: np.array([[A@A + B@C, A@B + B@D],
    ...:       [C@A + D@C, C@B + D@D]])
Out[47]: 
array([[[[12, 16],
         [28, 40]],

        [[16, 20],
         [40, 52]]],


       [[[28, 40],
         [44, 64]],

        [[40, 52],
         [64, 84]]]])

То же самое с использованием einsum. В этом j и l представлены измерения суммы продуктов:

In [48]: np.einsum('ijkl,jmln->imkn',M,M)
Out[48]: 
array([[[[12, 16],
         [28, 40]],

        [[16, 20],
         [40, 52]]],


       [[[28, 40],
         [44, 64]],

        [[40, 52],
         [64, 84]]]])

matmul эквивалентно ijkl,ijlm->ijkm, где ijbatch размеры, а l — сумма произведений. Часто einsum можно воспроизвести с некоторым изменением формы и общим транспонированием. Но я оставлю это для изучения другим.

Играя с индексами einsum, транспонируя и изменяя массивы, я могу получить эквивалент:

In [56]: np.matmul(M.transpose(0,2,1,3).reshape(4,4),M.transpose(0,2,1,3).reshape(4,4))
Out[56]: 
array([[12, 16, 16, 20],
       [28, 40, 40, 52],
       [28, 40, 40, 52],
       [44, 64, 64, 84]])

который при еще немного массировании становится желаемым (4,4,4,4)

In [57]: np.matmul(M.transpose(0,2,1,3).reshape(4,4),M.transpose(0,2,1,3).reshape(4,4)).reshape(2,2,2,2).transpose(0,2,1,3)
Out[57]: 
array([[[[12, 16],
         [28, 40]],

        [[16, 20],
         [40, 52]]],


       [[[28, 40],
         [44, 64]],

        [[40, 52],
         [64, 84]]]])

Вы просто вычисляете нормальное матричное произведение блочной матрицы 4x4, созданной путем соединения меньших матриц от A до D.

В MATLAB ваш ожидаемый результат с использованием некоторых произвольных матриц:

A = [1, 2
     3, 4];
B = [5, 6
     7, 8];
C = [ 9, 10
     11, 12];
D = [13, 14
     15, 16];

res = [A*A + B*C, A*B + B*D
       C*A + D*C, C*B + D*D]
res =
   118   132   174   188
   166   188   254   276
   310   356   494   540
   358   412   574   628

Блочная матрица 4x4 и ее квадрат:

M = [A, B
     C, D];
res2 = M^2
res2 =
   118   132   174   188
   166   188   254   276
   310   356   494   540
   358   412   574   628

Другие вопросы по теме