def test_geodesic_and_belongs(self):
        # TODO(nina): this tests fails when geodesic goes "too far"
        initial_point = tf.convert_to_tensor([4.0, 1., 3.0, math.sqrt(5)])
        n_geodesic_points = 100
        vector = tf.convert_to_tensor([1., 0., 0., 0.])

        initial_tangent_vec = self.space.projection_to_tangent_space(
            vector=vector, base_point=initial_point)
        geodesic = self.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)

        bool_belongs = self.space.belongs(points)
        expected = tf.convert_to_tensor(n_geodesic_points * [[True]])

        with self.test_session():
            self.assertAllClose(gs.eval(expected), gs.eval(bool_belongs))
Пример #2
0
    def test_geodesic_and_belongs(self):
        # TODO(nina): Fix this tests, as it fails when geodesic goes "too far"
        initial_point = gs.array([4.0, 1., 3.0, math.sqrt(5)])
        n_geodesic_points = 100
        vector = gs.array([1., 0., 0., 0.])

        initial_tangent_vec = self.space.projection_to_tangent_space(
            vector=vector, base_point=initial_point)
        geodesic = self.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 = self.space.belongs(points)
        expected = gs.array(n_geodesic_points * [[True]])

        with self.session():
            self.assertAllClose(expected, result)
Пример #3
0
    def test_geodesic(self):
        """Test geodesic.

        Check that the norm of the velocity is constant.
        """
        initial_point = self.dirichlet.random_point()
        end_point = self.dirichlet.random_point()

        n_steps = 10000
        geod = self.metric.geodesic(initial_point=initial_point,
                                    end_point=end_point)
        t = gs.linspace(0., 1., n_steps)
        geod_at_t = geod(t)
        velocity = n_steps * (geod_at_t[1:, :] - geod_at_t[:-1, :])
        velocity_norm = self.metric.norm(velocity, geod_at_t[:-1, :])
        result = 1 / velocity_norm.min() * (velocity_norm.max() -
                                            velocity_norm.min())
        expected = 0.

        self.assertAllClose(expected, result, rtol=1.)
Пример #4
0
    def test_geodesic(self):
        """Test geodesic.

        Check that the norm of the velocity is constant.
        """
        initial_point = self.categorical.random_point()
        end_point = self.categorical.random_point()

        n_steps = 100
        geod = self.metric.geodesic(initial_point=initial_point,
                                    end_point=end_point)
        t = gs.linspace(0.0, 1.0, n_steps)
        geod_at_t = geod(t)
        velocity = n_steps * (geod_at_t[1:, :] - geod_at_t[:-1, :])
        velocity_norm = self.metric.norm(velocity, geod_at_t[:-1, :])
        result = (1 / gs.amin(velocity_norm) *
                  (gs.amax(velocity_norm) - gs.amin(velocity_norm)))
        expected = 0.0

        self.assertAllClose(expected, result, rtol=1.0)
        def path(t):
            """Generate parameterized function for geodesic curve.

            Parameters
            ----------
            t : array-like, shape=[n_times,]
                Times at which to compute points of the geodesics.

            Returns
            -------
            geodesic : array-like, shape=[..., n_times, dim]
                Values of the geodesic at times t.
            """
            t = gs.to_ndarray(t, to_ndim=1)
            n_times = len(t)
            geod = []

            if n_times < n_steps:
                t_int = gs.linspace(0, 1, n_steps + 1)
                tangent_vecs = gs.einsum(
                    'i,...k->...ik', t, initial_tangent_vec)
                for point, vec in zip(initial_point, tangent_vecs):
                    point = gs.tile(point, (n_times, 1))
                    exp = []
                    for pt, vc in zip(point, vec):
                        initial_state = gs.hstack([pt, vc])
                        solution = odeint(
                            ivp, initial_state, t_int, (), rtol=1e-6)
                        exp.append(solution[-1, :self.dim])
                    exp = exp[0] if n_times == 1 else gs.stack(exp)
                    geod.append(exp)
            else:
                t_int = t
                for point, vec in zip(initial_point, initial_tangent_vec):
                    initial_state = gs.hstack([point, vec])
                    solution = odeint(
                        ivp, initial_state, t_int, (), rtol=1e-6)
                    geod.append(solution[:, :self.dim])

            return geod[0] if len(initial_point) == 1 else \
                gs.stack(geod)  # , axis=1)
Пример #6
0
 def test_quotient_dist(
     self, sampling_times, curve_fun_a, curve_a, n_sampling_points
 ):
     """Test quotient distance.
     Check that the quotient distance is the same as the distance
     between the end points of the horizontal geodesic.
     """
     curve_a_resampled = curve_fun_a(sampling_times**2)
     curve_b = gs.transpose(
         gs.stack(
             (
                 gs.zeros(n_sampling_points),
                 gs.zeros(n_sampling_points),
                 gs.linspace(1.0, 0.5, n_sampling_points),
             )
         )
     )
     quotient_srv_metric_r3 = DiscreteCurves(ambient_manifold=r3).quotient_srv_metric
     result = quotient_srv_metric_r3.dist(curve_a_resampled, curve_b)
     expected = quotient_srv_metric_r3.dist(curve_a, curve_b)
     self.assertAllClose(result, expected, atol=1e-3, rtol=1e-3)
Пример #7
0
    def tests_geodesic_ivp_and_bvp(self):
        """Test geodesic intial and boundary value problems.

        Check the shape of the geodesic.
        """
        n_steps = 50
        t = gs.linspace(0.0, 1.0, n_steps)

        initial_points = self.dirichlet.random_point(self.n_points)
        initial_tangent_vecs = self.dirichlet.random_point(self.n_points)
        geodesic = self.metric._geodesic_ivp(initial_points, initial_tangent_vecs)
        geodesic_at_t = geodesic(t)
        result = geodesic_at_t.shape
        expected = (self.n_points, n_steps, self.dim)
        self.assertAllClose(result, expected)

        end_points = self.dirichlet.random_point(self.n_points)
        geodesic = self.metric._geodesic_bvp(initial_points, end_points)
        geodesic_at_t = geodesic(t)
        result = geodesic_at_t.shape
        self.assertAllClose(result, expected)
Пример #8
0
    def test_geodesic_bvp_belongs(
        self,
        connection_args,
        space,
        n_points,
        initial_point,
        end_point,
        belongs_atol,
    ):
        """Check that connection geodesics belong to manifold.

        This is for geodesics defined by the boundary value problem (bvp).

        Parameters
        ----------
        connection_args : tuple
            Arguments to pass to constructor of the connection.
        space : Manifold
            Manifold where connection is defined.
        n_points : int
            Number of points on the geodesics.
        initial_point : array-like
            Point on the manifold.
        end_point : array-like
            Point on the manifold.
        belongs_atol : float
            Absolute tolerance for the belongs function.
        """
        connection = self.connection(*connection_args)

        geodesic = connection.geodesic(initial_point=initial_point,
                                       end_point=end_point)

        t = gs.linspace(start=0.0, stop=1.0, num=n_points)
        points = geodesic(t)

        result = space.belongs(points, belongs_atol)
        expected = gs.array(n_points * [True])

        self.assertAllClose(result, expected)
