Ejemplo n.º 1
0
    def test_parallel_transport(self, n):
        space = SPDMatrices(*n)
        metric = self.metric(*n)
        shape = (2, *n, *n)

        point = space.random_point(2)
        end_point = space.random_point(2)
        tan_b = gs.random.rand(*shape)
        tan_b = space.to_tangent(tan_b, point)

        # use a vector orthonormal to tan_b
        tan_a = gs.random.rand(*shape)
        tan_a = space.to_tangent(tan_a, point)

        # orthonormalize and move to base_point
        tan_a -= gs.einsum(
            "...,...ij->...ij",
            metric.inner_product(tan_a, tan_b, point) /
            metric.squared_norm(tan_b, point),
            tan_b,
        )
        tan_b = gs.einsum("...ij,...->...ij", tan_b,
                          1.0 / metric.norm(tan_b, point))
        tan_a = gs.einsum("...ij,...->...ij", tan_a,
                          1.0 / metric.norm(tan_a, point))

        transported = metric.parallel_transport(tan_a,
                                                point,
                                                end_point=end_point,
                                                n_steps=15,
                                                step="rk4")
        result = metric.norm(transported, end_point)
        expected = metric.norm(tan_a, point)
        self.assertAllClose(result, expected)

        is_tangent = space.is_tangent(transported, end_point)
        self.assertTrue(gs.all(is_tangent))

        transported = metric.parallel_transport(tan_a,
                                                point,
                                                tan_b,
                                                n_steps=15,
                                                step="rk4")

        end_point = metric.exp(tan_b, point)
        result = metric.norm(transported, end_point)
        expected = metric.norm(tan_a, point)
        self.assertAllClose(result, expected)

        is_tangent = space.is_tangent(transported, end_point)
        self.assertTrue(gs.all(is_tangent))
Ejemplo n.º 2
0
 def test_estimate_spd_two_samples(self):
     space = SPDMatrices(3)
     metric = SPDMetricAffine(3)
     point = space.random_point(2)
     mean = FrechetMean(metric)
     mean.fit(point)
     result = mean.estimate_
     expected = metric.exp(metric.log(point[0], point[1]) / 2, point[1])
     self.assertAllClose(expected, result)
Ejemplo n.º 3
0
    def test_batched(self):
        space = SPDMatrices(3)
        metric = SPDMetricAffine(3)
        point = space.random_point(4)
        mean_batch = FrechetMean(metric, method="batch", verbose=True)
        data = gs.stack([point[:2], point[2:]], axis=1)
        mean_batch.fit(data)
        result = mean_batch.estimate_

        mean = FrechetMean(metric)
        mean.fit(data[:, 0])
        expected_1 = mean.estimate_
        mean.fit(data[:, 1])
        expected_2 = mean.estimate_
        expected = gs.stack([expected_1, expected_2])
        self.assertAllClose(expected, result)
