def setUp(self): gs.random.seed(1234) self.n = 3 self.n_samples = 2 self.group = GeneralLinear(n=self.n) self.group_pos = GeneralLinear(self.n, positive_det=True) warnings.simplefilter('ignore', category=ImportWarning)
def test_orbit(self): point = gs.array([[gs.exp(4.), 0.], [0., gs.exp(2.)]]) sqrt = gs.array([[gs.exp(2.), 0.], [0., gs.exp(1.)]]) idty = GeneralLinear(2).identity path = GeneralLinear(2).orbit(point) time = gs.linspace(0., 1., 3) result = path(time) expected = gs.array([idty, sqrt, point]) self.assertAllClose(result, expected)
def test_orbit_vectorization(self): point = gs.array([[gs.exp(4.), 0.], [0., gs.exp(2.)]]) sqrt = gs.array([[gs.exp(2.), 0.], [0., gs.exp(1.)]]) identity = GeneralLinear(2).identity path = GeneralLinear(2).orbit(gs.stack([point] * 2), identity) time = gs.linspace(0., 1., 3) result = path(time) expected = gs.array([identity, sqrt, point]) expected = gs.stack([expected] * 2) self.assertAllClose(result, expected)
def setUp(self): gs.random.seed(0) n = 3 self.base = SPDMatrices(n) self.base_metric = SPDMetricBuresWasserstein(n) self.group = SpecialOrthogonal(n) self.bundle = FiberBundle(GeneralLinear(n), base=self.base, group=self.group) self.quotient_metric = QuotientMetric(self.bundle, ambient_metric=MatricesMetric( n, n)) def submersion(point): return GeneralLinear.mul(point, GeneralLinear.transpose(point)) def tangent_submersion(tangent_vec, base_point): product = GeneralLinear.mul(base_point, GeneralLinear.transpose(tangent_vec)) return 2 * GeneralLinear.to_symmetric(product) def horizontal_lift(tangent_vec, point, base_point=None): if base_point is None: base_point = submersion(point) sylvester = gs.linalg.solve_sylvester(base_point, base_point, tangent_vec) return GeneralLinear.mul(sylvester, point) self.bundle.submersion = submersion self.bundle.tangent_submersion = tangent_submersion self.bundle.horizontal_lift = horizontal_lift self.bundle.lift = gs.linalg.cholesky
def log(self, point, base_point): r"""Compute the Riemannian logarithm of point w.r.t. base_point. Given :math:`P, P'` in Gr(n, k) the logarithm from :math:`P` to :math:`P` is given by the infinitesimal rotation [Batzies2015]_: .. math:: \omega = \frac 1 2 \log \big((2 P' - 1)(2 P - 1)\big) Parameters ---------- point : array-like, shape=[n_samples, n, n] Point in the Grassmannian. base_point : array-like, shape=[n_samples, n, n] Point in the Grassmannian. Returns ------- tangent_vec : array-like, shape=[n_samples, n, n] Tangent vector at `base_point`. References ---------- .. [Batzies2015] Batzies, Hüper, Machado, Leite. "Geometric Mean and Geodesic Regression on Grassmannians" Linear Algebra and its Applications, 466, 83-101, 2015. """ GLn = GeneralLinear(self.n) id_n = GLn.identity() sym2 = 2 * point - id_n sym1 = 2 * base_point - id_n rot = GLn.mul(sym2, sym1) return GLn.log(rot) / 2
def orbit_data(self): point = gs.array([[gs.exp(4.0), 0.0], [0.0, gs.exp(2.0)]]) sqrt = gs.array([[gs.exp(2.0), 0.0], [0.0, gs.exp(1.0)]]) identity = GeneralLinear(2).identity time = gs.linspace(0.0, 1.0, 3) smoke_data = [ dict( n=2, point=point, base_point=identity, time=time, expected=gs.array([identity, sqrt, point]), ), dict( n=2, point=[point, point], base_point=identity, time=time, expected=[ gs.array([identity, sqrt, point]), gs.array([identity, sqrt, point]), ], ), ] return self.generate_tests(smoke_data)
def setUp(self): gs.random.seed(1234) self.n = 3 self.n_samples = 2 self.group = GeneralLinear(n=self.n) # We generate invertible matrices using so3_group self.so3_group = SpecialOrthogonal(n=self.n) warnings.simplefilter('ignore', category=ImportWarning)
def compose_data(self): smoke_data = [ dict( n=2, mat1=[[1.0, 0.0], [0.0, 2.0]], mat2=[[2.0, 0.0], [0.0, 1.0]], expected=2.0 * GeneralLinear(2).identity, ) ] return self.generate_tests(smoke_data)
def test_compose(self): mat1 = gs.array([ [1., 0.], [0., 2.]]) mat2 = gs.array([ [2., 0.], [0., 1.]]) result = self.group.compose(mat1, mat2) expected = 2. * GeneralLinear(2).identity self.assertAllClose(result, expected)
def __init__(self, n): super().__init__( n=n + 1, dim=int((n * (n + 1)) / 2), embedding_space=GeneralLinear(n + 1, positive_det=True), submersion=submersion, value=gs.eye(n + 1), tangent_submersion=tangent_submersion, lie_algebra=SpecialEuclideanMatrixLieAlgebra(n=n)) self.rotations = SpecialOrthogonal(n=n) self.translations = Euclidean(dim=n) self.n = n self.left_canonical_metric = \ SpecialEuclideanMatrixCannonicalLeftMetric(group=self) self.metric = self.left_canonical_metric
def log(self, point, base_point, **kwargs): r"""Compute the Riemannian logarithm of point w.r.t. base_point. Given :math:`P, P'` in Gr(n, k) the logarithm from :math:`P` to :math:`P` is induced by the infinitesimal rotation [Batzies2015]_: .. math:: Y = \frac 1 2 \log \big((2 P' - 1)(2 P - 1)\big) The tangent vector :math:`X` at :math:`P` is then recovered by :math:`X = [Y, P]`. Parameters ---------- point : array-like, shape=[..., n, n] Point. base_point : array-like, shape=[..., n, n] Base point. Returns ------- tangent_vec : array-like, shape=[..., n, n] Riemannian logarithm, a tangent vector at `base_point`. References ---------- .. [Batzies2015] Batzies, Hüper, Machado, Leite. "Geometric Mean and Geodesic Regression on Grassmannians" Linear Algebra and its Applications, 466, 83-101, 2015. """ GLn = GeneralLinear(self.n) id_n = GLn.identity id_n, point, base_point = gs.convert_to_wider_dtype( [id_n, point, base_point]) sym2 = 2 * point - id_n sym1 = 2 * base_point - id_n rot = GLn.compose(sym2, sym1) return Matrices.bracket(GLn.log(rot) / 2, base_point)
def __init__(self, n): super(SPDMatrices, self).__init__( n=n, dim=int(n * (n + 1) / 2), embedding_manifold=GeneralLinear(n=n))
def __init__(self, n): assert isinstance(n, int) and n > 0 super(SPDMatrices, self).__init__(dimension=int(n * (n + 1) / 2), embedding_manifold=GeneralLinear(n=n)) self.n = n