Пример #9
0
    def log(self, point, base_point, n_steps=N_STEPS, jacobian=False, init="linear"):
        """Compute the logarithm map.

        Compute logarithm map associated to the Fisher information metric by
        solving the boundary value problem associated to the geodesic ordinary
        differential equation (ODE) using the Christoffel symbols.

        Parameters
        ----------
        point : array-like, shape=[..., dim]
            Point.
        base_point : array-like, shape=[..., dim]
            Base po int.
        n_steps : int
            Number of steps for integration.
            Optional, default: 100.
        jacobian : boolean.
            If True, the explicit value of the jacobian is used to solve
            the geodesic boundary value problem.
            Optional, default: False.
        init : str, {'linear', 'polynomial}
            Initialization used to solve the geodesic boundary value problem.
            If 'linear', use the Euclidean straight line as initial guess.
            If 'polynomial', use a curve with coordinates that are polynomial
            functions of time.

        Returns
        -------
        tangent_vec : array-like, shape=[..., dim]
            Initial velocity of the geodesic starting at base_point and
            reaching point at time 1.
        """
        t = gs.linspace(0.0, 1.0, n_steps)
        geodesic = self._geodesic_bvp(
            initial_point=base_point, end_point=point, jacobian=jacobian, init=init
        )
        geodesic_at_t = geodesic(t)
        log = n_steps * (geodesic_at_t[..., 1, :] - geodesic_at_t[..., 0, :])

        return gs.squeeze(gs.stack(log))
Пример #10
0
    def log(self, point, base_point, n_steps=N_STEPS, jacobian=False,
            max_time=MAX_TIME):
        """Compute the logarithm map.

        Compute logarithm map associated to the Fisher information metric by
        solving the boundary value problem associated to the geodesic ordinary
        differential equation (ODE) using the Christoffel symbols.

        Parameters
        ----------
        point : array-like, shape=[..., dim]
            Point.
        base_point : array-like, shape=[..., dim]
            Base po int.
        n_steps : int
            Number of steps for integration.
            Optional, default: 100.
        jacobian : boolean.
            If True, the explicit value of the jacobian is used to solve
            the geodesic boundary value problem.
            Optional, default: False.
        max_time : float.
            Maximum time in which the boundary value problem should be
            solved, in seconds. If it takes longer, the process is terminated.
            Optional, default: 300 seconds i.e. 5 minutes.

        Returns
        -------
        tangent_vec : array-like, shape=[..., dim]
            Initial velocity of the geodesic starting at base_point and
            reaching point at time 1.
        """
        t = gs.linspace(0., 1., n_steps)
        geodesic = self._geodesic_bvp(
            initial_point=base_point, end_point=point, jacobian=jacobian,
            max_time=max_time)
        geodesic_at_t = geodesic(t)
        log = n_steps * (geodesic_at_t[..., 1, :] - geodesic_at_t[..., 0, :])

        return gs.squeeze(gs.stack(log))
        def path(t):
            """Generate parameterized function for geodesic curve.

            Parameters
            ----------
            t : array-like, shape=[n_times,]
                Times at which to compute points of the geodesics.

            Returns
            -------
            geodesic : array-like, shape=[..., n_times, dim]
                Values of the geodesic at times t.
            """
            t = gs.to_ndarray(t, to_ndim=1)
            geod = []

            def initialize(point_0, point_1):
                """Initialize the solution of the boundary value problem."""
                lin_init = gs.zeros([2 * self.dim, n_steps])
                lin_init[:self.dim, :] = gs.transpose(
                    gs.linspace(point_0, point_1, n_steps))
                lin_init[self.dim:, :-1] = n_steps * (
                    lin_init[:self.dim, 1:] - lin_init[:self.dim, :-1])
                lin_init[self.dim:, -1] = lin_init[self.dim:, -2]
                return lin_init

            t_int = gs.linspace(0., 1., n_steps)

            for ip, ep in zip(initial_point, end_point):
                geodesic_init = initialize(ip, ep)

                def bc(y0, y1, ip=ip, ep=ep):
                    return boundary_cond(y0, y1, ip, ep)

                solution = solve_bvp(bvp, bc, t_int, geodesic_init)
                solution_at_t = solution.sol(t)
                geodesic = solution_at_t[:self.dim, :]
                geod.append(gs.squeeze(gs.transpose(geodesic)))

            return geod[0] if len(initial_point) == 1 else gs.stack(geod)
Пример #12
0
    def exp(self, tangent_vec, base_point, n_steps=N_STEPS):
        """Exponential map associated to the Fisher information metric.

        Exponential map at base_point of tangent_vec computed by integration
        of the geodesic equation (initial value problem), using the
        christoffel symbols.

        Parameters
        ----------
        tangent_vec : array-like, shape=[..., dim]
            Tangent vector at base point.
        base_point : array-like, shape=[..., dim]
            Base point.
        n_steps : int
            Number of steps for integration.
            Optional, default: 100.

        Returns
        -------
        exp : array-like, shape=[..., dim]
            Riemannian exponential.
        """
        base_point = gs.to_ndarray(base_point, to_ndim=2)
        tangent_vec = gs.to_ndarray(tangent_vec, to_ndim=2)

        def ivp(state, _):
            """Reformat the initial value problem geodesic ODE."""
            position, velocity = state[:2], state[2:]
            eq = self.geodesic_equation(velocity=velocity, position=position)
            return gs.hstack([velocity, eq])

        times = gs.linspace(0, 1, n_steps + 1)
        exp = []
        for point, vec in zip(base_point, tangent_vec):
            initial_state = gs.hstack([point, vec])
            geodesic = odeint(
                ivp, initial_state, times, (), rtol=1e-6)
            exp.append(geodesic[-1, :2])
        return exp[0] if len(base_point) == 1 else gs.stack(exp)