Ejemplo n.º 4
0
class TestSPDMatrices(geomstats.tests.TestCase):
    """Test of SPDMatrices methods."""
    def setUp(self):
        """Set up the test."""
        warnings.simplefilter('ignore', category=ImportWarning)

        gs.random.seed(1234)

        self.n = 3
        self.space = SPDMatrices(n=self.n)
        self.metric_affine = SPDMetricAffine(n=self.n)
        self.metric_bureswasserstein = SPDMetricBuresWasserstein(n=self.n)
        self.metric_euclidean = SPDMetricEuclidean(n=self.n)
        self.metric_logeuclidean = SPDMetricLogEuclidean(n=self.n)
        self.n_samples = 4

    def test_belongs(self):
        """Test of belongs method."""
        mats = gs.array([[3., -1.], [-1., 3.]])
        result = SPDMatrices(2).belongs(mats)
        expected = True
        self.assertAllClose(result, expected)

        mats = gs.array([[-1., -1.], [-1., 3.]])
        result = SPDMatrices(2).belongs(mats)
        expected = False
        self.assertAllClose(result, expected)

        mats = gs.eye(3)
        result = SPDMatrices(2).belongs(mats)
        expected = False
        self.assertAllClose(result, expected)

    def test_belongs_vectorization(self):
        """Test of belongs method."""
        mats = gs.array([[[1., 0], [0, 1.]], [[1., 2.], [2., 1.]],
                         [[1., 0.], [1., 1.]]])
        result = SPDMatrices(2).belongs(mats)
        expected = gs.array([True, False, False])
        self.assertAllClose(result, expected)

    def test_random_point_and_belongs(self):
        """Test of random_point and belongs methods."""
        point = self.space.random_point()
        result = self.space.belongs(point)
        expected = True
        self.assertAllClose(result, expected)

    def test_random_point_and_belongs_vectorization(self):
        """Test of random_point and belongs methods."""
        points = self.space.random_point(4)
        result = self.space.belongs(points)
        expected = gs.array([True] * 4)
        self.assertAllClose(result, expected)

    def test_vector_from_symmetric_matrix_and_symmetric_matrix_from_vector(
            self):
        """Test for matrix to vector and vector to matrix conversions."""
        sym_mat_1 = gs.array([[1., 0.6, -3.], [0.6, 7., 0.], [-3., 0., 8.]])
        vector_1 = self.space.to_vector(sym_mat_1)
        result_1 = self.space.from_vector(vector_1)
        expected_1 = sym_mat_1

        self.assertTrue(gs.allclose(result_1, expected_1))

        vector_2 = gs.array([1., 2., 3., 4., 5., 6.])
        sym_mat_2 = self.space.from_vector(vector_2)
        result_2 = self.space.to_vector(sym_mat_2)
        expected_2 = vector_2

        self.assertTrue(gs.allclose(result_2, expected_2))

    def test_vector_and_symmetric_matrix_vectorization(self):
        """Test of vectorization."""
        n_samples = self.n_samples
        vector = gs.random.rand(n_samples, 6)
        sym_mat = self.space.from_vector(vector)
        result = self.space.to_vector(sym_mat)
        expected = vector

        self.assertTrue(gs.allclose(result, expected))

        sym_mat = self.space.random_point(n_samples)
        vector = self.space.to_vector(sym_mat)
        result = self.space.from_vector(vector)
        expected = sym_mat

        self.assertTrue(gs.allclose(result, expected))

    def test_logm(self):
        """Test of logm method."""
        expected = gs.array([[[0., 1., 0.], [1., 0., 0.], [0., 0., 1.]]])
        c = math.cosh(1)
        s = math.sinh(1)
        e = math.exp(1)
        v = gs.array([[[c, s, 0.], [s, c, 0.], [0., 0., e]]])
        result = self.space.logm(v)
        self.assertAllClose(result, expected)

    def test_differential_power(self):
        """Test of differential_power method."""
        base_point = gs.array([[1., 0., 0.], [0., 2.5, 1.5], [0., 1.5, 2.5]])
        tangent_vec = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]])
        power = .5
        result = self.space.differential_power(power=power,
                                               tangent_vec=tangent_vec,
                                               base_point=base_point)
        expected = gs.array([[1., 1 / 3, 1 / 3], [1 / 3, .125, .125],
                             [1 / 3, .125, .125]])
        self.assertAllClose(result, expected)

    def test_inverse_differential_power(self):
        """Test of inverse_differential_power method."""
        base_point = gs.array([[1., 0., 0.], [0., 2.5, 1.5], [0., 1.5, 2.5]])
        tangent_vec = gs.array([[1., 1 / 3, 1 / 3], [1 / 3, .125, .125],
                                [1 / 3, .125, .125]])
        power = .5
        result = self.space.inverse_differential_power(power=power,
                                                       tangent_vec=tangent_vec,
                                                       base_point=base_point)
        expected = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]])
        self.assertAllClose(result, expected)

    def test_differential_log(self):
        """Test of differential_log method."""
        base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 4.]])
        tangent_vec = gs.array([[1., 1., 3.], [1., 1., 3.], [3., 3., 4.]])
        result = self.space.differential_log(tangent_vec, base_point)
        x = 2 * gs.log(2.)
        expected = gs.array([[1., 1., x], [1., 1., x], [x, x, 1]])

        self.assertAllClose(result, expected)

    def test_inverse_differential_log(self):
        """Test of inverse_differential_log method."""
        base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 4.]])
        x = 2 * gs.log(2.)
        tangent_vec = gs.array([[1., 1., x], [1., 1., x], [x, x, 1]])
        result = self.space.inverse_differential_log(tangent_vec, base_point)
        expected = gs.array([[1., 1., 3.], [1., 1., 3.], [3., 3., 4.]])
        self.assertAllClose(result, expected)

    def test_differential_exp(self):
        """Test of differential_exp method."""
        base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., -1.]])
        tangent_vec = gs.array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
        result = self.space.differential_exp(tangent_vec, base_point)
        x = gs.exp(1.)
        y = gs.sinh(1.)
        expected = gs.array([[x, x, y], [x, x, y], [y, y, 1 / x]])

        self.assertAllClose(result, expected)

    def test_inverse_differential_exp(self):
        """Test of inverse_differential_exp method."""
        base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., -1.]])
        x = gs.exp(1.)
        y = gs.sinh(1.)
        tangent_vec = gs.array([[x, x, y], [x, x, y], [y, y, 1. / x]])
        result = self.space.inverse_differential_exp(tangent_vec, base_point)
        expected = gs.array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
        self.assertAllClose(result, expected)

    def test_bureswasserstein_inner_product(self):
        """Test of SPDMetricBuresWasserstein.inner_product method."""
        base_point = gs.array([[1., 0., 0.], [0., 1.5, .5], [0., .5, 1.5]])
        tangent_vec_a = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]])
        tangent_vec_b = gs.array([[1., 2., 4.], [2., 3., 8.], [4., 8., 5.]])
        metric = SPDMetricBuresWasserstein(3)
        result = metric.inner_product(tangent_vec_a, tangent_vec_b, base_point)
        expected = gs.array(4.)

        self.assertAllClose(result, expected)

    def test_power_affine_inner_product(self):
        """Test of SPDMetricAffine.inner_product method."""
        base_point = gs.array([[1., 0., 0.], [0., 2.5, 1.5], [0., 1.5, 2.5]])
        tangent_vec = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]])
        metric = SPDMetricAffine(3, power_affine=.5)
        result = metric.inner_product(tangent_vec, tangent_vec, base_point)
        expected = 713 / 144

        self.assertAllClose(result, expected)

    def test_power_euclidean_inner_product(self):
        """Test of SPDMetricEuclidean.inner_product method."""
        base_point = gs.array([[1., 0., 0.], [0., 2.5, 1.5], [0., 1.5, 2.5]])
        tangent_vec = gs.array([[2., 1., 1.], [1., .5, .5], [1., .5, .5]])
        metric = SPDMetricEuclidean(3, power_euclidean=.5)
        result = metric.inner_product(tangent_vec, tangent_vec, base_point)
        expected = 3472 / 576
        self.assertAllClose(result, expected)

        result = self.metric_euclidean.inner_product(tangent_vec, tangent_vec,
                                                     base_point)
        expected = MatricesMetric(3, 3).inner_product(tangent_vec, tangent_vec)

        self.assertAllClose(result, expected)

    @geomstats.tests.np_and_tf_only
    def test_euclidean_exp_domain(self):
        """Test of SPDMetricEuclidean.exp_domain method."""
        base_point = gs.array([[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]])
        tangent_vec = gs.array([[-1., 0., 0.], [0., -.5, 0.], [0., 0., 1.]])
        metric = self.metric_euclidean
        result = metric.exp_domain(tangent_vec, base_point)
        expected = gs.array([-3, 1])

        self.assertAllClose(result, expected)

    def test_log_euclidean_inner_product(self):
        """Test of SPDMetricLogEuclidean.inner_product method."""
        base_point = gs.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 4.]])
        tangent_vec = gs.array([[1., 1., 3.], [1., 1., 3.], [3., 3., 4.]])
        metric = self.metric_logeuclidean
        result = metric.inner_product(tangent_vec, tangent_vec, base_point)
        x = 2 * gs.log(2.)
        expected = 5. + 4. * x**2

        self.assertAllClose(result, expected)

    def test_log_and_exp_affine_invariant(self):
        """Test of SPDMetricAffine.log and exp methods with power=1."""
        base_point = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]])
        point = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]])

        metric = self.metric_affine
        log = metric.log(point=point, base_point=base_point)
        result = metric.exp(tangent_vec=log, base_point=base_point)
        expected = point

        self.assertAllClose(result, expected)

    def test_log_and_exp_power_affine(self):
        """Test of SPDMetricAffine.log and exp methods with power!=1."""
        base_point = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]])
        point = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]])
        metric = SPDMetricAffine(3, power_affine=.5)
        log = metric.log(point, base_point)
        result = metric.exp(log, base_point)
        expected = point
        self.assertAllClose(result, expected)

    def test_log_and_exp_bureswasserstein(self):
        """Test of SPDMetricBuresWasserstein.log and exp methods."""
        base_point = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]])
        point = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]])

        metric = self.metric_bureswasserstein
        log = metric.log(point=point, base_point=base_point)
        result = metric.exp(tangent_vec=log, base_point=base_point)
        expected = point

        self.assertAllClose(result, expected)

    def test_log_and_exp_logeuclidean(self):
        """Test of SPDMetricLogEuclidean.log and exp methods."""
        base_point = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]])
        point = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]])

        metric = self.metric_logeuclidean
        log = metric.log(point=point, base_point=base_point)
        result = metric.exp(tangent_vec=log, base_point=base_point)
        expected = point

        self.assertAllClose(result, expected)

    def test_exp_and_belongs(self):
        """Test of SPDMetricAffine.exp with power=1 and belongs methods."""
        n_samples = self.n_samples
        base_point = self.space.random_point(n_samples=1)
        tangent_vec = self.space.random_tangent_vec(n_samples=n_samples,
                                                    base_point=base_point)
        metric = self.metric_affine
        exps = metric.exp(tangent_vec, base_point)
        result = self.space.belongs(exps)
        expected = gs.array([True] * n_samples)

        self.assertAllClose(result, expected)

    def test_exp_vectorization(self):
        """Test of SPDMetricAffine.exp with power=1 and vectorization."""
        n_samples = self.n_samples
        one_base_point = self.space.random_point(n_samples=1)
        n_base_point = self.space.random_point(n_samples=n_samples)

        n_tangent_vec_same_base = self.space.random_tangent_vec(
            n_samples=n_samples, base_point=one_base_point)
        n_tangent_vec = self.space.random_tangent_vec(n_samples=n_samples,
                                                      base_point=n_base_point)
        metric = self.metric_affine

        # Test with the 1 base_point, and several different tangent_vecs
        result = metric.exp(n_tangent_vec_same_base, one_base_point)

        self.assertAllClose(gs.shape(result),
                            (n_samples, self.space.n, self.space.n))

        # Test with the same number of base_points and tangent_vecs
        result = metric.exp(n_tangent_vec, n_base_point)

        self.assertAllClose(gs.shape(result),
                            (n_samples, self.space.n, self.space.n))

    def test_log_vectorization(self):
        """Test of SPDMetricAffine.log with power 1 and vectorization."""
        n_samples = self.n_samples
        one_base_point = self.space.random_point(n_samples=1)
        n_base_point = self.space.random_point(n_samples=n_samples)

        one_point = self.space.random_point(n_samples=1)
        n_point = self.space.random_point(n_samples=n_samples)
        metric = self.metric_affine

        # Test with different points, one base point
        result = metric.log(n_point, one_base_point)

        self.assertAllClose(gs.shape(result),
                            (n_samples, self.space.n, self.space.n))

        # Test with the same number of points and base points
        result = metric.log(n_point, n_base_point)

        self.assertAllClose(gs.shape(result),
                            (n_samples, self.space.n, self.space.n))

        # Test with the one point and n base points
        result = metric.log(one_point, n_base_point)

        self.assertAllClose(gs.shape(result),
                            (n_samples, self.space.n, self.space.n))

    def test_geodesic_and_belongs(self):
        """Test of SPDMetricAffine.geodesic with power 1 and belongs."""
        initial_point = self.space.random_point()
        initial_tangent_vec = self.space.random_tangent_vec(
            n_samples=1, base_point=initial_point)
        metric = self.metric_affine
        geodesic = metric.geodesic(initial_point=initial_point,
                                   initial_tangent_vec=initial_tangent_vec)

        n_points = 10
        t = gs.linspace(start=0., stop=1., num=n_points)
        points = geodesic(t)
        result = self.space.belongs(points)
        self.assertTrue(gs.all(result))

    def test_squared_dist_is_symmetric(self):
        """Test of SPDMetricAffine.squared_dist (power=1) and is_symmetric."""
        n_samples = self.n_samples

        point_1 = self.space.random_point(n_samples=1)
        point_2 = self.space.random_point(n_samples=1)
        point_1 = gs.cast(point_1, gs.float64)
        point_2 = gs.cast(point_2, gs.float64)

        metric = self.metric_affine

        sq_dist_1_2 = metric.squared_dist(point_1, point_2)
        sq_dist_2_1 = metric.squared_dist(point_2, point_1)

        self.assertAllClose(sq_dist_1_2, sq_dist_2_1)

        point_2 = self.space.random_point(n_samples=n_samples)
        point_2 = gs.cast(point_2, gs.float64)

        sq_dist_1_2 = metric.squared_dist(point_1, point_2)
        sq_dist_2_1 = metric.squared_dist(point_2, point_1)
        self.assertAllClose(sq_dist_1_2, sq_dist_2_1)

        point_1 = self.space.random_point(n_samples=n_samples)
        point_2 = self.space.random_point(n_samples=1)
        point_1 = gs.cast(point_1, gs.float64)
        point_2 = gs.cast(point_2, gs.float64)

        sq_dist_1_2 = metric.squared_dist(point_1, point_2)
        sq_dist_2_1 = metric.squared_dist(point_2, point_1)

        self.assertAllClose(sq_dist_1_2, sq_dist_2_1)

        sq_dist_1_2 = metric.squared_dist(point_1, point_2)
        sq_dist_2_1 = metric.squared_dist(point_2, point_1)

        self.assertAllClose(sq_dist_1_2, sq_dist_2_1)

    def test_squared_dist_vectorization(self):
        """Test of SPDMetricAffine.squared_dist (power=1) and vectorization."""
        n_samples = self.n_samples
        point_1 = self.space.random_point(n_samples=n_samples)
        point_2 = self.space.random_point(n_samples=n_samples)

        metric = self.metric_affine
        result = metric.squared_dist(point_1, point_2)

        self.assertAllClose(gs.shape(result), (n_samples, ))

        point_1 = self.space.random_point(n_samples=1)
        point_2 = self.space.random_point(n_samples=n_samples)

        result = metric.squared_dist(point_1, point_2)

        self.assertAllClose(gs.shape(result), (n_samples, ))

        point_1 = self.space.random_point(n_samples=n_samples)
        point_2 = self.space.random_point(n_samples=1)

        result = metric.squared_dist(point_1, point_2)

        self.assertAllClose(gs.shape(result), (n_samples, ))

        point_1 = self.space.random_point(n_samples=1)
        point_2 = self.space.random_point(n_samples=1)

        result = metric.squared_dist(point_1, point_2)

        self.assertAllClose(gs.shape(result), ())

    def test_parallel_transport_affine_invariant(self):
        """Test of SPDMetricAffine.parallel_transport method with power=1."""
        n_samples = self.n_samples
        gs.random.seed(1)
        point = self.space.random_point(n_samples)
        tan_a = self.space.random_tangent_vec(n_samples, point)
        tan_b = self.space.random_tangent_vec(n_samples, point)

        point = gs.cast(point, gs.float64)
        tan_a = gs.cast(tan_a, gs.float64)
        tan_b = gs.cast(tan_b, gs.float64)

        metric = self.metric_affine
        expected = metric.norm(tan_a, point)
        end_point = metric.exp(tan_b, point)

        transported = metric.parallel_transport(tan_a, tan_b, point)
        result = metric.norm(transported, end_point)

        self.assertAllClose(expected, result)

    def test_squared_dist_bureswasserstein(self):
        """Test of SPDMetricBuresWasserstein.squared_dist method."""
        point_a = gs.array([[5., 0., 0.], [0., 7., 2.], [0., 2., 8.]])
        point_b = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]])

        metric = self.metric_bureswasserstein
        result = metric.squared_dist(point_a, point_b)

        log = metric.log(point=point_b, base_point=point_a)
        expected = metric.squared_norm(vector=log, base_point=point_a)

        self.assertAllClose(result, expected)

    def test_squared_dist_bureswasserstein_vectorization(self):
        """Test of SPDMetricBuresWasserstein.squared_dist method."""
        point_a = self.space.random_point(2)
        point_b = gs.array([[9., 0., 0.], [0., 5., 0.], [0., 0., 1.]])

        point_a = gs.cast(point_a, gs.float64)
        point_b = gs.cast(point_b, gs.float64)

        metric = self.metric_bureswasserstein
        result = metric.squared_dist(point_a, point_b)

        log = metric.log(point=point_b, base_point=point_a)
        expected = metric.squared_norm(vector=log, base_point=point_a)

        self.assertAllClose(result, expected)

    def test_to_tangent_and_is_tangent(self):
        mat = gs.random.rand(3, 3)
        projection = self.space.to_tangent(mat)
        result = self.space.is_tangent(projection)
        self.assertTrue(result)
