目前我使用下面的代码来删除第i行和第j列的子矩阵,但在分析我的代码之后,它似乎是我代码中的主要瓶颈之一。有更有效的方法吗?
def submatrix(A, i, j):
logger.debug('submatrix(%r, %r, %r)', A, i, j)
B = empty(shape=tuple(x - 1 for x in A.shape), dtype=int)
B[:i, :j] = A[:i, :j]
B[i:, :j] = A[i+1:, :j]
B[:i, j:] = A[:i, j+1:]
B[i:, j:] = A[i+1:, j+1:]
return B
25015049 function calls (24599369 primitive calls) in 44.587 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
3983040 15.541 0.000 20.719 0.000 defmatrix.py:301(__getitem__)
415680 10.216 0.000 33.069 0.000 hill.py:127(submatrix)
415686/6 3.232 0.000 44.578 7.430 hill.py:112(det)
编辑:Jaime提供了一种使用常规逆和行列式逼近模块化逆的好方法,但是对于大基数(在我的情况下是模256),不准确性足以使整个事情变得没有意义。主时间接收器似乎实际上是 getitem numpy,但我相信这是由这些线引起的:
B[:i, :j] = A[:i, :j]
B[i:, :j] = A[i+1:, :j]
B[:i, j:] = A[:i, j+1:]
B[i:, j:] = A[i+1:, j+1:]
瓶颈可能不是在内存中复制矩阵,而是矩阵输入访问。
答案 0 :(得分:1)
嗯...你只是在复制矩阵,所以它可能很难加速,但你可以尝试的一件事是验证A是否在一个连续的内存块中,这可以加快C的访问速度码。请看numpy.ascontiguousarray()。
答案 1 :(得分:1)
据我所知,submatrix
只会删除i
行和j
列。您可以使用np.delete
i = 3
j = 4
a = np.arange(100).reshape(10,10)
b = np.delete(np.delete(a, i, 0), j, 1)
但是,对于rason @Jaime引用,这实际上是较慢:-/
timeit submatrix(a, i, j)
#10000 loops, best of 3: 23.2 us per loop
timeit subdel(a, i, j)
#10000 loops, best of 3: 42.6 us per loop
但我现在暂时离开这里。
答案 2 :(得分:1)
使用决定因素计算矩阵的逆矩阵是一种非常慢的方法,无论您如何处理子矩阵。让我们举一个愚蠢的例子:
a = np.array([[3, 0, 2],
[2, 0, -2],
[0, 1, 1]])
您可以快速计算逆转:
>>> np.linalg.inv(a)
array([[ 0.2, 0.2, 0. ],
[-0.2, 0.3, 1. ],
[ 0.2, -0.3, -0. ]])
但是要计算模逆,你需要将它作为整数矩阵除以整数因子。该整数因子当然是决定因素,因此您可以执行以下操作:
>>> np.linalg.inv(a) * np.linalg.det(a)
array([[ 2., 2., 0.],
[ -2., 3., 10.],
[ 2., -3., -0.]])
a
的倒数是这个整数矩阵,除以a
的行列式。作为一项功能,您可以这样做:
def extended_euclidean_algorithm(a, b) :
"""
Computes a solution to a x + b y = gcd(a,b), as well as gcd(a,b),
using the extended Euclidean algorithm.
"""
if b == 0 :
return 1, 0, a
else :
x, y, gcd = extended_euclidean_algorithm(b, a % b)
return y, x - y * (a // b), gcd
def mmi(a, m) :
"""
Computes the modular multiplicative inverse of a modulo m, using the
extended Euclidean algorithm.
"""
x, y, gcd = extended_euclidean_algorithm(a, m)
if gcd == 1 :
return x % m
else :
return None
def modular_inv(a, m):
det_a = np.linalg.det(a)
inv_a = np.linalg.inv(a) * det_a
det_a = np.rint(det_a).astype(int)
inv_a = np.rint(inv_a).astype(int)
return ((inv_a % m) * mmi(det_a, m)) % m
现在:
>>> a = np.random.randint(10, size=(10, 10))
>>> b = modular_inv(a, 7)
>>> a.dot(b) % 7
array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]])