Ejemplo n.º 1
0
    def test_spherical_to_extrinsic_and_inverse(self):
        dim = 2
        n_samples = 5
        sphere = Hypersphere(dim)
        points = gs.random.rand(n_samples, 2) * gs.pi * gs.array([1., 2.
                                                                  ])[None, :]
        extrinsic = sphere.spherical_to_extrinsic(points)
        result = sphere.extrinsic_to_spherical(extrinsic)
        self.assertAllClose(result, points)

        points_extrinsic = sphere.random_uniform(n_samples)
        spherical = sphere.extrinsic_to_spherical(points_extrinsic)
        result = sphere.spherical_to_extrinsic(spherical)
        self.assertAllClose(result, points_extrinsic)
Ejemplo n.º 2
0
    def test_exp_connection_metric(self, dim, tangent_vec, base_point):
        sphere = Hypersphere(dim)
        connection = Connection(dim)
        point_ext = sphere.spherical_to_extrinsic(base_point)
        vector_ext = sphere.tangent_spherical_to_extrinsic(
            tangent_vec, base_point)
        connection.christoffels = sphere.metric.christoffels
        expected = sphere.metric.exp(vector_ext, point_ext)
        result_spherical = connection.exp(tangent_vec,
                                          base_point,
                                          n_steps=50,
                                          step="rk4")
        result = sphere.spherical_to_extrinsic(result_spherical)

        self.assertAllClose(result, expected)
Ejemplo n.º 3
0
    def test_log_connection_metric(self, dim, point, base_point, atol):
        sphere = Hypersphere(dim)
        connection = Connection(dim)
        connection.christoffels = sphere.metric.christoffels
        vector = connection.log(point=point,
                                base_point=base_point,
                                n_steps=75,
                                step="rk4",
                                tol=1e-10)
        result = sphere.tangent_spherical_to_extrinsic(vector, base_point)
        p_ext = sphere.spherical_to_extrinsic(base_point)
        q_ext = sphere.spherical_to_extrinsic(point)
        expected = sphere.metric.log(base_point=p_ext, point=q_ext)

        self.assertAllClose(result, expected, atol)
Ejemplo n.º 4
0
def load_cities():
    """Load data from data/cities/cities.json.

    Returns
    -------
    data : array-like, shape=[50, 2]
        Array with each row representing one sample,
        i. e. latitude and longitude of a city.
        Angles are in radians.
    name : list
        List of city names.
    """
    with open(CITIES_PATH, encoding='utf-8') as json_file:
        data_file = json.load(json_file)

        names = [row['city'] for row in data_file]
        data = list(
            map(
                lambda row:
                [row[col_name] / 180 * gs.pi for col_name in ['lat', 'lng']],
                data_file,
            ))

    data = gs.array(data)

    colat = gs.pi / 2 - data[:, 0]
    colat = gs.expand_dims(colat, axis=1)
    lng = gs.expand_dims(data[:, 1] + gs.pi, axis=1)

    data = gs.concatenate([colat, lng], axis=1)
    sphere = Hypersphere(dim=2)
    data = sphere.spherical_to_extrinsic(data)
    return data, names
Ejemplo n.º 5
0
 def test_spherical_to_extrinsic_vectorization(self):
     dim = 2
     sphere = Hypersphere(dim)
     points_spherical = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]])
     result = sphere.spherical_to_extrinsic(points_spherical)
     expected = gs.array([[1., 0., 0.],
                          [gs.sqrt(2) / 4,
                           gs.sqrt(2) / 4,
                           gs.sqrt(3) / 2]])
     self.assertAllClose(result, expected)
Ejemplo n.º 6
0
    def test_spherical_to_extrinsic(self):
        """
        Check vectorization of conversion from spherical
        to extrinsic coordinates on the 2-sphere.
        """
        dim = 2
        sphere = Hypersphere(dim)

        points_spherical = gs.array([gs.pi / 2, 0])
        result = sphere.spherical_to_extrinsic(points_spherical)
        expected = gs.array([1.0, 0.0, 0.0])
        self.assertAllClose(result, expected)
