Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
# Test `Woodbury`.
a = np.random.randn(3, 2)
b = np.random.randn(2, 2) + 1e-2 * np.eye(2)
wb = d + LowRank(left=a, middle=b.dot(b.T))
for _ in range(4):
allclose(B.matmul(wb, B.inverse(wb)), np.eye(3))
allclose(B.matmul(B.inverse(wb), wb), np.eye(3))
allclose(B.logdet(wb), np.log(np.linalg.det(to_np(wb))))
wb = B.inverse(wb)
# Test `LowRank`.
with pytest.raises(RuntimeError):
B.inverse(wb.lr)
with pytest.raises(RuntimeError):
B.logdet(wb.lr)
def test_inverse_and_logdet():
# Test `Dense`.
a = np.random.randn(3, 3)
a = Dense(a.dot(a.T))
allclose(B.matmul(a, B.inverse(a)), np.eye(3))
allclose(B.matmul(B.inverse(a), a), np.eye(3))
allclose(B.logdet(a), np.log(np.linalg.det(to_np(a))))
# Test `Diagonal`.
d = Diagonal(np.array([1, 2, 3]))
allclose(B.matmul(d, B.inverse(d)), np.eye(3))
allclose(B.matmul(B.inverse(d), d), np.eye(3))
allclose(B.logdet(d), np.log(np.linalg.det(to_np(d))))
assert B.shape(B.inverse(Diagonal(np.array([1, 2]),
rows=2, cols=4))) == (4, 2)
# Test `Woodbury`.
a = np.random.randn(3, 2)
b = np.random.randn(2, 2) + 1e-2 * np.eye(2)
wb = d + LowRank(left=a, middle=b.dot(b.T))
for _ in range(4):
allclose(B.matmul(wb, B.inverse(wb)), np.eye(3))
allclose(B.matmul(B.inverse(wb), wb), np.eye(3))
L_z = B.cholesky(self._K_z)
self._A = B.add(B.eye(self._K_z),
B.iqf(K_n, B.transpose(B.solve(L_z, K_zx))))
y_bar = uprank(self.y) - self.e.mean(x_n) - self.graph.means[p_x](x)
prod_y_bar = B.solve(L_z, B.iqf(K_n, B.transpose(K_zx), y_bar))
# Compute the optimal mean.
self._mu = B.add(self.graph.means[p_z](z),
B.iqf(self._A, B.solve(L_z, self._K_z), prod_y_bar))
# Compute the ELBO.
# NOTE: The calculation of `trace_part` asserts that `K_n` is diagonal.
# The rest, however, is completely generic.
trace_part = B.ratio(Diagonal(self.graph.kernels[p_x].elwise(x)[:, 0]) -
Diagonal(B.iqf_diag(self._K_z, K_zx)), K_n)
det_part = B.logdet(2 * B.pi * K_n) + B.logdet(self._A)
iqf_part = B.iqf(K_n, y_bar)[0, 0] - B.iqf(self._A, prod_y_bar)[0, 0]
self._elbo = -0.5 * (trace_part + det_part + iqf_part)
@B.inverse.extend(LowRank)
def inverse(a): raise RuntimeError('Matrix is singular.')
# Compute the log-determinant of matrices.
@_dispatch({B.Numeric, Dense})
def logdet(a):
a = matrix(a)
if a.logdet is None:
a.logdet = 2 * B.sum(B.log(B.diag(B.cholesky(a))))
return a.logdet
B.logdet = logdet # Record in LAB.
@B.logdet.extend(Diagonal)
def logdet(a): return B.sum(B.log(a.diag))
@B.logdet.extend(Woodbury)
def logdet(a):
return B.logdet(B.schur(a)) + \
B.logdet(a.diag) + \
B.logdet(a.lr.middle if a.lr_pd else -a.lr.middle)
@B.logdet.extend(LowRank)
def logdet(a): raise RuntimeError('Matrix is singular.')
def logdet(a):
return B.logdet(B.schur(a)) + \
B.logdet(a.diag) + \
B.logdet(a.lr.middle if a.lr_pd else -a.lr.middle)