def inner_product(self, tangent_vec_a, tangent_vec_b, base_point): """Compute the Log-Euclidean inner-product. Compute the inner-product of tangent_vec_a and tangent_vec_b at point base_point using the log-Euclidean metric. Parameters ---------- tangent_vec_a : array-like, shape=[..., n, n] Tangent vector at base point. tangent_vec_b : array-like, shape=[..., n, n] Tangent vector at base point. base_point : array-like, shape=[..., n, n] Base point. Returns ------- inner_product : array-like, shape=[...,] Inner-product. """ spd_space = self.space modified_tangent_vec_a = spd_space.differential_log( tangent_vec_a, base_point) modified_tangent_vec_b = spd_space.differential_log( tangent_vec_b, base_point) product = Matrices.trace_product( modified_tangent_vec_a, modified_tangent_vec_b) return product
def inner_product(self, tangent_vec_a, tangent_vec_b, base_point): r"""Compute the inner-product of two tangent vectors at a base point. Canonical inner-product on the tangent space at `base_point`, which is different from the inner-product induced by the embedding (see [RLSMRZ2017]_). .. math:: \langle\Delta, \tilde{\Delta}\rangle_{U}=\operatorname{tr} \left(\Delta^{T}\left(I-\frac{1}{2} U U^{T}\right) \tilde{\Delta}\right) References ---------- .. [RLSMRZ2017] R Zimmermann. A matrix-algebraic algorithm for the Riemannian logarithm on the Stiefel manifold under the canonical metric. SIAM Journal on Matrix Analysis and Applications 38 (2), 322-342, 2017. https://epubs.siam.org/doi/pdf/10.1137/16M1074485 Parameters ---------- tangent_vec_a : array-like, shape=[..., n, p] First tangent vector at base point. tangent_vec_b : array-like, shape=[..., n, p] Second tangent vector at base point. base_point : array-like, shape=[..., n, p] Point in the Stiefel manifold. Returns ------- inner_prod : array-like, shape=[..., 1] Inner-product of the two tangent vectors. """ base_point_transpose = Matrices.transpose(base_point) aux = gs.matmul( Matrices.transpose(tangent_vec_a), gs.eye(self.n) - 0.5 * gs.matmul(base_point, base_point_transpose), ) inner_prod = Matrices.trace_product(aux, tangent_vec_b) return inner_prod
def _aux_inner_product(tangent_vec_a, tangent_vec_b, inv_base_point): """Compute the inner-product (auxiliary). Parameters ---------- tangent_vec_a : array-like, shape=[..., n, n] tangent_vec_b : array-like, shape=[..., n, n] inv_base_point : array-like, shape=[..., n, n] Returns ------- inner_product : array-like, shape=[...] """ aux_a = Matrices.mul(inv_base_point, tangent_vec_a) aux_b = Matrices.mul(inv_base_point, tangent_vec_b) # Use product instead of matrix product and trace to save time inner_product = Matrices.trace_product(aux_a, aux_b) return inner_product
def test_trace_product(self, mat_a, mat_b, expected): self.assertAllClose( Matrices.trace_product(gs.array(mat_a), gs.array(mat_b)), gs.array(expected))