Ejemplo n.º 7
0
class TestConnection(geomstats.tests.TestCase):
    def setup_method(self):
        warnings.simplefilter("ignore", category=UserWarning)
        gs.random.seed(0)
        self.dim = 4
        self.euc_metric = EuclideanMetric(dim=self.dim)

        self.connection = Connection(dim=2)
        self.hypersphere = Hypersphere(dim=2)

    def test_metric_matrix(self):
        base_point = gs.array([0.0, 1.0, 0.0, 0.0])

        result = self.euc_metric.metric_matrix(base_point)
        expected = gs.eye(self.dim)

        self.assertAllClose(result, expected)

    def test_parallel_transport(self):
        n_samples = 2
        base_point = self.hypersphere.random_uniform(n_samples)
        tan_vec_a = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3),
                                                base_point)
        tan_vec_b = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3),
                                                base_point)
        expected = self.hypersphere.metric.parallel_transport(
            tan_vec_a, base_point, tan_vec_b)
        expected_point = self.hypersphere.metric.exp(tan_vec_b, base_point)
        base_point = gs.cast(base_point, gs.float64)
        base_point, tan_vec_a, tan_vec_b = gs.convert_to_wider_dtype(
            [base_point, tan_vec_a, tan_vec_b])
        for step, alpha in zip(["pole", "schild"], [1, 2]):
            min_n = 1 if step == "pole" else 50
            tol = 1e-5 if step == "pole" else 1e-2
            for n_rungs in [min_n, 11]:
                ladder = self.hypersphere.metric.ladder_parallel_transport(
                    tan_vec_a,
                    base_point,
                    tan_vec_b,
                    n_rungs=n_rungs,
                    scheme=step,
                    alpha=alpha,
                )
                result = ladder["transported_tangent_vec"]
                result_point = ladder["end_point"]
                self.assertAllClose(result, expected, rtol=tol, atol=tol)
                self.assertAllClose(result_point, expected_point)

    def test_parallel_transport_trajectory(self):
        n_samples = 2
        for step in ["pole", "schild"]:
            n_steps = 1 if step == "pole" else 50
            tol = 1e-6 if step == "pole" else 1e-2
            base_point = self.hypersphere.random_uniform(n_samples)
            tan_vec_a = self.hypersphere.to_tangent(
                gs.random.rand(n_samples, 3), base_point)
            tan_vec_b = self.hypersphere.to_tangent(
                gs.random.rand(n_samples, 3), base_point)
            expected = self.hypersphere.metric.parallel_transport(
                tan_vec_a, base_point, tan_vec_b)
            expected_point = self.hypersphere.metric.exp(tan_vec_b, base_point)
            ladder = self.hypersphere.metric.ladder_parallel_transport(
                tan_vec_a,
                base_point,
                tan_vec_b,
                n_rungs=n_steps,
                scheme=step,
                return_geodesics=True,
            )
            result = ladder["transported_tangent_vec"]
            result_point = ladder["end_point"]

            self.assertAllClose(result, expected, rtol=tol, atol=tol)
            self.assertAllClose(result_point, expected_point)

    def test_ladder_alpha(self):
        n_samples = 2
        base_point = self.hypersphere.random_uniform(n_samples)
        tan_vec_a = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3),
                                                base_point)
        tan_vec_b = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3),
                                                base_point)

        with pytest.raises(ValueError):
            self.hypersphere.metric.ladder_parallel_transport(
                tan_vec_a,
                base_point,
                tan_vec_b,
                n_rungs=1,
                scheme="pole",
                alpha=0.5,
                return_geodesics=False,
            )

    def test_exp_connection_metric(self):
        point = gs.array([gs.pi / 2, 0])
        vector = gs.array([0.25, 0.5])
        point_ext = self.hypersphere.spherical_to_extrinsic(point)
        vector_ext = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, point)
        self.connection.christoffels = self.hypersphere.metric.christoffels
        expected = self.hypersphere.metric.exp(vector_ext, point_ext)
        result_spherical = self.connection.exp(vector,
                                               point,
                                               n_steps=50,
                                               step="rk4")
        result = self.hypersphere.spherical_to_extrinsic(result_spherical)

        self.assertAllClose(result, expected)

    def test_exp_connection_metric_vectorization(self):
        point = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]])
        vector = gs.array([[0.25, 0.5], [0.30, 0.2]])
        point_ext = self.hypersphere.spherical_to_extrinsic(point)
        vector_ext = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, point)
        self.connection.christoffels = self.hypersphere.metric.christoffels
        expected = self.hypersphere.metric.exp(vector_ext, point_ext)
        result_spherical = self.connection.exp(vector,
                                               point,
                                               n_steps=50,
                                               step="rk4")
        result = self.hypersphere.spherical_to_extrinsic(result_spherical)

        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_log_connection_metric(self):
        base_point = gs.array([gs.pi / 3, gs.pi / 4])
        point = gs.array([1.0, gs.pi / 2])
        self.connection.christoffels = self.hypersphere.metric.christoffels
        vector = self.connection.log(point=point,
                                     base_point=base_point,
                                     n_steps=75,
                                     step="rk4",
                                     tol=1e-10)
        result = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, base_point)
        p_ext = self.hypersphere.spherical_to_extrinsic(base_point)
        q_ext = self.hypersphere.spherical_to_extrinsic(point)
        expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext)

        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_log_connection_metric_vectorization(self):
        base_point = gs.array([[gs.pi / 3, gs.pi / 4], [gs.pi / 2, gs.pi / 4]])
        point = gs.array([[1.0, gs.pi / 2], [gs.pi / 6, gs.pi / 3]])
        self.connection.christoffels = self.hypersphere.metric.christoffels
        vector = self.connection.log(point=point,
                                     base_point=base_point,
                                     n_steps=75,
                                     step="rk4",
                                     tol=1e-10)
        result = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, base_point)
        p_ext = self.hypersphere.spherical_to_extrinsic(base_point)
        q_ext = self.hypersphere.spherical_to_extrinsic(point)
        expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext)

        self.assertAllClose(result, expected, atol=1e-6)

    def test_geodesic_and_coincides_exp_hypersphere(self):
        n_geodesic_points = 10
        initial_point = self.hypersphere.random_uniform(2)
        vector = gs.array([[2.0, 0.0, -1.0]] * 2)
        initial_tangent_vec = self.hypersphere.to_tangent(
            vector=vector, base_point=initial_point)
        geodesic = self.hypersphere.metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        t = gs.linspace(start=0.0, stop=1.0, num=n_geodesic_points)
        points = geodesic(t)
        result = points[:, -1]
        expected = self.hypersphere.metric.exp(vector, initial_point)
        self.assertAllClose(expected, result)

        initial_point = initial_point[0]
        initial_tangent_vec = initial_tangent_vec[0]
        geodesic = self.hypersphere.metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        points = geodesic(t)
        result = points[-1]
        expected = self.hypersphere.metric.exp(initial_tangent_vec,
                                               initial_point)
        self.assertAllClose(expected, result)

    def test_geodesic_and_coincides_exp_son(self):
        n_geodesic_points = 10
        space = SpecialOrthogonal(n=4)
        initial_point = space.random_uniform(2)
        vector = gs.random.rand(2, 4, 4)
        initial_tangent_vec = space.to_tangent(vector=vector,
                                               base_point=initial_point)
        geodesic = space.bi_invariant_metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        t = gs.linspace(start=0.0, stop=1.0, num=n_geodesic_points)
        points = geodesic(t)
        result = points[:, -1]
        expected = space.bi_invariant_metric.exp(initial_tangent_vec,
                                                 initial_point)
        self.assertAllClose(result, expected)

        initial_point = initial_point[0]
        initial_tangent_vec = initial_tangent_vec[0]
        geodesic = space.bi_invariant_metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        points = geodesic(t)
        result = points[-1]
        expected = space.bi_invariant_metric.exp(initial_tangent_vec,
                                                 initial_point)
        self.assertAllClose(expected, result)

    def test_geodesic_invalid_initial_conditions(self):
        space = SpecialOrthogonal(n=4)
        initial_point = space.random_uniform(2)
        vector = gs.random.rand(2, 4, 4)
        initial_tangent_vec = space.to_tangent(vector=vector,
                                               base_point=initial_point)
        end_point = space.random_uniform(2)
        with pytest.raises(RuntimeError):
            space.bi_invariant_metric.geodesic(
                initial_point=initial_point,
                initial_tangent_vec=initial_tangent_vec,
                end_point=end_point,
            )

    def test_geodesic_vectorization(self):
        space = Hypersphere(2)
        metric = space.metric
        initial_point = space.random_uniform(2)
        vector = gs.random.rand(2, 3)
        initial_tangent_vec = space.to_tangent(vector=vector,
                                               base_point=initial_point)
        end_point = space.random_uniform(2)
        time = gs.linspace(0, 1, 10)

        geo = metric.geodesic(initial_point, initial_tangent_vec)
        path = geo(time)
        result = path.shape
        expected = (2, 10, 3)
        self.assertAllClose(result, expected)

        geo = metric.geodesic(initial_point, end_point=end_point)
        path = geo(time)
        result = path.shape
        expected = (2, 10, 3)
        self.assertAllClose(result, expected)

        geo = metric.geodesic(initial_point, end_point=end_point[0])
        path = geo(time)
        result = path.shape
        expected = (2, 10, 3)
        self.assertAllClose(result, expected)

        initial_tangent_vec = space.to_tangent(vector=vector,
                                               base_point=initial_point[0])
        geo = metric.geodesic(initial_point[0], initial_tangent_vec)
        path = geo(time)
        result = path.shape
        expected = (2, 10, 3)
        self.assertAllClose(result, expected)
