def test_multiqr(self): shape = (self.k, self.m, self.m) A_real = np.random.normal(size=shape) q, r = multiqr(A_real) np_testing.assert_allclose(q @ r, A_real) A_complex = np.random.normal( size=shape) + 1j * np.random.normal(size=shape) q, r = multiqr(A_complex) np_testing.assert_allclose(q @ r, A_complex)
def random_point(self): q, _ = multiqr( np.random.normal(size=(self._k, self._n, self._p)) + 1j * np.random.normal(size=(self._k, self._n, self._p))) if self._k == 1: return q[0] return q
def exp(self, point, tangent_vector): U, S, VH = np.linalg.svd(tangent_vector, full_matrices=False) cos_S = np.expand_dims(np.cos(S), -2) sin_S = np.expand_dims(np.sin(S), -2) Y = point @ (multihconj(VH) * cos_S) @ VH + (U * sin_S) @ VH # From numerical experiments, it seems necessary to # re-orthonormalize. This is overall quite expensive. q, _ = multiqr(Y) return q
def random_point(self): # Generate eigenvalues between 1 and 2. d = 1.0 + np.random.uniform(size=(self._k, self._n, 1)) # Generate an orthogonal matrix. q, _ = multiqr(np.random.normal(size=(self._n, self._n))) point = q @ (d * multitransp(q)) if self._k == 1: return point[0] return point
def exp(self, point, tangent_vector): u, s, vt = np.linalg.svd(tangent_vector, full_matrices=False) cos_s = np.expand_dims(np.cos(s), -2) sin_s = np.expand_dims(np.sin(s), -2) Y = point @ (multitransp(vt) * cos_s) @ vt + (u * sin_s) @ vt # From numerical experiments, it seems necessary to re-orthonormalize. # This is quite expensive. q, _ = multiqr(Y) return q
def random_point(self): n, k = self._n, self._k if n == 1: point = np.ones((k, 1, 1)) else: point, _ = multiqr(np.random.normal(size=(k, n, n))) # Swap the first two columns of matrices where det(point) < 0 to # flip the sign of their determinants. negative_det, *_ = np.where(np.linalg.det(point) < 0) slice_ = np.arange(point.shape[1]) point[np.ix_(negative_det, slice_, [0, 1])] = point[np.ix_(negative_det, slice_, [1, 0])] if k == 1: return point[0] return point
def _retraction_qr(self, point, tangent_vector): a = point + tangent_vector point, _ = multiqr(a) return point
def random_point(self): point, _ = multiqr(np.random.normal(size=(self._k, self._n, self._p))) if self._k == 1: return point[0] return point
def _retraction_qr(self, point, tangent_vector): Y = point + point @ tangent_vector q, _ = multiqr(Y) return q