Попытка скопировать ваше подразделение nxn.Я использовал вспомогательную функцию blk
для репликации среза массива 2d:
import numpy as np
def matrix_mulitplication(A, B):
def blk(x,i1,i2):
return [row[i2] for row in x[i1]]
n = len(A) # A.shape[0]
if n == 1:
#print(A)
return A[0][0] * B[0][0]
else:
i = int(n / 2)
i1, i2 = slice(None,i), slice(i,None)
#C = np.zeros((n, n), dtype=np.int)
C1 = matrix_mulitplication(blk(A, i1, i1), blk(B,i1,i1)) +\
matrix_mulitplication(blk(A, i1, i2), blk(B,i2,i1))
C2 = matrix_mulitplication(blk(A, i1, i1), blk(B,i1,i2)) +\
matrix_mulitplication(blk(A, i1, i2), blk(B,i2,i2))
C3 = matrix_mulitplication(blk(A, i2, i1), blk(B,i1,i1)) +\
matrix_mulitplication(blk(A, i2, i2), blk(B,i2,i1))
C4 = matrix_mulitplication(blk(A, i2, i1), blk(B,i1,i2)) +\
matrix_mulitplication(blk(A, i2, i2), blk(B,i2,i2))
C = [[C1,C2],[C3,C4]]
return C
x = np.array([[1, 2], [3, 4]])
y = np.arange(16).reshape(4,4)
z = matrix_mulitplication([[1]],[[2]])
print(z)
z = matrix_mulitplication(x.tolist(), x.tolist())
print(z)
print(x@x)
z = matrix_mulitplication(y.tolist(), y.tolist())
print(z)
print(y@y)
Это работает для одного уровня рекурсии, но не для двух:
1253:~/mypy$ python3 stack50552791.py
2
[[7, 10], [15, 22]]
[[ 7 10]
[15 22]]
[[[[4, 5], [20, 29], [52, 57], [132, 145]], [[6, 7], [38, 47], [62, 67], [158, 171]]], [[[36, 53], [52, 77], [212, 233], [292, 321]], [[70, 87], [102, 127], [254, 275], [350, 379]]]]
[[ 56 62 68 74]
[152 174 196 218]
[248 286 324 362]
[344 398 452 506]]
Проблема со вторымУровень в том, что matrix_mulitplication
возвращает вложенный список, а список +
определяется как конкатенация, а не добавление элемента.Поэтому мне нужно определить другую вспомогательную функцию (или 2) для правильного решения этой проблемы.
чуть лучше
def matrix_mulitplication(A, B):
def blk(x,i1,i2):
return [row[i2] for row in x[i1]]
def add(x,y):
if isinstance(x, list):
return [add(i,j) for i,j in zip(x,y)]
else:
return x+y
n = len(A) # A.shape[0]
if n == 1:
return A[0][0] * B[0][0]
else:
i = int(n / 2)
i1, i2 = slice(None,i), slice(i,None)
#C = np.zeros((n, n), dtype=np.int)
C1 = add(matrix_mulitplication(blk(A, i1, i1), blk(B,i1,i1)) ,\
matrix_mulitplication(blk(A, i1, i2), blk(B,i2,i1)))
C2 = add(matrix_mulitplication(blk(A, i1, i1), blk(B,i1,i2)) ,\
matrix_mulitplication(blk(A, i1, i2), blk(B,i2,i2)))
C3 = add(matrix_mulitplication(blk(A, i2, i1), blk(B,i1,i1)) ,\
matrix_mulitplication(blk(A, i2, i2), blk(B,i2,i1)))
C4 = add(matrix_mulitplication(blk(A, i2, i1), blk(B,i1,i2)) ,\
matrix_mulitplication(blk(A, i2, i2), blk(B,i2,i2)))
C = [[C1,C2],[C3,C4]]
return C
и для случая 4x4
[[[[56, 62], [152, 174]], [[68, 74], [196, 218]]], [[[248, 286], [344, 398]], [[324, 362], [452, 506]]]]
[[ 56 62 68 74]
[152 174 196 218]
[248 286 324 362]
[344 398 452 506]]
Все числа есть, но во вложенном списке из 4 глубин.
Так что не только разбивать вложенный список на 2d блоки более неудобно, чем с массивами, их сборка также неудобна.
https://en.wikipedia.org/wiki/Strassen_algorithm
Без подробного ознакомления с алгоритмом Штрассена очевидно, что любые утверждения о его эффективности предполагают, что индексирование A_ij
(для отдельных элементов или блоков) является эффективным, какпри получении значений и настроек (C_ij
).Со списками A[i]
или A[i:j]
довольно эффективны, но [row[i2] for row in x[i1]
- нет.
Сборка блоков с [[a,b],[c,d]]
- это нормально, но все, что сопоставимо с [[C_11,C_12],[C_21,C_22]]
, где элементы C
Блоки, в отличие от скаляров, сложны.
Кажется, что целью Штрассена является уменьшение необходимого количества умножений.Это предполагает, что (скалярные) умножения являются самой дорогой частью умножения матриц.Со списками Python это явно не так.Доступ к элементам обходится дороже.
нудистский чит
Я мог бы переделать z
из корпуса 4x4 с
arr = np.array(z)
arr = arr.transpose(0,2,1,3).reshape(4,4)
Это намного проще в numpy
.