def log(self, X, Y): U = multiprod(multitransp(X), Y) if self._k == 1: return multiskew(np.real(logm(U))) for i in range(self._k): U[i] = np.real(logm(U[i])) return multiskew(U)
def euclidean_to_riemannian_hessian(self, point, euclidean_gradient, euclidean_hessian, tangent_vector): Xt = multitransp(point) Xtegrad = Xt @ euclidean_gradient symXtegrad = multisym(Xtegrad) Xtehess = Xt @ euclidean_hessian return multiskew(Xtehess - tangent_vector @ symXtegrad)
def log(self, R, Q): """Riemannian logarithm with base point R evaluated at Q Note that tangent vectors are always represented in the Lie Algebra.Thus, the Riemannian and group operation coincide. """ assert R.shape == Q.shape versors = Rotation.from_matrix(np.einsum('...ij,...kj', Q, R)).as_rotvec() X = np.einsum('ijk,...k', self.versor2skew, versors) return multiskew(X)
def jacobiField(self, R, Q, t, X): """Evaluates a Jacobi field (with boundary conditions gam(0) = X, gam(1) = 0) along the geodesic gam from R to Q. :param R: element of the space of SO(3)^k :param Q: element of the space of SO(3)^k :param t: scalar in [0,1] :param X: tangent vector at R :return: tangent vector at gam(t) """ assert R.shape == Q.shape == X.shape and np.isscalar(t) if t == 1: return np.zeros_like(X) elif t == 0: return X else: # gam(t) P = self.geopoint(R, Q, t) # orthonormal eigenvectors of the Jacobi operator that generate the parallel frame field along gam and the # eigenvalues lam, F = self.jacONB(R, Q) Fp = np.zeros_like(F) alpha = np.zeros_like(lam) for i in range(3): # transport bases elements to gam(t) Fp[:, i, ...] = self.transp(R, P, F[:, i, ...]) # expand X w.r.t. F at R alpha[:, i] = self.eleminner(R, F[:, i, ...], X) # weights for the linear combination of the three basis elements weights = weightfun(lam, t, self.elemdist(R, Q)) # evaluate the adjoint Jacobi field at R a = weights * alpha for i in range(3): Fp[:, i, ...] = vectime3d(a[:, i], Fp[:, i, ...]) return multiskew(np.sum(Fp, axis=1))
def proj(self, X, H): """orthogonal (with respect to the euclidean inner product) projection of ambient vector ((k,3,3) array) onto the tangentspace at X""" # skew-sym. part of: H * X.T return multiskew(np.einsum('...ij,...kj', X, H))
def randvec(self, X): G = self.rand() return multiskew(G / self.norm(X, G))
def rand(self): return multiskew(rnd.randn(*self._shape))
def euclidean_to_riemannian_hessian(self, point, euclidean_gradient, euclidean_hessian, tangent_vector): return multiskew(euclidean_hessian)
def tangent(self, X, H): return multiskew(H)
def proj(self, X, U): return multiskew(U)
def to_tangent_space(self, point, vector): return multiskew(vector)
def projection(self, point, vector): return multiskew(multitransp(point) @ vector)
def log(self, point_a, point_b): return multiskew(multilogm(multitransp(point_a) @ point_b))
def random_tangent_vector(self, point): tangent_vector = self.random_point() return multiskew(tangent_vector / self.norm(point, tangent_vector))
def random_point(self): return multiskew(np.random.normal(size=self._shape))
def egrad2rgrad(self, X, U): return multiskew(U)
def proj(self, X, H): return multiskew(multiprod(multitransp(X), H))
def ehess2rhess(self, X, egrad, ehess, H): return multiskew(ehess)
def ehess2rhess(self, X, egrad, ehess, H): Xt = multitransp(X) Xtegrad = multiprod(Xt, egrad) symXtegrad = multisym(Xtegrad) Xtehess = multiprod(Xt, ehess) return multiskew(Xtehess - multiprod(H, symXtegrad))
def projection(self, point, vector): return multiskew(vector)