Ejemplo n.º 8
0
class TestConnection(geomstats.tests.TestCase):
    def setUp(self):
        warnings.simplefilter('ignore', category=UserWarning)

        self.dim = 4
        self.euc_metric = EuclideanMetric(dim=self.dim)

        self.connection = Connection(dim=2)
        self.hypersphere = Hypersphere(dim=2)

    def test_metric_matrix(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.metric_matrix(base_point)
        expected = gs.eye(self.dim)

        self.assertAllClose(result, expected)

    def test_cometric_matrix(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.inner_product_inverse_matrix(base_point)
        expected = gs.eye(self.dim)

        self.assertAllClose(result, expected)

    @geomstats.tests.np_only
    def test_metric_derivative(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.inner_product_derivative_matrix(base_point)
        expected = gs.zeros((self.dim, ) * 3)

        self.assertAllClose(result, expected)

    @geomstats.tests.np_only
    def test_christoffels(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.christoffels(base_point)
        expected = gs.zeros((self.dim, ) * 3)

        self.assertAllClose(result, expected)

    def test_parallel_transport(self):
        n_samples = 2
        base_point = self.hypersphere.random_uniform(n_samples)
        tan_vec_a = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3),
                                                base_point)
        tan_vec_b = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3),
                                                base_point)
        expected = self.hypersphere.metric.parallel_transport(
            tan_vec_a, tan_vec_b, base_point)
        expected_point = self.hypersphere.metric.exp(tan_vec_b, base_point)
        base_point = gs.cast(base_point, gs.float64)
        base_point, tan_vec_a, tan_vec_b = gs.convert_to_wider_dtype(
            [base_point, tan_vec_a, tan_vec_b])
        for step, alpha in zip(['pole', 'schild'], [1, 2]):
            min_n = 1 if step == 'pole' else 50
            tol = 1e-5 if step == 'pole' else 1e-2
            for n_rungs in [min_n, 11]:
                ladder = self.hypersphere.metric.ladder_parallel_transport(
                    tan_vec_a,
                    tan_vec_b,
                    base_point,
                    scheme=step,
                    n_rungs=n_rungs,
                    alpha=alpha)
                result = ladder['transported_tangent_vec']
                result_point = ladder['end_point']
                self.assertAllClose(result, expected, rtol=tol, atol=tol)
                self.assertAllClose(result_point, expected_point)

    def test_parallel_transport_trajectory(self):
        n_samples = 2
        for step in ['pole', 'schild']:
            n_steps = 1 if step == 'pole' else 50
            tol = 1e-6 if step == 'pole' else 1e-2
            base_point = self.hypersphere.random_uniform(n_samples)
            tan_vec_a = self.hypersphere.to_tangent(
                gs.random.rand(n_samples, 3), base_point)
            tan_vec_b = self.hypersphere.to_tangent(
                gs.random.rand(n_samples, 3), base_point)
            expected = self.hypersphere.metric.parallel_transport(
                tan_vec_a, tan_vec_b, base_point)
            expected_point = self.hypersphere.metric.exp(tan_vec_b, base_point)
            ladder = self.hypersphere.metric.ladder_parallel_transport(
                tan_vec_a,
                tan_vec_b,
                base_point,
                return_geodesics=True,
                scheme=step,
                n_rungs=n_steps)
            result = ladder['transported_tangent_vec']
            result_point = ladder['end_point']

            self.assertAllClose(result, expected, rtol=tol, atol=tol)
            self.assertAllClose(result_point, expected_point)

    def test_ladder_alpha(self):
        n_samples = 2
        base_point = self.hypersphere.random_uniform(n_samples)
        tan_vec_a = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3),
                                                base_point)
        tan_vec_b = self.hypersphere.to_tangent(gs.random.rand(n_samples, 3),
                                                base_point)
        self.assertRaises(
            ValueError, lambda: self.hypersphere.metric.
            ladder_parallel_transport(tan_vec_a,
                                      tan_vec_b,
                                      base_point,
                                      return_geodesics=False,
                                      scheme='pole',
                                      n_rungs=1,
                                      alpha=0.5))

    def test_exp_connection_metric(self):
        point = gs.array([gs.pi / 2, 0])
        vector = gs.array([0.25, 0.5])
        point_ext = self.hypersphere.spherical_to_extrinsic(point)
        vector_ext = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, point)
        self.connection.christoffels = self.hypersphere.metric.christoffels
        expected = self.hypersphere.metric.exp(vector_ext, point_ext)
        result_spherical = self.connection.exp(vector,
                                               point,
                                               n_steps=50,
                                               step='rk4')
        result = self.hypersphere.spherical_to_extrinsic(result_spherical)

        self.assertAllClose(result, expected, rtol=1e-6)

    def test_exp_connection_metric_vectorization(self):
        point = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]])
        vector = gs.array([[0.25, 0.5], [0.30, 0.2]])
        point_ext = self.hypersphere.spherical_to_extrinsic(point)
        vector_ext = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, point)
        self.connection.christoffels = self.hypersphere.metric.christoffels
        expected = self.hypersphere.metric.exp(vector_ext, point_ext)
        result_spherical = self.connection.exp(vector,
                                               point,
                                               n_steps=50,
                                               step='rk4')
        result = self.hypersphere.spherical_to_extrinsic(result_spherical)

        self.assertAllClose(result, expected, rtol=1e-6)

    def test_log_connection_metric(self):
        base_point = gs.array([gs.pi / 3, gs.pi / 4])
        point = gs.array([1.0, gs.pi / 2])
        self.connection.christoffels = self.hypersphere.metric.christoffels
        vector = self.connection.log(point=point,
                                     base_point=base_point,
                                     n_steps=75,
                                     step='rk',
                                     tol=1e-10)
        result = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, base_point)
        p_ext = self.hypersphere.spherical_to_extrinsic(base_point)
        q_ext = self.hypersphere.spherical_to_extrinsic(point)
        expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext)

        self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5)

    def test_log_connection_metric_vectorization(self):
        base_point = gs.array([[gs.pi / 3, gs.pi / 4], [gs.pi / 2, gs.pi / 4]])
        point = gs.array([[1.0, gs.pi / 2], [gs.pi / 6, gs.pi / 3]])
        self.connection.christoffels = self.hypersphere.metric.christoffels
        vector = self.connection.log(point=point,
                                     base_point=base_point,
                                     n_steps=75,
                                     step='rk',
                                     tol=1e-10)
        result = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, base_point)
        p_ext = self.hypersphere.spherical_to_extrinsic(base_point)
        q_ext = self.hypersphere.spherical_to_extrinsic(point)
        expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext)

        self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5)

    def test_geodesic_and_coincides_exp_hypersphere(self):
        n_geodesic_points = 10
        initial_point = self.hypersphere.random_uniform(2)
        vector = gs.array([[2., 0., -1.]] * 2)
        initial_tangent_vec = self.hypersphere.to_tangent(
            vector=vector, base_point=initial_point)
        geodesic = self.hypersphere.metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        t = gs.linspace(start=0., stop=1., num=n_geodesic_points)
        points = geodesic(t)
        result = points[-1]
        expected = self.hypersphere.metric.exp(vector, initial_point)
        self.assertAllClose(expected, result)

        initial_point = initial_point[0]
        initial_tangent_vec = initial_tangent_vec[0]
        geodesic = self.hypersphere.metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        points = geodesic(t)
        result = points[-1]
        expected = self.hypersphere.metric.exp(initial_tangent_vec,
                                               initial_point)
        self.assertAllClose(expected, result)

    def test_geodesic_and_coincides_exp_son(self):
        n_geodesic_points = 10
        space = SpecialOrthogonal(n=4)
        initial_point = space.random_uniform(2)
        vector = gs.random.rand(2, 4, 4)
        initial_tangent_vec = space.to_tangent(vector=vector,
                                               base_point=initial_point)
        geodesic = space.bi_invariant_metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        t = gs.linspace(start=0., stop=1., num=n_geodesic_points)
        points = geodesic(t)
        result = points[-1]
        expected = space.bi_invariant_metric.exp(initial_tangent_vec,
                                                 initial_point)
        self.assertAllClose(result, expected)

        initial_point = initial_point[0]
        initial_tangent_vec = initial_tangent_vec[0]
        geodesic = space.bi_invariant_metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        points = geodesic(t)
        result = points[-1]
        expected = space.bi_invariant_metric.exp(initial_tangent_vec,
                                                 initial_point)
        self.assertAllClose(expected, result)

    def test_geodesic_invalid_initial_conditions(self):
        space = SpecialOrthogonal(n=4)
        initial_point = space.random_uniform(2)
        vector = gs.random.rand(2, 4, 4)
        initial_tangent_vec = space.to_tangent(vector=vector,
                                               base_point=initial_point)
        end_point = space.random_uniform(2)
        self.assertRaises(
            RuntimeError, lambda: space.bi_invariant_metric.geodesic(
                initial_point=initial_point,
                initial_tangent_vec=initial_tangent_vec,
                end_point=end_point))
