def dlogp(inputs, gradients): (g_logp, ) = gradients cov, delta = inputs g_logp.tag.test_value = floatX(1.0) n, k = delta.shape chol_cov = cholesky(cov) diag = at.diag(chol_cov) ok = at.all(diag > 0) chol_cov = at.switch(ok, chol_cov, at.fill(chol_cov, 1)) delta_trans = solve_lower(chol_cov, delta.T).T inner = n * at.eye(k) - at.dot(delta_trans.T, delta_trans) g_cov = solve_upper(chol_cov.T, inner) g_cov = solve_upper(chol_cov.T, g_cov.T) tau_delta = solve_upper(chol_cov.T, delta_trans.T) g_delta = tau_delta.T g_cov = at.switch(ok, g_cov, -np.nan) g_delta = at.switch(ok, g_delta, -np.nan) return [-0.5 * g_cov * g_logp, -g_delta * g_logp]
def MvNormalLogp(): """Compute the log pdf of a multivariate normal distribution. This should be used in MvNormal.logp once Theano#5908 is released. Parameters ---------- cov: at.matrix The covariance matrix. delta: at.matrix Array of deviations from the mean. """ cov = at.matrix("cov") cov.tag.test_value = floatX(np.eye(3)) delta = at.matrix("delta") delta.tag.test_value = floatX(np.zeros((2, 3))) cholesky = Cholesky(lower=True, on_error="nan") n, k = delta.shape n, k = f(n), f(k) chol_cov = cholesky(cov) diag = at.diag(chol_cov) ok = at.all(diag > 0) chol_cov = at.switch(ok, chol_cov, at.fill(chol_cov, 1)) delta_trans = solve_lower(chol_cov, delta.T).T result = n * k * at.log(f(2) * np.pi) result += f(2) * n * at.sum(at.log(diag)) result += (delta_trans**f(2)).sum() result = f(-0.5) * result logp = at.switch(ok, result, -np.inf) def dlogp(inputs, gradients): (g_logp, ) = gradients cov, delta = inputs g_logp.tag.test_value = floatX(1.0) n, k = delta.shape chol_cov = cholesky(cov) diag = at.diag(chol_cov) ok = at.all(diag > 0) chol_cov = at.switch(ok, chol_cov, at.fill(chol_cov, 1)) delta_trans = solve_lower(chol_cov, delta.T).T inner = n * at.eye(k) - at.dot(delta_trans.T, delta_trans) g_cov = solve_upper(chol_cov.T, inner) g_cov = solve_upper(chol_cov.T, g_cov.T) tau_delta = solve_upper(chol_cov.T, delta_trans.T) g_delta = tau_delta.T g_cov = at.switch(ok, g_cov, -np.nan) g_delta = at.switch(ok, g_delta, -np.nan) return [-0.5 * g_cov * g_logp, -g_delta * g_logp] return OpFromGraph([cov, delta], [logp], grad_overrides=dlogp, inline=True)