我想迭代一个嵌套列表。我只找到了Numpy的解决方案(在其他情况下是>),但我想知道如果没有Numpy这是否可行。
import numpy as np
def matrix_mulitplication(A, B):
n = A.shape[0]
if n == 1:
return A * B
else:
i = int(n / 2)
C = np.zeros((n, n), dtype=np.int)
C[:i, :i] = matrix_mulitplication(A[:i, :i], B[:i, :i]) + matrix_mulitplication(A[:i, i:], B[i:, :i])
C[:i, i:] = matrix_mulitplication(A[:i, :i], B[:i, i:]) + matrix_mulitplication(A[:i, i:], B[i:, i:])
C[i:, :i] = matrix_mulitplication(A[i:, :i], B[:i, :i]) + matrix_mulitplication(A[i:, i:], B[i:, :i])
C[i:, i:] = matrix_mulitplication(A[i:, :i], B[:i, i:]) + matrix_mulitplication(A[i:, i:], B[i:, i:])
return C
x = np.array([[1, 2], [3, 4]])
y = np.array([[1, 2], [3, 4]])
print(matrix_mulitplication(x, y))
输出:
[[ 7 10]
[15 22]]
我对第一个切片案例的想法:
c_one = [C[i][0:int(len(C) / 2)] for i in range(0,int(len(C) / 2))]
答案 0 :(得分:0)
在numpy
中,您只是进行二维矩阵乘法,可以用多种方式表示,例如np.dot
,np.einsum
或(新的)@
运算符
In [1]: x = np.array([[1, 2], [3, 4]])
In [2]: x@x
Out[2]:
array([[ 7, 10],
[15, 22]])
要对列表执行相同操作,请让我们按步骤处理任务
在代数中,我学会了用一根手指划过各行,另一根指向列。因此,让我们使用列表理解:
In [6]: x1 = x.tolist()
In [7]: x2 = x.tolist()
In [8]: [[(row1,col2) for col2 in zip(*x2)] for row1 in x1]
Out[8]: [[([1, 2], (1, 3)), ([1, 2], (2, 4))], [([3, 4], (1, 3)), ([3, 4], (2, 4))]]
行和列的配对看起来正确。 zip(*xl)
是一种用于转置'的习惯用语。一个列表(相当于numpy中的x.T
)
现在定义一个执行1d乘法的辅助函数:
In [9]: def mult(row,col):
...: return [i*j for i,j in zip(row,col)]
...:
...:
In [10]: [[mult(row1,col2) for col2 in zip(*x2)] for row1 in x1]
Out[10]: [[[1, 6], [2, 8]], [[3, 12], [6, 16]]]
现在添加总和。我可以回去修改mult
,但在外部理解中这样做也很容易。
In [12]: [[sum(mult(row1,col2)) for col2 in zip(*x2)] for row1 in x1]
Out[12]: [[7, 10], [15, 22]]
或者将所有列表推导结合起来,制作一个不可读的行:
In [14]: [[sum(i*j for i,j in zip(row1,col2)) for col2 in zip(*x2)] for row1 in x1]
Out[14]: [[7, 10], [15, 22]]
对于这个2x2示例,我的结果与您的结果相同,但是您采用了不同的方法,将原始数组拆分为块。可以使用切片很好的numpy
数组正常工作。但我不确定它对列表有帮助。我们必须与其他例子一起玩。
Mine使用3x3阵列
In [29]: y = np.arange(9).reshape(3,3)
In [30]: [[sum(mult(row1,col2)) for col2 in zip(*y.tolist())] for row1 in y.toli
...: st()]
Out[30]: [[15, 18, 21], [42, 54, 66], [69, 90, 111]]
In [31]: y@y
Out[31]:
array([[ 15, 18, 21],
[ 42, 54, 66],
[ 69, 90, 111]])
您的3x3上的形状广播错误失败,但在4x4上的效果相同。
In [32]: y = np.arange(16).reshape(4,4)
In [33]: y@y
Out[33]:
array([[ 56, 62, 68, 74],
[152, 174, 196, 218],
[248, 286, 324, 362],
[344, 398, 452, 506]])
In [34]: [[sum(mult(row1,col2)) for col2 in zip(*y.tolist())] for row1 in y.toli
...: st()]
Out[34]:
[[56, 62, 68, 74],
[152, 174, 196, 218],
[248, 286, 324, 362],
[344, 398, 452, 506]]
In [35]: matrix_mulitplication(y,y)
Out[35]:
array([[ 56, 62, 68, 74],
[152, 174, 196, 218],
[248, 286, 324, 362],
[344, 398, 452, 506]])
因此,您的递归是将4x4分解为2x2块然后降至1x1。我将2d阵列分成1d产品总和。
答案 1 :(得分:0)
尝试复制你的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
在没有详细阅读Strassen算法的情况下,很明显任何关于其效率的声明都假定A_ij
索引(对于单个元素或块)在获取值和设置时都是有效的({{1} })。对于列表,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]]
元素都是块而不是标量,这很复杂。
似乎Strassen的目标是减少所需的乘法次数。这假设(标量)乘法是矩阵乘法中最昂贵的部分。使用Python列表显然不是这样的。访问元素更加昂贵。
我可以使用
从4x4案例中修改C
z
这在arr = np.array(z)
arr = arr.transpose(0,2,1,3).reshape(4,4)
中更容易。