Ejemplo n.º 9
0
class TestPullbackMetric(geomstats.tests.TestCase):
    def setUp(self):
        warnings.simplefilter("ignore", category=UserWarning)
        gs.random.seed(0)
        self.dim = 2
        self.sphere = Hypersphere(dim=self.dim)
        self.sphere_metric = self.sphere.metric

        def _sphere_immersion(spherical_coords):
            theta = spherical_coords[..., 0]
            phi = spherical_coords[..., 1]
            return gs.array([
                gs.cos(phi) * gs.sin(theta),
                gs.sin(phi) * gs.sin(theta),
                gs.cos(theta),
            ])

        self.immersion = _sphere_immersion
        self.pullback_metric = PullbackMetric(dim=self.dim,
                                              embedding_dim=self.dim + 1,
                                              immersion=self.immersion)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_immersion(self):
        expected = gs.array([0.0, 0.0, 1.0])
        result = self.immersion(gs.array([0.0, 0.0]))
        self.assertAllClose(result, expected)

        expected = gs.array([0.0, 0.0, -1.0])
        result = self.immersion(gs.array([gs.pi, 0.0]))
        self.assertAllClose(result, expected)

        expected = gs.array([-1.0, 0.0, 0.0])
        result = self.immersion(gs.array([gs.pi / 2.0, gs.pi]))
        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_immersion_and_spherical_to_extrinsic(self):
        point = gs.array([0.0, 0.0])
        expected = self.immersion(point)
        result = self.sphere.spherical_to_extrinsic(point)
        self.assertAllClose(result, expected)

        point = gs.array([0.2, 0.1])
        expected = self.immersion(point)
        result = self.sphere.spherical_to_extrinsic(point)
        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_jacobian_immersion(self):
        def _expected_jacobian_immersion(point):
            theta = point[..., 0]
            phi = point[..., 1]
            jacobian = gs.array([
                [gs.cos(phi) * gs.cos(theta), -gs.sin(phi) * gs.sin(theta)],
                [gs.sin(phi) * gs.cos(theta),
                 gs.cos(phi) * gs.sin(theta)],
                [-gs.sin(theta), 0.0],
            ])
            return jacobian

        pole = gs.array([0.0, 0.0])
        result = self.pullback_metric.jacobian_immersion(pole)
        expected = _expected_jacobian_immersion(pole)
        self.assertAllClose(result, expected)

        base_point = gs.array([0.22, 0.1])
        result = self.pullback_metric.jacobian_immersion(base_point)
        expected = _expected_jacobian_immersion(base_point)
        self.assertAllClose(result, expected)

        base_point = gs.array([0.1, 0.88])
        result = self.pullback_metric.jacobian_immersion(base_point)
        expected = _expected_jacobian_immersion(base_point)
        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_tangent_immersion(self):
        point = gs.array([gs.pi / 2.0, gs.pi / 2.0])

        tangent_vec = gs.array([1.0, 0.0])
        result = self.pullback_metric.tangent_immersion(tangent_vec, point)
        expected = gs.array([0.0, 0.0, -1.0])
        self.assertAllClose(result, expected)

        tangent_vec = gs.array([0.0, 1.0])
        result = self.pullback_metric.tangent_immersion(tangent_vec, point)
        expected = gs.array([-1.0, 0.0, 0.0])
        self.assertAllClose(result, expected)

        point = gs.array([gs.pi / 2.0, 0.0])

        tangent_vec = gs.array([1.0, 0.0])
        result = self.pullback_metric.tangent_immersion(tangent_vec, point)
        expected = gs.array([0.0, 0.0, -1.0])
        self.assertAllClose(result, expected)

        tangent_vec = gs.array([0.0, 1.0])
        result = self.pullback_metric.tangent_immersion(tangent_vec, point)
        expected = gs.array([0.0, 1.0, 0.0])
        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_metric_matrix(self):
        def _expected_metric_matrix(point):
            theta = point[..., 0]
            mat = gs.array([[1.0, 0.0], [0.0, gs.sin(theta)**2]])
            return mat

        base_point = gs.array([0.0, 0.0])
        result = self.pullback_metric.metric_matrix(base_point)
        expected = _expected_metric_matrix(base_point)
        self.assertAllClose(result, expected)

        base_point = gs.array([1.0, 1.0])
        result = self.pullback_metric.metric_matrix(base_point)
        expected = _expected_metric_matrix(base_point)
        self.assertAllClose(result, expected)

        base_point = gs.array([0.3, 0.8])
        result = self.pullback_metric.metric_matrix(base_point)
        expected = _expected_metric_matrix(base_point)
        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_inverse_metric_matrix(self):
        def _expected_inverse_metric_matrix(point):
            theta = point[..., 0]
            mat = gs.array([[1.0, 0.0], [0.0, gs.sin(theta)**(-2)]])
            return mat

        base_point = gs.array([0.6, -1.0])
        result = self.pullback_metric.metric_inverse_matrix(base_point)
        expected = _expected_inverse_metric_matrix(base_point)
        self.assertAllClose(result, expected)

        base_point = gs.array([0.8, -0.8])
        result = self.pullback_metric.metric_inverse_matrix(base_point)
        expected = _expected_inverse_metric_matrix(base_point)
        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_inner_product_and_sphere_inner_product(self):
        """Test consistency between sphere's inner-products.

        The inner-product of the class Hypersphere is
        defined in terms of extrinsic coordinates.

        The inner-product of pullback_metric is defined in terms
        of the spherical coordinates.
        """
        tangent_vec_a = gs.array([0.0, 1.0])
        tangent_vec_b = gs.array([0.0, 1.0])
        base_point = gs.array([gs.pi / 2.0, 0.0])
        immersed_base_point = self.immersion(base_point)
        jac_immersion = self.pullback_metric.jacobian_immersion(base_point)
        immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a)
        immersed_tangent_vec_b = gs.matmul(jac_immersion, tangent_vec_b)

        result = self.pullback_metric.inner_product(tangent_vec_a,
                                                    tangent_vec_b,
                                                    base_point=base_point)
        expected = self.sphere_metric.inner_product(
            immersed_tangent_vec_a,
            immersed_tangent_vec_b,
            base_point=immersed_base_point,
        )
        self.assertAllClose(result, expected)

        tangent_vec_a = gs.array([0.4, 1.0])
        tangent_vec_b = gs.array([0.2, 0.6])
        base_point = gs.array([gs.pi / 2.0, 0.1])
        immersed_base_point = self.immersion(base_point)
        jac_immersion = self.pullback_metric.jacobian_immersion(base_point)
        immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a)
        immersed_tangent_vec_b = gs.matmul(jac_immersion, tangent_vec_b)

        result = self.pullback_metric.inner_product(tangent_vec_a,
                                                    tangent_vec_b,
                                                    base_point=base_point)
        expected = self.sphere_metric.inner_product(
            immersed_tangent_vec_a,
            immersed_tangent_vec_b,
            base_point=immersed_base_point,
        )
        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_and_tf_only
    def test_christoffels_and_sphere_christoffels(self):
        """Test consistency between sphere's christoffels.

        The christoffels of the class Hypersphere are
        defined in terms of spherical coordinates.

        The christoffels of pullback_metric are also defined
        in terms of the spherical coordinates.
        """
        base_point = gs.array([0.1, 0.2])
        result = self.pullback_metric.christoffels(base_point=base_point)
        expected = self.sphere_metric.christoffels(point=base_point)
        self.assertAllClose(result, expected)

        base_point = gs.array([0.7, 0.233])
        result = self.pullback_metric.christoffels(base_point=base_point)
        expected = self.sphere_metric.christoffels(point=base_point)
        self.assertAllClose(result, expected)

    @geomstats.tests.autograd_tf_and_torch_only
    def test_exp_and_sphere_exp(self):
        """Test consistency between sphere's Riemannian exp.

        The exp map of the class Hypersphere is
        defined in terms of extrinsic coordinates.

        The exp map of pullback_metric is defined
        in terms of the spherical coordinates.
        """
        base_point = gs.array([gs.pi / 2.0, 0.0])
        tangent_vec_a = gs.array([0.0, 1.0])
        immersed_base_point = self.immersion(base_point)
        jac_immersion = self.pullback_metric.jacobian_immersion(base_point)
        immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a)
        result = self.pullback_metric.exp(tangent_vec_a, base_point=base_point)
        result = self.sphere.spherical_to_extrinsic(result)
        expected = self.sphere.metric.exp(immersed_tangent_vec_a,
                                          base_point=immersed_base_point)
        self.assertAllClose(result, expected)

        base_point = gs.array([gs.pi / 2.0, 0.1])
        tangent_vec_a = gs.array([0.4, 1.0])
        immersed_base_point = self.immersion(base_point)
        jac_immersion = self.pullback_metric.jacobian_immersion(base_point)
        immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a)
        result = self.pullback_metric.exp(tangent_vec_a, base_point=base_point)
        result = self.sphere.spherical_to_extrinsic(result)
        expected = self.sphere.metric.exp(immersed_tangent_vec_a,
                                          base_point=immersed_base_point)

        self.assertAllClose(result, expected, atol=1e-1)

    @geomstats.tests.autograd_and_torch_only
    def test_parallel_transport_and_sphere_parallel_transport(self):
        """Test consistency between sphere's parallel transports.

        The parallel transport of the class Hypersphere is
        defined in terms of extrinsic coordinates.

        The parallel transport of pullback_metric is defined
        in terms of the spherical coordinates.
        """
        tangent_vec_a = gs.array([0.0, 1.0])
        tangent_vec_b = gs.array([0.0, 1.0])
        base_point = gs.array([gs.pi / 2.0, 0.0])
        immersed_base_point = self.immersion(base_point)
        jac_immersion = self.pullback_metric.jacobian_immersion(base_point)
        immersed_tangent_vec_a = gs.matmul(jac_immersion, tangent_vec_a)
        immersed_tangent_vec_b = gs.matmul(jac_immersion, tangent_vec_b)

        result_dict = self.pullback_metric.ladder_parallel_transport(
            tangent_vec_a, tangent_vec_b, base_point=base_point)

        result = result_dict["transported_tangent_vec"]
        end_point = result_dict["end_point"]
        result = self.pullback_metric.tangent_immersion(v=result, x=end_point)

        expected = self.sphere_metric.parallel_transport(
            immersed_tangent_vec_a,
            immersed_tangent_vec_b,
            base_point=immersed_base_point,
        )
        self.assertAllClose(result, expected, atol=1e-5)