Пример #13
0
        def cost_fun(param):
            """Compute the energy of the polynomial curve defined by param.

            Parameters
            ----------
            param : array-like, shape=(degree - 1, dim)
                Parameters of the curve coordinates' polynomial functions of time.

            Returns
            -------
            energy : float
                Energy of the polynomial approximation of the geodesic.
            length : float
                Length of the polynomial approximation of the geodesic.
            curve : array-like, shape=(n_times, dim)
                Polynomial approximation of the geodesic.
            velocity : array-like, shape=(n_times, dim)
                Velocity of the polynomial approximation of the geodesic.
            """
            last_coef = end_point - initial_point - gs.sum(param, axis=0)
            coef = gs.vstack((initial_point, param, last_coef))

            t = gs.linspace(0.0, 1.0, n_times)
            t_curve = [t**i for i in range(degree + 1)]
            t_curve = gs.stack(t_curve)
            curve = gs.einsum("ij,ik->kj", coef, t_curve)

            t_velocity = [i * t**(i - 1) for i in range(1, degree + 1)]
            t_velocity = gs.stack(t_velocity)
            velocity = gs.einsum("ij,ik->kj", coef[1:], t_velocity)

            if curve.min() < 0:
                return np.inf, np.inf, curve, np.nan

            velocity_sqnorm = self.squared_norm(vector=velocity,
                                                base_point=curve)
            length = gs.sum(velocity_sqnorm**(1 / 2)) / n_times
            energy = gs.sum(velocity_sqnorm) / n_times
            return energy, length, curve, velocity
Пример #14
0
def main():
    """Plot a square on H2 with Poincare Disk visualization."""
    top = SQUARE_SIZE / 2.0
    bot = -SQUARE_SIZE / 2.0
    left = -SQUARE_SIZE / 2.0
    right = SQUARE_SIZE / 2.0
    corners_int = gs.array([[bot, left], [bot, right], [top, right], [top, left]])
    corners_ext = H2.from_coordinates(corners_int, "intrinsic")
    n_steps = 20
    ax = plt.gca()
    for i, src in enumerate(corners_ext):
        dst_id = (i + 1) % len(corners_ext)
        dst = corners_ext[dst_id]
        tangent_vec = METRIC.log(point=dst, base_point=src)
        geodesic = METRIC.geodesic(initial_point=src, initial_tangent_vec=tangent_vec)
        t = gs.linspace(0.0, 1.0, n_steps)
        edge_points = geodesic(t)

        visualization.plot(
            edge_points, ax=ax, space="H2_poincare_disk", marker=".", color="black"
        )

    plt.show()
Пример #15
0
    def test_geodesic_and_coincides_exp(self, space, n_geodesic_points,
                                        vector):
        initial_point = space.random_uniform(2)
        initial_tangent_vec = space.to_tangent(vector=vector,
                                               base_point=initial_point)
        geodesic = space.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.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.metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        points = geodesic(t)
        result = points[-1]
        expected = space.metric.exp(initial_tangent_vec, initial_point)
        self.assertAllClose(expected, result)