Ejemplo n.º 5
0
    def test_check_belongs_with_tol():
        spd = SPDMatrices(5)
        point = spd.random_point()

        geomstats.errors.check_belongs(point, spd)
Ejemplo n.º 6
0
class TestTangentPCA(geomstats.tests.TestCase):
    _multiprocess_can_split_ = True

    def setup_method(self):
        self.so3 = SpecialOrthogonal(n=3, point_type="vector")
        self.spd = SPDMatrices(3)
        self.spd_metric = SPDMetricAffine(3)

        self.n_samples = 10

        self.X = self.so3.random_uniform(n_samples=self.n_samples)
        self.metric = self.so3.bi_invariant_metric
        self.n_components = 2

    def test_tangent_pca_error(self):
        X = self.X
        tpca = TangentPCA(self.metric, n_components=self.n_components)
        tpca.fit(X)
        X_diff_size = gs.ones((self.n_samples, gs.shape(X)[1] + 1))
        with pytest.raises(ValueError):
            tpca.transform(X_diff_size)

    def test_tangent_pca(self):
        X = self.X
        tpca = TangentPCA(self.metric, n_components=gs.shape(X)[1])
        tpca.fit(X)
        self.assertEqual(tpca.n_features_, gs.shape(X)[1])

    def test_fit_mle(self):
        X = self.X
        tpca = TangentPCA(self.metric, n_components="mle")
        tpca.fit(X)
        self.assertEqual(tpca.n_features_, gs.shape(X)[1])

    def test_fit_to_target_explained_variance(self):
        X = self.spd.random_point(n_samples=5)
        target = 0.90
        tpca = TangentPCA(self.spd_metric, n_components=target)
        tpca.fit(X)
        result = gs.cumsum(tpca.explained_variance_ratio_)[-1] > target
        expected = True
        self.assertAllClose(result, expected)

    def test_fit_matrix(self):
        expected = 2
        X = self.spd.random_point(n_samples=5)
        tpca = TangentPCA(metric=self.spd_metric, n_components=expected)
        tpca.fit(X)
        result = tpca.n_components_
        self.assertAllClose(result, expected)

    def test_fit_transform_matrix(self):
        expected = 2
        X = self.spd.random_point(n_samples=5)
        tpca = TangentPCA(metric=self.spd_metric, n_components=expected)
        tangent_projected_data = tpca.fit_transform(X)
        result = tangent_projected_data.shape[-1]
        self.assertAllClose(result, expected)

    def test_fit_inverse_transform_matrix(self):
        X = self.spd.random_point(n_samples=5)
        tpca = TangentPCA(metric=self.spd_metric)
        tangent_projected_data = tpca.fit_transform(X)
        result = tpca.inverse_transform(tangent_projected_data)
        expected = X
        self.assertAllClose(result, expected, atol=1e-6)

    def test_fit_transform_vector(self):
        expected = 2
        tpca = TangentPCA(metric=self.metric, n_components=expected)
        tangent_projected_data = tpca.fit_transform(self.X)
        result = tangent_projected_data.shape[-1]
        self.assertAllClose(result, expected)

    def test_fit_inverse_transform_vector(self):
        tpca = TangentPCA(metric=self.metric)
        tangent_projected_data = tpca.fit_transform(self.X)
        result = tpca.inverse_transform(tangent_projected_data)
        expected = self.X
        self.assertAllClose(result, expected)

    def test_fit_fit_transform_matrix(self):
        X = self.spd.random_point(n_samples=5)
        tpca = TangentPCA(metric=self.spd_metric)
        expected = tpca.fit_transform(X)
        result = tpca.fit(X).transform(X)
        self.assertAllClose(result, expected)

    def test_fit_matrix_se(self):
        se_mat = SpecialEuclidean(n=3)
        X = se_mat.random_point(self.n_samples)
        estimator = ExponentialBarycenter(se_mat)
        estimator.fit(X)
        mean = estimator.estimate_
        tpca = TangentPCA(metric=se_mat)
        tangent_projected_data = tpca.fit_transform(X, base_point=mean)
        result = tpca.inverse_transform(tangent_projected_data)
        expected = X
        self.assertAllClose(result, expected)