Ejemplo n.º 10
0
class TestConnectionMethods(geomstats.tests.TestCase):
    def setUp(self):
        warnings.simplefilter('ignore', category=UserWarning)

        self.dimension = 4
        self.euc_metric = EuclideanMetric(dimension=self.dimension)

        self.connection = Connection(dimension=2)
        self.hypersphere = Hypersphere(dimension=2)

    def test_metric_matrix(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.inner_product_matrix(base_point)
        expected = gs.array([gs.eye(self.dimension)])

        with self.session():
            self.assertAllClose(result, expected)

    def test_cometric_matrix(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.inner_product_inverse_matrix(base_point)
        expected = gs.array([gs.eye(self.dimension)])

        with self.session():
            self.assertAllClose(result, expected)

    @geomstats.tests.np_only
    def test_metric_derivative(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.inner_product_derivative_matrix(base_point)
        expected = gs.zeros((1, ) + (self.dimension, ) * 3)

        self.assertAllClose(result, expected)

    @geomstats.tests.np_only
    def test_christoffels(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.christoffels(base_point)
        expected = gs.zeros((1, ) + (self.dimension, ) * 3)

        self.assertAllClose(result, expected)

    @geomstats.tests.np_only
    def test_parallel_transport(self):
        n_samples = 10
        base_point = self.hypersphere.random_uniform(n_samples)
        tan_vec_a = self.hypersphere.projection_to_tangent_space(
            gs.random.rand(n_samples, 3), base_point)
        tan_vec_b = self.hypersphere.projection_to_tangent_space(
            gs.random.rand(n_samples, 3), base_point)
        expected = self.hypersphere.metric.parallel_transport(
            tan_vec_a, tan_vec_b, base_point)
        result = self.hypersphere.metric.pole_ladder_parallel_transport(
            tan_vec_a, tan_vec_b, base_point)

        self.assertAllClose(result, expected, rtol=1e-7, atol=1e-5)

    @geomstats.tests.np_only
    def test_exp(self):
        point = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]])
        vector = gs.array([[0.25, 0.5], [0.30, 0.2]])
        point_ext = self.hypersphere.spherical_to_extrinsic(point)
        vector_ext = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, point)
        self.connection.christoffels = self.hypersphere.metric.christoffels
        expected = self.hypersphere.metric.exp(vector_ext, point_ext)
        result_spherical = self.connection.exp(vector,
                                               point,
                                               n_steps=50,
                                               step='rk4')
        result = self.hypersphere.spherical_to_extrinsic(result_spherical)

        self.assertAllClose(result, expected, rtol=1e-6)

    @geomstats.tests.np_only
    def test_log(self):
        base_point = gs.array([[gs.pi / 3, gs.pi / 4], [gs.pi / 2, gs.pi / 4]])
        point = gs.array([[1.0, gs.pi / 2], [gs.pi / 6, gs.pi / 3]])
        self.connection.christoffels = self.hypersphere.metric.christoffels
        vector = self.connection.log(point=point,
                                     base_point=base_point,
                                     n_steps=75,
                                     step='rk')
        result = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, base_point)
        p_ext = self.hypersphere.spherical_to_extrinsic(base_point)
        q_ext = self.hypersphere.spherical_to_extrinsic(point)
        expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext)

        self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5)