Пример #16
0
    def compute_coordinates(point):
        """
        Compute the ellipsis coordinates from 2D SPD matrix.

        :param point: array-like, shape = [2, 2]: SPD matrix.
        :return:
        X: array-like, shape = [n_steps,];
        Y: array-like, shape = [n_steps,];
        X and Y coordinates.
        """
        w, vr = gs.linalg.eigh(point)
        w = w + EPS
        n_steps = 100

        [e1, e2] = w
        x0, y0 = 0, 0
        n = vr.shape[0]
        angle = SpecialOrthogonal(n).angle_of_rot2(vr)
        c, s = gs.cos(angle), gs.sin(angle)
        the = gs.linspace(0, 2 * gs.pi, n_steps)
        X = e1 * gs.cos(the) * c - s * e2 * gs.sin(the) + x0
        y = e1 * gs.cos(the) * s + c * e2 * gs.sin(the) + y0
        return X, y, X[n_steps // 4], y[n_steps // 4]
Пример #17
0
    def test_geodesic_and_belongs(self):
        n_geodesic_points = 10
        initial_point = self.space.random_uniform(2)
        vector = gs.array([[2.0, 0.0, -1.0, -2.0, 1.0]] * 2)
        initial_tangent_vec = self.space.to_tangent(vector=vector,
                                                    base_point=initial_point)
        geodesic = self.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 = gs.stack([self.space.belongs(pt) for pt in points])
        self.assertTrue(gs.all(result))

        initial_point = initial_point[0]
        initial_tangent_vec = initial_tangent_vec[0]
        geodesic = self.metric.geodesic(
            initial_point=initial_point,
            initial_tangent_vec=initial_tangent_vec)
        points = geodesic(t)
        result = self.space.belongs(points)
        expected = gs.array(n_geodesic_points * [True])
        self.assertAllClose(expected, result)
Пример #18
0
def plot_gaussian_mixture_distribution(
    data,
    mixture_coefficients,
    means,
    variances,
    plot_precision=DEFAULT_PLOT_PRECISION,
    save_path="",
    metric=None,
):
    """Plot Gaussian Mixture Model."""
    x_axis_samples = gs.linspace(-1, 1, plot_precision)
    y_axis_samples = gs.linspace(-1, 1, plot_precision)
    x_axis_samples, y_axis_samples = gs.meshgrid(x_axis_samples, y_axis_samples)

    z_axis_samples = gs.zeros((plot_precision, plot_precision))

    for z_index, _ in enumerate(z_axis_samples):

        x_y_plane_mesh = gs.concatenate(
            (
                gs.expand_dims(x_axis_samples[z_index], -1),
                gs.expand_dims(y_axis_samples[z_index], -1),
            ),
            axis=-1,
        )

        mesh_probabilities = weighted_gmm_pdf(
            mixture_coefficients, x_y_plane_mesh, means, variances, metric
        )

        z_axis_samples[z_index] = mesh_probabilities.sum(-1)

    fig = plt.figure(
        "Learned Gaussian Mixture Model "
        "via Expectation Maximization on Poincaré Disc"
    )

    ax = fig.gca(projection="3d")
    ax.plot_surface(
        x_axis_samples,
        y_axis_samples,
        z_axis_samples,
        rstride=1,
        cstride=1,
        linewidth=1,
        antialiased=True,
        cmap=plt.get_cmap("viridis"),
    )
    z_circle = -0.8
    p = Circle((0, 0), 1, edgecolor="b", lw=1, facecolor="none")

    ax.add_patch(p)

    art3d.pathpatch_2d_to_3d(p, z=z_circle, zdir="z")

    for data_index, _ in enumerate(data):
        ax.scatter(
            data[data_index][0], data[data_index][1], z_circle, c="b", marker="."
        )

    for means_index, _ in enumerate(means):
        ax.scatter(
            means[means_index][0], means[means_index][1], z_circle, c="r", marker="D"
        )

    ax.set_xlim(-1.2, 1.2)
    ax.set_ylim(-1.2, 1.2)
    ax.set_zlim(-0.8, 0.4)

    ax.set_xlabel("X")
    ax.set_ylabel("Y")
    ax.set_zlabel("P")

    plt.savefig(save_path, format="pdf")

    return plt
Пример #19
0
    def log(self, point, base_point, n_steps=N_STEPS):
        """Compute logarithm map associated to the Fisher information metric.

        Solve the boundary value problem associated to the geodesic ordinary
        differential equation (ODE) using the Christoffel symbols.

        Parameters
        ----------
        point : array-like, shape=[n_samples, dim]
        base_point : array-like, shape=[n_samples, dim]
        n_steps : int

        Returns
        -------
        tangent_vec : array-like, shape=[n_samples, dim]
            the initial velocity of the geodesic starting at base_point and
            reaching point at time 1
        """
        stop_time = 1.
        t = gs.linspace(0, stop_time, n_steps)
        point = gs.to_ndarray(point, to_ndim=2)
        base_point = gs.to_ndarray(base_point, to_ndim=2)

        def initialize(end_point, start_point):
            a0, b0 = start_point
            a1, b1 = end_point
            lin_init = gs.zeros([2 * self.dim, n_steps])
            lin_init[0, :] = gs.linspace(a0, a1, n_steps)
            lin_init[1, :] = gs.linspace(b0, b1, n_steps)
            lin_init[2, :-1] = (lin_init[0, 1:] - lin_init[0, :-1]) * n_steps
            lin_init[3, :-1] = (lin_init[1, 1:] - lin_init[1, :-1]) * n_steps
            lin_init[2, -1] = lin_init[2, -2]
            lin_init[3, -1] = lin_init[3, -2]
            return lin_init

        def bvp(time, state):
            """Reformat the boundary value problem geodesic ODE.

            Parameters
            ----------
                state :  vector of the state variables: y = [a,b,u,v]
                time :  time
            """
            position, velocity = state[:2].T, state[2:].T
            eq = self.geodesic_equation(
                velocity=velocity, position=position)
            return gs.vstack((velocity.T, eq.T))

        def boundary_cond(
                state_a, state_b, point_0_a, point_0_b, point_1_a, point_1_b):
            return gs.array(
                [state_a[0] - point_0_a,
                 state_a[1] - point_0_b,
                 state_b[0] - point_1_a,
                 state_b[1] - point_1_b])

        log = []
        for bp, pt in zip(base_point, point):
            geodesic_init = initialize(pt, bp)
            base_point_a, base_point_b = bp
            point_a, point_b = pt

            def bc(y0, y1):
                return boundary_cond(
                    y0, y1, base_point_a, base_point_b, point_a, point_b)

            solution = solve_bvp(bvp, bc, t, geodesic_init)
            geodesic = solution.sol(t)
            geodesic = geodesic[:2, :]
            log.append(n_steps * (geodesic[:, 1] - geodesic[:, 0]))

        return log[0] if len(base_point) == 1 else gs.stack(log)
Пример #20
0
    ax = fig.add_subplot(111, projection='3d')
    plot_sphere = Sphere()

    n_points = 10000
    f_points = plot_sphere.fibonnaci_points(n_points).swapaxes(0, 1)
    plot_sphere.plot_heatmap(ax=ax, n_points=n_points, scalar_function=loss_f)
    correct_points = s_points[labels == 0][:30, :]
    correct_labels = np.ones_like(correct_points)

    ax = visualization.plot(correct_points, ax=ax, space='S2', color='red', s=80)

    f_labels = np.array(f_labels)[:, 0]
    f_points = f_points[f_labels != 0]

    metric = HypersphereMetric(dim=2)
    for k in range(len(correct_points)):
        point_matrix = correct_points[k:k+1, :].repeat(len(f_points), axis=0)
        dist_array = metric.dist(point_matrix, f_points)
        idx_min = np.argmin(dist_array)

        geodesic = sphere.metric.geodesic(
            initial_point=correct_points[k],
            end_point=f_points[idx_min])

        points_on_geodesic = geodesic(gs.linspace(0., 1., 10))
        plot_sphere.add_points(points_on_geodesic)

    plot_sphere.draw_points(ax=ax, color='black', alpha=0.1)

    plt.show()
Пример #21
0
    def log(self, point, base_point, n_steps=N_STEPS):
        """Compute the logarithm map.

        Compute logarithm map associated to the Fisher information metric by
        solving the boundary value problem associated to the geodesic ordinary
        differential equation (ODE) using the Christoffel symbols.

        Parameters
        ----------
        point : array-like, shape=[..., dim]
            Point.
        base_point : array-like, shape=[..., dim]
            Base point.
        n_steps : int
            Number of steps for integration.
            Optional, default: 100.

        Returns
        -------
        tangent_vec : array-like, shape=[..., dim]
            Initial velocity of the geodesic starting at base_point and
            reaching point at time 1.
        """
        stop_time = 1.
        t = gs.linspace(0, stop_time, n_steps)
        point = gs.to_ndarray(point, to_ndim=2)
        base_point = gs.to_ndarray(base_point, to_ndim=2)
        n_points = point.shape[0]
        n_base_points = base_point.shape[0]
        if n_base_points > n_points:
            if n_points > 1:
                raise ValueError('For several base points, specify either '
                                 'one or the same number of points.')
            point = gs.tile(point, (n_base_points, 1))
        elif n_points > n_base_points:
            if n_base_points > 1:
                raise ValueError('For several points, specify either '
                                 'one or the same number of base points.')
            base_point = gs.tile(base_point, (n_points, 1))

        def initialize(end_point, start_point):
            lin_init = gs.zeros([2 * self.dim, n_steps])
            lin_init[:self.dim, :] = gs.transpose(
                gs.linspace(start_point, end_point, n_steps))
            lin_init[self.dim:, :-1] = (lin_init[:self.dim, 1:] -
                                        lin_init[:self.dim, :-1]) * n_steps
            lin_init[self.dim:, -1] = lin_init[self.dim:, -2]
            return lin_init

        def bvp(_, state):
            """Reformat the boundary value problem geodesic ODE.

            Parameters
            ----------
            state :  array-like, shape[4,]
                Vector of the state variables: y = [a,b,u,v]
            _ :  unused
                Any (time).
            """
            position, velocity = state[:self.dim].T, state[self.dim:].T
            eq = self.geodesic_equation(velocity=velocity, position=position)
            return gs.transpose(gs.hstack(eq))

        def boundary_cond(state_0, state_1, point_0, point_1):
            return gs.hstack(
                (state_0[:self.dim] - point_0, state_1[:self.dim] - point_1))

        log = []
        for bp, pt in zip(base_point, point):
            geodesic_init = initialize(pt, bp)

            def bc(y0, y1, bp=bp, pt=pt):
                return boundary_cond(y0, y1, bp, pt)

            solution = solve_bvp(bvp, bc, t, geodesic_init)
            geodesic = solution.sol(t)
            geodesic = geodesic[:self.dim, :]
            log.append(n_steps * (geodesic[:, 1] - geodesic[:, 0]))

        return log[0] if len(base_point) == 1 else gs.stack(log)
Пример #22
0
r3 = s2.embedding_space

initial_point = [0.0, 0.0, 1.0]
initial_tangent_vec_a = [1.0, 0.0, 0.0]
initial_tangent_vec_b = [0.0, 1.0, 0.0]
initial_tangent_vec_c = [-1.0, 0.0, 0.0]

curve_fun_a = s2.metric.geodesic(initial_point=initial_point,
                                 initial_tangent_vec=initial_tangent_vec_a)
curve_fun_b = s2.metric.geodesic(initial_point=initial_point,
                                 initial_tangent_vec=initial_tangent_vec_b)
curve_fun_c = s2.metric.geodesic(initial_point=initial_point,
                                 initial_tangent_vec=initial_tangent_vec_c)

n_sampling_points = 10
sampling_times = gs.linspace(0.0, 1.0, n_sampling_points)
curve_a = curve_fun_a(sampling_times)
curve_b = curve_fun_b(sampling_times)
curve_c = curve_fun_c(sampling_times)

n_discretized_curves = 5
times = gs.linspace(0.0, 1.0, n_discretized_curves)


class DiscreteCurvesTestData(_ManifoldTestData):
    space_args_list = [(r2, ), (r3, )]
    shape_list = [(10, 2), (10, 3)]
    n_samples_list = random.sample(range(2, 5), 2)
    n_points_list = random.sample(range(2, 5), 2)
    n_vecs_list = random.sample(range(2, 5), 2)
Пример #23
0
def multi_plot_modulation_factor(dim, n_expectation=1000, n_theta=20):
    """Plot modulation factor curves for large number of samples.

    Plot several curves of modulation factor on the convergence of the
    empirical Fréchet mean as a function of the radius of the bubble
    distribution and for 10 to 100 sample points on the hyperbolic space H_dim
    embedded in R^{1,dim}.

    Parameters
    ----------
    dim: dimension of the hyperbolic space (embedded in R^{1,dim})
    n_expectation: number of computations for approximating the expectation
    n_theta: number of sampled radii for the bubble distribution

    Returns
    -------
    matplolib figure
    """
    theta = gs.linspace(0.000001, 5, n_theta)
    small_var_modulation_factor = []
    asymptotic_modulation_actor = []
    print("Convergence rate modulation factor, "
          "hyperbolic space, dim={0}, n > 5".format(dim))
    plt.figure()
    for theta_i in theta:
        small_var_modulation_factor.append(1.0 - 2.0 / 3.0 * theta_i**2 *
                                           (1.0 - 1.0 / dim) * 1.0)
        asymptotic_modulation_actor.append(asymptotic_modulation(dim, theta_i))
    plt.plot(theta,
             small_var_modulation_factor,
             'g',
             label='Small variance prediction')
    plt.plot(theta,
             asymptotic_modulation_actor,
             'grey',
             label='Asymptotic prediction')
    color = {10: 'red', 20: 'orange', 50: 'olive', 100: 'blue'}
    for n_samples in [10, 20, 50, 100]:
        measured_modulation_factor = []
        for theta_i in theta:
            (var, std_var) = modulation_factor(n_samples,
                                               theta_i,
                                               dim,
                                               n_expectation=n_expectation)
            measured_modulation_factor.append(var)
            print('{} {} {} {}\n'.format(n_samples, theta_i, var, std_var))
        plt.plot(theta,
                 measured_modulation_factor,
                 color=color[n_samples],
                 label="n={0}".format(n_samples))
    plt.xlabel(r'Standard deviation $\theta$')
    plt.ylabel(r'Modulation factor $\alpha$')
    plt.legend(loc='best')
    plt.title("Convergence rate modulation factor, "
              "hyperbolic space, dim={0}, n > 5".format(dim))
    plt.ylim([0, 1.3])
    plt.draw()
    plt.pause(0.01)
    plt.savefig("Figures/HypVarModulation_n10p_d{0}_m{1}.png".format(
        dim, n_expectation))
    plt.savefig("Figures/HypVarModulation_n10p_d{0}_m{1}.pdf".format(
        dim, n_expectation))
    return plt
Пример #24
0
def plot_modulation_factor(n_samples, dim, n_expectation=1000, n_theta=20):
    """Plot the modulation factor curve w.r.t. the dispersion.

    Plot the curve of modulation factor on the convergence of the
    empirical Fréchet mean as a function of the radius of the bubble
    distribution and for n_samples points on the hyperbolic space H_dim
    embedded in R^{1,dim}.

    Parameters
    ----------
    n_samples: number of samples to draw
    dim: dimension of the hyperbolic space (embedded in R^{1,dim})
    n_expectation: number of computations for approximating the expectation
    n_theta: number of sampled radii for the bubble distribution

    Returns
    -------
    matplolib figure
    """
    theta = gs.linspace(0.000001, 5, n_theta)
    measured_modulation_factor = []
    error = []
    small_var_modulation_factor = []
    asymptotic_modulation_factor = []
    print("Convergence rate modulation factor, "
          "hyperbolic space dim={1}, n={0}".format(n_samples, dim))
    for theta_i in theta:
        (var, std_var) = modulation_factor(n_samples,
                                           theta_i,
                                           dim,
                                           n_expectation=n_expectation)
        measured_modulation_factor.append(var)
        error.append(std_var)
        print('{} {} {} {}\n'.format(n_samples, theta_i, var, std_var))
        small_var_modulation_factor.append(1.0 - 2.0 / 3.0 * theta_i**2 *
                                           (1.0 - 1.0 / dim) *
                                           (1.0 - 1.0 / n_samples))
        asymptotic_modulation_factor.append(asymptotic_modulation(
            dim, theta_i))
    plt.figure()
    plt.errorbar(theta,
                 measured_modulation_factor,
                 yerr=error,
                 color='r',
                 label='Measured')
    plt.plot(theta,
             small_var_modulation_factor,
             'g',
             label='Small variance prediction')
    plt.plot(theta,
             asymptotic_modulation_factor,
             'grey',
             label='Asymptotic prediction')
    plt.xlabel(r'Standard deviation $\theta$')
    plt.ylabel(r'Modulation factor $\alpha$')
    plt.title("Convergence rate modulation factor, "
              "hyperbolic space dim={1}, n={0}".format(n_samples, dim))
    plt.legend(loc='best')
    plt.ylim([0, 1.3])
    plt.draw()
    plt.pause(0.01)
    plt.savefig("Figures/HypVarModulation_n{0}_d{1}_m{2}.png".format(
        n_samples, dim, n_expectation))
    plt.savefig("Figures/HypVarModulation_n{0}_d{1}_m{2}.pdf".format(
        n_samples, dim, n_expectation))
    return plt
c1 = resample(c1, n)
c2 = resample(c2, n)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(c1[:, 0], c1[:, 1], c1[:, 2])
ax.plot(c2[:, 0], c2[:, 1], c2[:, 2])
ax.scatter(c1[0, 0], c1[0, 1], c1[0, 2])
ax.scatter(c2[0, 0], c2[0, 1], c2[0, 2])
plt.show()

srv_geod_fun = curves3D.square_root_velocity_metric.geodesic(initial_curve=c1,
                                                             end_curve=c2)

n_times = 50
t = gs.linspace(0., 1., n_times + 1)
srv_geod = srv_geod_fun(t)

fig = plt.figure(figsize=(12, 10))
ax = fig.add_subplot(111, projection='3d')
for i in range(n_times):
    ax.plot(srv_geod[i, :, 0], srv_geod[i, :, 1], srv_geod[i, :, 2])
plt.title('SRV geodesic')
plt.show()

horizontal_geod = horizontal_geodesic(c1, c2, 50)

fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='3d')
for i in range(n_times + 1):
    ax.plot(horizontal_geod[i, :, 0], horizontal_geod[i, :, 1],
Пример #26
0
def main():
    r"""Compute and visualize a geodesic regression on the sphere.

    The generative model of the data is:
    :math:`Z = Exp_{\beta_0}(\beta_1.X)` and :math:`Y = Exp_Z(\epsilon)`
    where:
    - :math:`Exp` denotes the Riemannian exponential,
    - :math:`\beta_0` is called the intercept,
    - :math:`\beta_1` is called the coefficient,
    - :math:`\epsilon \sim N(0, 1)` is a standard Gaussian noise,
    - :math:`X` is the input, :math:`Y` is the target.
    """
    # Generate noise-free data
    n_samples = 50
    X = gs.random.rand(n_samples)
    X -= gs.mean(X)

    intercept = SPACE.random_uniform()
    coef = SPACE.to_tangent(5.0 * gs.random.rand(EMBEDDING_DIM),
                            base_point=intercept)
    y = METRIC.exp(X[:, None] * coef, base_point=intercept)

    # Generate normal noise
    normal_noise = gs.random.normal(size=(n_samples, EMBEDDING_DIM))
    noise = SPACE.to_tangent(normal_noise, base_point=y) / gs.pi / 2

    rss = gs.sum(METRIC.squared_norm(noise, base_point=y)) / n_samples

    # Add noise
    y = METRIC.exp(noise, y)

    # True noise level and R2
    estimator = FrechetMean(METRIC)
    estimator.fit(y)
    variance_ = variance(y, estimator.estimate_, metric=METRIC)
    r2 = 1 - rss / variance_

    # Fit geodesic regression
    gr = GeodesicRegression(SPACE,
                            center_X=False,
                            method="extrinsic",
                            verbose=True)
    gr.fit(X, y, compute_training_score=True)
    intercept_hat, coef_hat = gr.intercept_, gr.coef_

    # Measure Mean Squared Error
    mse_intercept = METRIC.squared_dist(intercept_hat, intercept)

    tangent_vec_to_transport = coef_hat
    tangent_vec_of_transport = METRIC.log(intercept, base_point=intercept_hat)
    transported_coef_hat = METRIC.parallel_transport(
        tangent_vec=tangent_vec_to_transport,
        base_point=intercept_hat,
        direction=tangent_vec_of_transport,
    )
    mse_coef = METRIC.squared_norm(transported_coef_hat - coef,
                                   base_point=intercept)

    # Measure goodness of fit
    r2_hat = gr.training_score_

    print(f"MSE on the intercept: {mse_intercept:.2e}")
    print(f"MSE on the coef, i.e. initial velocity: {mse_coef:.2e}")
    print(f"Determination coefficient: R^2={r2_hat:.2f}")
    print(f"True R^2: {r2:.2f}")

    # Plot
    fitted_data = gr.predict(X)
    fig = plt.figure(figsize=(8, 8))
    ax = fig.add_subplot(111, projection="3d")
    sphere_visu = visualization.Sphere(n_meridians=30)
    ax = sphere_visu.set_ax(ax=ax)

    path = METRIC.geodesic(initial_point=intercept_hat,
                           initial_tangent_vec=coef_hat)
    regressed_geodesic = path(
        gs.linspace(0.0, 1.0, 100) * gs.pi * 2 / METRIC.norm(coef))
    regressed_geodesic = gs.to_numpy(gs.autodiff.detach(regressed_geodesic))

    size = 10
    marker = "o"
    sphere_visu.draw_points(ax,
                            gs.array([intercept_hat]),
                            marker=marker,
                            c="r",
                            s=size)
    sphere_visu.draw_points(ax, y, marker=marker, c="b", s=size)
    sphere_visu.draw_points(ax, fitted_data, marker=marker, c="g", s=size)

    ax.plot(
        regressed_geodesic[:, 0],
        regressed_geodesic[:, 1],
        regressed_geodesic[:, 2],
        c="gray",
    )
    sphere_visu.draw(ax, linewidth=1)
    ax.grid(False)
    plt.axis("off")

    plt.show()
Пример #27
0
class TestDataL2Metric(_RiemannianMetricTestData):

    dim_list = random.sample(range(2, 4), 2)
    n_landmarks_list = random.sample(range(2, 5), 2)
    metric_args_list = [
        (Hypersphere(dim), n_landmarks)
        for dim, n_landmarks in zip(dim_list, n_landmarks_list)
    ] + [(Euclidean(dim + 1), n_landmarks)
         for dim, n_landmarks in zip(dim_list, n_landmarks_list)]
    space_list = [Landmarks(*metric_arg) for metric_arg in metric_args_list]
    shape_list = [(n_landmark, dim + 1)
                  for dim, n_landmark in zip(dim_list, n_landmarks_list)] * 2
    n_points_list = random.sample(range(2, 5), 2)
    n_tangent_vecs_list = random.sample(range(2, 5), 2)
    n_points_a_list = random.sample(range(2, 5), 2)
    n_points_b_list = [1]
    alpha_list = [1] * 4
    n_rungs_list = [1] * 4
    scheme_list = ["pole"] * 4

    s2 = Hypersphere(dim=2)
    r3 = s2.embedding_space

    initial_point = [0.0, 0.0, 1.0]
    initial_tangent_vec_a = [1.0, 0.0, 0.0]
    initial_tangent_vec_b = [0.0, 1.0, 0.0]
    initial_tangent_vec_c = [-1.0, 0.0, 0.0]

    landmarks_a = s2.metric.geodesic(initial_point=initial_point,
                                     initial_tangent_vec=initial_tangent_vec_a)
    landmarks_b = s2.metric.geodesic(initial_point=initial_point,
                                     initial_tangent_vec=initial_tangent_vec_b)
    landmarks_c = s2.metric.geodesic(initial_point=initial_point,
                                     initial_tangent_vec=initial_tangent_vec_c)

    n_sampling_points = 10
    sampling_times = gs.linspace(0.0, 1.0, n_sampling_points)
    landmark_set_a = landmarks_a(sampling_times)
    landmark_set_b = landmarks_b(sampling_times)
    landmark_set_c = landmarks_c(sampling_times)

    n_landmark_sets = 5
    times = gs.linspace(0.0, 1.0, n_landmark_sets)
    space_landmarks_in_sphere_2d = Landmarks(ambient_manifold=s2,
                                             k_landmarks=n_sampling_points)
    l2_metric_s2 = space_landmarks_in_sphere_2d.metric

    def exp_shape_test_data(self):
        return self._exp_shape_test_data(self.metric_args_list,
                                         self.space_list, self.shape_list)

    def log_shape_test_data(self):
        return self._log_shape_test_data(self.metric_args_list,
                                         self.space_list)

    def squared_dist_is_symmetric_test_data(self):
        return self._squared_dist_is_symmetric_test_data(
            self.metric_args_list,
            self.space_list,
            self.n_points_a_list,
            self.n_points_b_list,
            atol=gs.atol * 1000,
        )

    def exp_belongs_test_data(self):
        return self._exp_belongs_test_data(
            self.metric_args_list,
            self.space_list,
            self.shape_list,
            self.n_tangent_vecs_list,
            belongs_atol=gs.atol * 10000,
        )

    def log_is_tangent_test_data(self):
        return self._log_is_tangent_test_data(
            self.metric_args_list,
            self.space_list,
            self.n_points_list,
            is_tangent_atol=gs.atol * 1000,
        )

    def geodesic_ivp_belongs_test_data(self):
        return self._geodesic_ivp_belongs_test_data(
            self.metric_args_list,
            self.space_list,
            self.shape_list,
            self.n_points_list,
            belongs_atol=gs.atol * 1000,
        )

    def geodesic_bvp_belongs_test_data(self):
        return self._geodesic_bvp_belongs_test_data(
            self.metric_args_list,
            self.space_list,
            self.n_points_list,
            belongs_atol=gs.atol * 100,
        )

    def exp_after_log_test_data(self):
        return self._exp_after_log_test_data(
            self.metric_args_list,
            self.space_list,
            self.n_tangent_vecs_list,
            rtol=gs.rtol * 1000,
            atol=gs.atol * 1000,
        )

    def log_after_exp_test_data(self):
        return self._log_after_exp_test_data(
            self.metric_args_list,
            self.space_list,
            self.shape_list,
            self.n_points_list,
            amplitude=30,
            rtol=gs.rtol * 10000,
            atol=gs.atol * 100000,
        )

    def exp_ladder_parallel_transport_test_data(self):
        return self._exp_ladder_parallel_transport_test_data(
            self.metric_args_list,
            self.space_list,
            self.shape_list,
            self.n_tangent_vecs_list,
            self.n_rungs_list,
            self.alpha_list,
            self.scheme_list,
        )

    def exp_geodesic_ivp_test_data(self):
        return self._exp_geodesic_ivp_test_data(
            self.metric_args_list,
            self.space_list,
            self.shape_list,
            self.n_tangent_vecs_list,
            self.n_points_list,
            rtol=gs.rtol * 10000,
            atol=gs.atol * 10000,
        )

    def parallel_transport_ivp_is_isometry_test_data(self):
        return self._parallel_transport_ivp_is_isometry_test_data(
            self.metric_args_list,
            self.space_list,
            self.shape_list,
            self.n_tangent_vecs_list,
            is_tangent_atol=gs.atol * 1000,
            atol=gs.atol * 100,
        )

    def parallel_transport_bvp_is_isometry_test_data(self):
        return self._parallel_transport_bvp_is_isometry_test_data(
            self.metric_args_list,
            self.space_list,
            self.shape_list,
            self.n_tangent_vecs_list,
            is_tangent_atol=gs.atol * 100,
            atol=gs.atol * 100,
        )

    def dist_is_symmetric_test_data(self):
        return self._dist_is_symmetric_test_data(
            self.metric_args_list,
            self.space_list,
            self.n_points_a_list,
            self.n_points_b_list,
        )

    def dist_is_positive_test_data(self):
        return self._dist_is_positive_test_data(
            self.metric_args_list,
            self.space_list,
            self.n_points_a_list,
            self.n_points_b_list,
        )

    def squared_dist_is_positive_test_data(self):
        return self._squared_dist_is_positive_test_data(
            self.metric_args_list,
            self.space_list,
            self.n_points_a_list,
            self.n_points_b_list,
        )

    def dist_is_norm_of_log_test_data(self):
        return self._dist_is_norm_of_log_test_data(
            self.metric_args_list,
            self.space_list,
            self.n_points_a_list,
            self.n_points_b_list,
        )

    def dist_point_to_itself_is_zero_test_data(self):
        return self._dist_point_to_itself_is_zero_test_data(
            self.metric_args_list, self.space_list, self.n_points_list)

    def inner_product_is_symmetric_test_data(self):
        return self._inner_product_is_symmetric_test_data(
            self.metric_args_list,
            self.space_list,
            self.shape_list,
            self.n_tangent_vecs_list,
        )

    def triangle_inequality_of_dist_test_data(self):
        return self._triangle_inequality_of_dist_test_data(
            self.metric_args_list, self.space_list, self.n_points_list)

    def l2_metric_inner_product_vectorization_test_data(self):
        smoke_data = [
            dict(
                l2_metric=self.l2_metric_s2,
                times=self.times,
                landmark_sets=self.n_landmark_sets,
                landmarks_a=self.landmark_set_a,
                landmarks_b=self.landmark_set_b,
                landmarks_c=self.landmark_set_c,
            )
        ]
        return self.generate_tests(smoke_data)

    def l2_metric_exp_vectorization_test_data(self):
        smoke_data = [
            dict(
                l2_metric=self.l2_metric_s2,
                times=self.times,
                landmarks_a=self.landmark_set_a,
                landmarks_b=self.landmark_set_b,
                landmarks_c=self.landmark_set_c,
            )
        ]
        return self.generate_tests(smoke_data)

    def l2_metric_log_vectorization_test_data(self):
        smoke_data = [
            dict(
                l2_metric=self.l2_metric_s2,
                times=self.times,
                landmarks_a=self.landmark_set_a,
                landmarks_b=self.landmark_set_b,
                landmarks_c=self.landmark_set_c,
            )
        ]
        return self.generate_tests(smoke_data)

    def l2_metric_geodesic_test_data(self):
        smoke_data = [
            dict(
                l2_metric=self.l2_metric_s2,
                times=self.times,
                n_sampling_points=self.n_sampling_points,
                landmarks_a=self.landmark_set_a,
                landmarks_b=self.landmark_set_b,
            )
        ]
        return self.generate_tests(smoke_data)
Пример #28
0
def main():
    r"""Compute and visualize a geodesic regression on the SE(2).

    The generative model of the data is:
    :math:`Z = Exp_{\beta_0}(\beta_1.X)` and :math:`Y = Exp_Z(\epsilon)`
    where:
    - :math:`Exp` denotes the Riemannian exponential,
    - :math:`\beta_0` is called the intercept,
    - :math:`\beta_1` is called the coefficient,
    - :math:`\epsilon \sim N(0, 1)` is a standard Gaussian noise,
    - :math:`X` is the input, :math:`Y` is the target.
    """
    # Generate noise-free data
    n_samples = 20
    X = gs.random.normal(size=(n_samples, ))
    X -= gs.mean(X)

    intercept = SPACE.random_point()
    coef = SPACE.to_tangent(5.0 * gs.random.rand(3, 3), intercept)
    y = METRIC.exp(X[:, None, None] * coef[None], intercept)

    # Generate normal noise in the Lie algebra
    normal_noise = gs.random.normal(size=(n_samples, 3))
    normal_noise = SPACE.lie_algebra.matrix_representation(normal_noise)
    noise = SPACE.tangent_translation_map(y)(normal_noise) / gs.pi

    rss = gs.sum(METRIC.squared_norm(noise, y)) / n_samples

    # Add noise
    y = METRIC.exp(noise, y)

    # True noise level and R2
    estimator = FrechetMean(METRIC)
    estimator.fit(y)
    variance_ = variance(y, estimator.estimate_, metric=METRIC)
    r2 = 1 - rss / variance_

    # Fit geodesic regression
    gr = GeodesicRegression(
        SPACE,
        metric=METRIC,
        center_X=False,
        method="riemannian",
        max_iter=100,
        init_step_size=0.1,
        verbose=True,
        initialization="frechet",
    )
    gr.fit(X, y, compute_training_score=True)

    intercept_hat, beta_hat = gr.intercept_, gr.coef_

    # Measure Mean Squared Error
    mse_intercept = METRIC.squared_dist(intercept_hat, intercept)
    mse_beta = METRIC.squared_norm(
        METRIC.parallel_transport(beta_hat, intercept_hat,
                                  METRIC.log(intercept_hat, intercept)) - coef,
        intercept,
    )

    # Measure goodness of fit
    r2_hat = gr.training_score_

    print(f"MSE on the intercept: {mse_intercept:.2e}")
    print(f"MSE on the initial velocity beta: {mse_beta:.2e}")
    print(f"Determination coefficient: R^2={r2_hat:.2f}")
    print(f"True R^2: {r2:.2f}")

    # Plot
    fitted_data = gr.predict(X)
    fig = plt.figure(figsize=(8, 8))
    ax = fig.add_subplot(111)
    sphere_visu = visualization.SpecialEuclidean2()
    ax = sphere_visu.set_ax(ax=ax)

    path = METRIC.geodesic(initial_point=intercept_hat,
                           initial_tangent_vec=beta_hat)
    regressed_geodesic = path(gs.linspace(min(X), max(X), 100))

    sphere_visu.draw_points(ax, y, marker="o", c="black")
    sphere_visu.draw_points(ax, fitted_data, marker="o", c="gray")
    sphere_visu.draw_points(ax, gs.array([intercept]), marker="x", c="r")
    sphere_visu.draw_points(ax,
                            gs.array([intercept_hat]),
                            marker="o",
                            c="green")

    ax.plot(regressed_geodesic[:, 0, 2], regressed_geodesic[:, 1, 2], c="gray")
    plt.show()
Пример #29
0
 def test_ball_geodesic(self):
     path_function =\
         self.manifold.metric.geodesic(gs.array([0.1, 0.1]),
                                       gs.array([0.2, 0.2]))
     steps = gs.array(gs.linspace(-1000., 1000., 10000))
     path_function(steps)
Пример #30
0
def plot_modulation_factor(n_samples, dim, n_expectation=1000, n_theta=20):
    """Plot the modulation factor curve w.r.t. the dispersion.

    Plot the curve of modulation factor on the convergence of the
    empirical Fréchet mean as a function of the radius of the bubble
    distribution and for n_samples points on the sphere S_dim
    embedded in R^{dim+1}.

    Parameters
    ----------
    n_samples : int
        Number of samples to draw
    dim : int
        Dimension of the sphere (embedded in R^{dim+1}).
    n_expectation: int, optional (defaults to 1000)
        Number of computations for approximating the expectation.
    n_theta: int, optional (defaults to 20)
        Number of sampled radii for the bubble distribution.

    Returns
    -------
    matplolib figure
    """
    theta = gs.linspace(0.000001, gs.pi / 2.0 - 0.000001, n_theta)
    measured_modulation_factor = []
    error = []
    small_var_modulation_factor = []
    asymptotic_modulation_factor = []
    for theta_i in theta:
        (var, std_var) = modulation_factor(n_samples,
                                           theta_i,
                                           dim,
                                           n_expectation=n_expectation)
        measured_modulation_factor.append(var)
        error.append(std_var)
        logging.info('{} {} {} {}\n'.format(n_samples, theta_i, var, std_var))
        small_var_modulation_factor.append(1.0 + 2.0 / 3.0 * theta_i**2 *
                                           (1.0 - 1.0 / dim) *
                                           (1.0 - 1.0 / n_samples))
        asymptotic_modulation_factor.append(asymptotic_modulation(
            dim, theta_i))
    plt.figure()
    plt.errorbar(theta,
                 measured_modulation_factor,
                 yerr=error,
                 color='r',
                 label='Measured')
    plt.plot(theta,
             small_var_modulation_factor,
             'g',
             label='Small variance prediction')
    plt.plot(theta,
             asymptotic_modulation_factor,
             'grey',
             label='Asymptotic prediction')
    plt.xlabel(r'Standard deviation $\theta$')
    plt.ylabel(r'Modulation factor $\alpha$')
    plt.title('Convergence rate modulation factor, '
              'sphere dim={1}, n={0}'.format(n_samples, dim))
    plt.legend(loc='best')
    plt.draw()
    plt.pause(0.01)
    return plt