我正在使用FOR实现矩阵的幂运算:
import numpy as np
fl=2
cl=2
fl2=fl
cl2=cl
M = random.random((fl,cl))
M2 = M
Result = np.zeros((fl,cl))
Temp = np.zeros((fl,cl))
itera = 2
print('Matriz A:\n',M)
print('Matriz AxA:\n',M2)
for i in range (0,itera):
for a in range(0,fl):
for b in range (0,cl):
Result[a,b]+=M[a,b]*M[a,b]
temp[a,b]=Result[a,b]
Res[a,k]=M[a,b]
print('Potencia:\n',temp)
print('Matriz:\n', Result)
错误是它在Result[a,b]+=M[a,b]*M[a,b]
中的乘法效果不佳,当我将其保存在临时矩阵中以与原始矩阵相乘时,它不会在for i in range (0,itera):
中进行下一个跳转
我知道我可以执行功能np.matmul
但我尝试使用FOR循环
答案 0 :(得分:1)
您正在寻找np.linalg.matrix_power
。
如果您使用的是numpy
,请不要使用for循环,请使用矢量化操作。
arr = np.arange(16).reshape((4,4))
np.linalg.matrix_power(arr, 3)
array([[ 1680, 1940, 2200, 2460],
[ 4880, 5620, 6360, 7100],
[ 8080, 9300, 10520, 11740],
[11280, 12980, 14680, 16380]])
与显式乘法相同:
arr @ arr @ arr
>>> np.array_equal(arr @ arr @ arr, np.linalg.matrix_power(arr, 3))
True
自从您问到
如果您真的想要使用循环的幼稚解决方案,我们可以很容易地整理各个部分。首先,我们需要一种实际上对矩阵进行多重计算的方法。有一些选项可以克服n ^ 3的复杂性,这个答案是不会做到的。这是基本的矩阵乘法函数:
def matmultiply(a, b):
res = np.zeros(a.shape)
size = a.shape[0]
for i in range(size):
for j in range(size):
for k in range(size):
res[i][j] += a[i][k] * b[k][j]
return res
现在,您需要一个指数函数。此函数获取一个矩阵和一个幂,然后将矩阵提高到该幂。
def loopy_matrix_power(a, n):
res = np.identity(a.shape[0])
while n > 0:
if n % 2 == 0:
a = matmultiply(a, a)
n /= 2
else:
res = matmultiply(res, a)
n -= 1
return res
实际情况:
loopy_matrix_power(arr, 3)
array([[ 1680., 1940., 2200., 2460.],
[ 4880., 5620., 6360., 7100.],
[ 8080., 9300., 10520., 11740.],
[11280., 12980., 14680., 16380.]])
答案 1 :(得分:1)
这里有一些问题:
result
矩阵,因此您将不断添加更多值;和result
分配回m
来执行 next 乘法。我认为最好将矩阵乘法“封装”到一个单独的函数中,例如:
def matmul(a1, a2):
m, ka = a1.shape
kb, n = a2.shape
if ka != kb:
raise ValueError()
res = np.zeros((m, n))
for i in range(m):
for j in range(n):
d = 0.0
for k in range(ka):
d += a1[i,k] * a2[k,j]
res[i, j] = d
return res
然后我们可以使用以下公式计算该矩阵的功效:
m2 = m
for i in range(topow-1):
m = matmul(m, m2)
请注意,我们不能不在这里使用m
作为唯一矩阵。由于如果我们写m = matmul(m, m)
,那么m
现在是m
2
。但这意味着,如果我们第二次执行乘法运算,则会得到m
4
而不是m
3
。
这将产生预期的结果:
>>> cross = np.array([[1,0,1],[0,1,0], [1,0,1]])
>>> matmul(cross, cross)
array([[2., 0., 2.],
[0., 1., 0.],
[2., 0., 2.]])
>>> matmul(cross, matmul(cross, cross))
array([[4., 0., 4.],
[0., 1., 0.],
[4., 0., 4.]])
>>> matmul(cross, matmul(cross, matmul(cross, cross)))
array([[8., 0., 8.],
[0., 1., 0.],
[8., 0., 8.]])
上面的代码可以在 O(n)(线性时间)中计算 M n ,但是我们可以做得更好,我们可以计算此矩阵在对数时间内:我们通过查看幂是否为1
来执行此操作,如果是,则简单地返回矩阵,如果不是,则检查幂是否为偶数,如果是偶数,我们将矩阵与其自身相乘,然后计算该矩阵的幂,但幂除以二,因此 M 2 n =(M×M)< sup> n 。如果幂是 odd ,我们做的差不多相同,只是我们将其乘以 M 的原始值: M 2 n + 1 = M×(M×M) n 。喜欢:
def matpow(m, p):
if p <= 0:
raise ValueError()
if p == 1:
return m
elif p % 2 == 0: # even
return matpow(matmul(m, m), p // 2)
else: # odd
return matmul(m, matpow(matmul(m, m), p // 2))
以上内容可以写得很优美,但我将其保留为练习:)。
但是请注意,与使用numpy提供的矩阵乘法(和其他函数)相比,使用numpy数组进行标量计算通常效率要低 。这些代码经过优化,并且没有 解释,并且通常明显优于Python等效代码。因此,我真的建议您使用这些。还对numpy函数进行了测试,从而减少了其中的bug。