Ejemplo n.º 11
0
class TestConnectionMethods(geomstats.tests.TestCase):
    def setUp(self):
        warnings.simplefilter('ignore', category=UserWarning)

        self.dim = 4
        self.euc_metric = EuclideanMetric(dim=self.dim)

        self.connection = Connection(dim=2)
        self.hypersphere = Hypersphere(dim=2)

    def test_metric_matrix(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.inner_product_matrix(base_point)
        expected = gs.eye(self.dim)

        self.assertAllClose(result, expected)

    def test_cometric_matrix(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.inner_product_inverse_matrix(base_point)
        expected = gs.eye(self.dim)

        self.assertAllClose(result, expected)

    @geomstats.tests.np_only
    def test_metric_derivative(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.inner_product_derivative_matrix(base_point)
        expected = gs.zeros((self.dim, ) * 3)

        self.assertAllClose(result, expected)

    @geomstats.tests.np_only
    def test_christoffels(self):
        base_point = gs.array([0., 1., 0., 0.])

        result = self.euc_metric.christoffels(base_point)
        expected = gs.zeros((self.dim, ) * 3)

        self.assertAllClose(result, expected)

    @geomstats.tests.np_and_pytorch_only
    def test_parallel_transport(self):
        n_samples = 2
        for step in ['pole', 'schild']:
            n_steps = 1 if step == 'pole' else 100
            tol = 1e-6 if step == 'pole' else 1e-1
            base_point = self.hypersphere.random_uniform(n_samples)
            tan_vec_a = self.hypersphere.projection_to_tangent_space(
                gs.random.rand(n_samples, 3), base_point)
            tan_vec_b = self.hypersphere.projection_to_tangent_space(
                gs.random.rand(n_samples, 3), base_point)
            expected = self.hypersphere.metric.parallel_transport(
                tan_vec_a, tan_vec_b, base_point)
            ladder = self.hypersphere.metric.ladder_parallel_transport(
                tan_vec_a, tan_vec_b, base_point, step=step, n_steps=n_steps)
            result = ladder['transported_tangent_vec']

            self.assertAllClose(result, expected, rtol=tol, atol=tol)

    @geomstats.tests.np_and_pytorch_only
    def test_parallel_transport_trajectory(self):
        n_samples = 2
        for step in ['pole', 'schild']:
            n_steps = 1 if step == 'pole' else 100
            rtol = 1e-6 if step == 'pole' else 1e-1
            base_point = self.hypersphere.random_uniform(n_samples)
            tan_vec_a = self.hypersphere.projection_to_tangent_space(
                gs.random.rand(n_samples, 3), base_point)
            tan_vec_b = self.hypersphere.projection_to_tangent_space(
                gs.random.rand(n_samples, 3), base_point)
            expected = self.hypersphere.metric.parallel_transport(
                tan_vec_a, tan_vec_b, base_point)
            ladder = self.hypersphere.metric.ladder_parallel_transport(
                tan_vec_a,
                tan_vec_b,
                base_point,
                return_geodesics=True,
                step=step,
                n_steps=n_steps)
            result = ladder['transported_tangent_vec']

            self.assertAllClose(result, expected, rtol=rtol)

    @geomstats.tests.np_only
    def test_exp(self):
        point = gs.array([[gs.pi / 2, 0], [gs.pi / 6, gs.pi / 4]])
        vector = gs.array([[0.25, 0.5], [0.30, 0.2]])
        point_ext = self.hypersphere.spherical_to_extrinsic(point)
        vector_ext = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, point)
        self.connection.christoffels = self.hypersphere.metric.christoffels
        expected = self.hypersphere.metric.exp(vector_ext, point_ext)
        result_spherical = self.connection.exp(vector,
                                               point,
                                               n_steps=50,
                                               step='rk4')
        result = self.hypersphere.spherical_to_extrinsic(result_spherical)

        self.assertAllClose(result, expected, rtol=1e-6)

    @geomstats.tests.np_only
    def test_log(self):
        base_point = gs.array([[gs.pi / 3, gs.pi / 4], [gs.pi / 2, gs.pi / 4]])
        point = gs.array([[1.0, gs.pi / 2], [gs.pi / 6, gs.pi / 3]])
        self.connection.christoffels = self.hypersphere.metric.christoffels
        vector = self.connection.log(point=point,
                                     base_point=base_point,
                                     n_steps=75,
                                     step='rk')
        result = self.hypersphere.tangent_spherical_to_extrinsic(
            vector, base_point)
        p_ext = self.hypersphere.spherical_to_extrinsic(base_point)
        q_ext = self.hypersphere.spherical_to_extrinsic(point)
        expected = self.hypersphere.metric.log(base_point=p_ext, point=q_ext)

        self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5)