Ejemplo n.º 7
0
class TestQuotientMetric(geomstats.tests.TestCase):
    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,
                                  ambient_metric=MatricesMetric(n, n))
        self.quotient_metric = QuotientMetric(self.bundle)

        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 test_belongs(self):
        point = self.base.random_point()
        result = self.bundle.belongs(point)
        self.assertTrue(result)

    def test_submersion(self):
        mat = self.bundle.total_space.random_point()
        point = self.bundle.submersion(mat)
        result = self.bundle.belongs(point)
        self.assertTrue(result)

    def test_lift_and_submersion(self):
        point = self.base.random_point()
        mat = self.bundle.lift(point)
        result = self.bundle.submersion(mat)
        self.assertAllClose(result, point)

    def test_tangent_submersion(self):
        mat = self.bundle.total_space.random_point()
        point = self.bundle.submersion(mat)
        vec = self.bundle.total_space.random_point()
        tangent_vec = self.bundle.tangent_submersion(vec, point)
        result = self.base.is_tangent(tangent_vec, point)
        self.assertTrue(result)

    def test_horizontal_projection(self):
        mat = self.bundle.total_space.random_point()
        vec = self.bundle.total_space.random_point()
        horizontal_vec = self.bundle.horizontal_projection(vec, mat)
        product = GeneralLinear.mul(horizontal_vec, GeneralLinear.inverse(mat))
        is_horizontal = GeneralLinear.is_symmetric(product)
        self.assertTrue(is_horizontal)

    def test_vertical_projection(self):
        mat = self.bundle.total_space.random_point()
        vec = self.bundle.total_space.random_point()
        vertical_vec = self.bundle.vertical_projection(vec, mat)

        result = self.bundle.tangent_submersion(vertical_vec, mat)
        expected = gs.zeros_like(result)
        self.assertAllClose(result, expected, atol=1e-5)

    def test_horizontal_lift_and_tangent_submersion(self):
        mat = self.bundle.total_space.random_point()
        tangent_vec = GeneralLinear.to_symmetric(
            self.bundle.total_space.random_point())
        horizontal = self.bundle.horizontal_lift(tangent_vec, mat)
        result = self.bundle.tangent_submersion(horizontal, mat)
        self.assertAllClose(result, tangent_vec)

    def test_is_horizontal(self):
        mat = self.bundle.total_space.random_point()
        tangent_vec = GeneralLinear.to_symmetric(
            self.bundle.total_space.random_point())
        horizontal = self.bundle.horizontal_lift(tangent_vec, mat)
        result = self.bundle.is_horizontal(horizontal, mat)
        self.assertTrue(result)

    def test_is_vertical(self):
        mat = self.bundle.total_space.random_point()
        tangent_vec = self.bundle.total_space.random_point()
        vertical = self.bundle.vertical_projection(tangent_vec, mat)
        result = self.bundle.is_vertical(vertical, mat)
        self.assertTrue(result)

    def test_align(self):
        point = self.bundle.total_space.random_point(2)
        aligned = self.bundle.align(point[0], point[1], tol=1e-10)
        result = self.bundle.is_horizontal(point[1] - aligned,
                                           point[1],
                                           atol=1e-5)
        self.assertTrue(result)

    def test_inner_product(self):
        mat = self.bundle.total_space.random_point()
        point = self.bundle.submersion(mat)
        tangent_vecs = GeneralLinear.to_symmetric(
            self.bundle.total_space.random_point(2)) / 10
        result = self.quotient_metric.inner_product(tangent_vecs[0],
                                                    tangent_vecs[1],
                                                    point=mat)
        expected = self.base_metric.inner_product(tangent_vecs[0],
                                                  tangent_vecs[1], point)
        self.assertAllClose(result, expected)

    def test_exp(self):
        mat = self.bundle.total_space.random_point()
        point = self.bundle.submersion(mat)
        tangent_vec = GeneralLinear.to_symmetric(
            self.bundle.total_space.random_point()) / 5

        result = self.quotient_metric.exp(tangent_vec, point)
        expected = self.base_metric.exp(tangent_vec, point)
        self.assertAllClose(result, expected)

    def test_log(self):
        mats = self.bundle.total_space.random_point(2)
        points = self.bundle.submersion(mats)

        result = self.quotient_metric.log(points[1], points[0], tol=1e-10)
        expected = self.base_metric.log(points[1], points[0])
        self.assertAllClose(result, expected, atol=3e-4)

    def test_squared_dist(self):
        mats = self.bundle.total_space.random_point(2)
        points = self.bundle.submersion(mats)

        result = self.quotient_metric.squared_dist(points[1],
                                                   points[0],
                                                   tol=1e-10)
        expected = self.base_metric.squared_dist(points[1], points[0])
        self.assertAllClose(result, expected, atol=1e-5)

    def test_integrability_tensor(self):
        mat = self.bundle.total_space.random_point()
        point = self.bundle.submersion(mat)
        tangent_vec = GeneralLinear.to_symmetric(
            self.bundle.total_space.random_point()) / 5

        self.assertRaises(
            NotImplementedError, lambda: self.bundle.integrability_tensor(
                tangent_vec, tangent_vec, point))
