Source code for arsenal.maths.inv
import numpy as np
from scipy.linalg import inv, det
from scipy.linalg.blas import dger
[docs]class Inv:
def __init__(self, A):
B = np.array(inv(A), order='F', copy=True)
assert B.flags['F_CONTIGUOUS']
self.B = B
[docs] def rank_one_update(self, u, v):
# https://timvieira.github.io/blog/post/2021/03/25/fast-rank-one-updates-to-matrix-inverse/
B = self.B
Bu = B @ u
s = 1 + float(v.T @ Bu)
alpha = -1 / s
# Warning: `overwrite_a=True` silently fails when B is not an order=F array!
dger(alpha, Bu, v.T @ B, a=B, overwrite_a=1)
return s
@property
def value(self):
return self.B
[docs]class InvAndDet(Inv):
def __init__(self, A):
super().__init__(A)
self.D = det(A)
[docs] def rank_one_update(self, u, v):
s = super().rank_one_update(u, v)
self.D *= s
[docs]def test():
n = 10
A = np.random.randn(n,n)
B = inv(A)
u = np.random.randn(n,1)
v = np.random.randn(n,1)
B = InvAndDet(A)
B.rank_one_update(u,v)
assert np.allclose(inv(A + np.outer(u, v)), B.value)
print(det(A + np.outer(u, v)), B.D)
assert np.allclose(det(A + np.outer(u, v)), B.D)
print('ok')
if __name__ == '__main__':
test()