Ejemplo n.º 8
0
class TestVisualization(geomstats.tests.TestCase):
    def setup_method(self):
        self.n_samples = 10
        self.SO3_GROUP = SpecialOrthogonal(n=3, point_type="vector")
        self.SE3_GROUP = SpecialEuclidean(n=3, point_type="vector")
        self.S1 = Hypersphere(dim=1)
        self.S2 = Hypersphere(dim=2)
        self.H2 = Hyperbolic(dim=2)
        self.H2_half_plane = PoincareHalfSpace(dim=2)
        self.M32 = Matrices(m=3, n=2)
        self.S32 = PreShapeSpace(k_landmarks=3, m_ambient=2)
        self.KS = visualization.KendallSphere()
        self.M33 = Matrices(m=3, n=3)
        self.S33 = PreShapeSpace(k_landmarks=3, m_ambient=3)
        self.KD = visualization.KendallDisk()
        self.spd = SPDMatrices(n=2)

        plt.figure()

    @staticmethod
    def test_tutorial_matplotlib():
        visualization.tutorial_matplotlib()

    def test_plot_points_so3(self):
        points = self.SO3_GROUP.random_uniform(self.n_samples)
        visualization.plot(points, space="SO3_GROUP")

    def test_plot_points_se3(self):
        points = self.SE3_GROUP.random_point(self.n_samples)
        visualization.plot(points, space="SE3_GROUP")

    def test_draw_pre_shape_2d(self):
        self.KS.draw()

    def test_draw_points_pre_shape_2d(self):
        points = self.S32.random_point(self.n_samples)
        visualization.plot(points, space="S32")
        points = self.M32.random_point(self.n_samples)
        visualization.plot(points, space="M32")
        self.KS.clear_points()

    def test_draw_curve_pre_shape_2d(self):
        self.KS.draw()
        base_point = self.S32.random_point()
        vec = self.S32.random_point()
        tangent_vec = self.S32.to_tangent(vec, base_point)
        times = gs.linspace(0.0, 1.0, 1000)
        speeds = gs.array([-t * tangent_vec for t in times])
        points = self.S32.ambient_metric.exp(speeds, base_point)
        self.KS.add_points(points)
        self.KS.draw_curve()
        self.KS.clear_points()

    def test_draw_vector_pre_shape_2d(self):
        self.KS.draw()
        base_point = self.S32.random_point()
        vec = self.S32.random_point()
        tangent_vec = self.S32.to_tangent(vec, base_point)
        self.KS.draw_vector(tangent_vec, base_point)

    def test_convert_to_spherical_coordinates_pre_shape_2d(self):
        points = self.S32.random_point(self.n_samples)
        coords = self.KS.convert_to_spherical_coordinates(points)
        x = coords[:, 0]
        y = coords[:, 1]
        z = coords[:, 2]
        result = x**2 + y**2 + z**2
        expected = 0.25 * gs.ones(self.n_samples)
        self.assertAllClose(result, expected)

    def test_rotation_pre_shape_2d(self):
        theta = gs.random.rand(1)[0]
        phi = gs.random.rand(1)[0]
        rot = self.KS.rotation(theta, phi)
        result = _SpecialOrthogonalMatrices(3).belongs(rot)
        expected = True
        self.assertAllClose(result, expected)

    def test_draw_pre_shape_3d(self):
        self.KD.draw()

    def test_draw_points_pre_shape_3d(self):
        points = self.S33.random_point(self.n_samples)
        visualization.plot(points, space="S33")
        points = self.M33.random_point(self.n_samples)
        visualization.plot(points, space="M33")
        self.KD.clear_points()

    def test_draw_curve_pre_shape_3d(self):
        self.KD.draw()
        base_point = self.S33.random_point()
        vec = self.S33.random_point()
        tangent_vec = self.S33.to_tangent(vec, base_point)
        tangent_vec = 0.5 * tangent_vec / self.S33.ambient_metric.norm(
            tangent_vec)
        times = gs.linspace(0.0, 1.0, 1000)
        speeds = gs.array([-t * tangent_vec for t in times])
        points = self.S33.ambient_metric.exp(speeds, base_point)
        self.KD.add_points(points)
        self.KD.draw_curve()
        self.KD.clear_points()

    def test_draw_vector_pre_shape_3d(self):
        self.KS.draw()
        base_point = self.S32.random_point()
        vec = self.S32.random_point()
        tangent_vec = self.S32.to_tangent(vec, base_point)
        self.KS.draw_vector(tangent_vec, base_point)

    def test_convert_to_planar_coordinates_pre_shape_3d(self):
        points = self.S33.random_point(self.n_samples)
        coords = self.KD.convert_to_planar_coordinates(points)
        x = coords[:, 0]
        y = coords[:, 1]
        radius = x**2 + y**2
        result = [r <= 1.0 for r in radius]
        self.assertTrue(gs.all(result))

    @geomstats.tests.np_autograd_and_torch_only
    def test_plot_points_s1(self):
        points = self.S1.random_uniform(self.n_samples)
        visualization.plot(points, space="S1")

    def test_plot_points_s2(self):
        points = self.S2.random_uniform(self.n_samples)
        visualization.plot(points, space="S2")

    def test_plot_points_h2_poincare_disk(self):
        points = self.H2.random_point(self.n_samples)
        visualization.plot(points, space="H2_poincare_disk")

    def test_plot_points_h2_poincare_half_plane_ext(self):
        points = self.H2.random_point(self.n_samples)
        visualization.plot(points,
                           space="H2_poincare_half_plane",
                           point_type="extrinsic")

    def test_plot_points_h2_poincare_half_plane_none(self):
        points = self.H2_half_plane.random_point(self.n_samples)
        visualization.plot(points, space="H2_poincare_half_plane")

    def test_plot_points_h2_poincare_half_plane_hs(self):
        points = self.H2_half_plane.random_point(self.n_samples)
        visualization.plot(points,
                           space="H2_poincare_half_plane",
                           point_type="half_space")

    def test_plot_points_h2_klein_disk(self):
        points = self.H2.random_point(self.n_samples)
        visualization.plot(points, space="H2_klein_disk")

    @staticmethod
    def test_plot_points_se2():
        points = SpecialEuclidean(n=2, point_type="vector").random_point(4)
        visu = visualization.SpecialEuclidean2(points, point_type="vector")
        ax = visu.set_ax()
        visu.draw_points(ax)

    def test_plot_points_spd2(self):
        one_point = self.spd.random_point()
        visualization.plot(one_point, space="SPD2")

        points = self.spd.random_point(4)
        visualization.plot(points, space="SPD2")

    def test_compute_coordinates_spd2(self):
        point = gs.eye(2)
        ellipsis = visualization.Ellipses(n_sampling_points=4)
        x, y = ellipsis.compute_coordinates(point)
        self.assertAllClose(x, gs.array([1, 0, -1, 0, 1]))
        self.assertAllClose(y, gs.array([0, 1, 0, -1, 0]))

    @staticmethod
    def teardown_method():
        plt.close()