def exp_domain(self, tangent_vec, base_point): """Compute the domain of the Euclidean exponential map. Compute the real interval of time where the Euclidean geodesic starting at point `base_point` in direction `tangent_vec` is defined. Parameters ---------- tangent_vec : array-like, shape=[n_samples, n, n] base_point : array-like, shape=[n_samples, n, n] Returns ------- exp_domain : array-like, shape=[n_samples, 2] """ base_point = gs.to_ndarray(base_point, to_ndim=3) tangent_vec = gs.to_ndarray(tangent_vec, to_ndim=3) invsqrt_base_point = gs.linalg.powerm(base_point, -.5) reduced_vec = gs.matmul(invsqrt_base_point, tangent_vec) reduced_vec = gs.matmul(reduced_vec, invsqrt_base_point) eigvals = gs.linalg.eigvalsh(reduced_vec) min_eig = gs.amin(eigvals, axis=1) max_eig = gs.amax(eigvals, axis=1) inf_value = gs.where(max_eig <= 0, -math.inf, -1 / max_eig) inf_value = gs.to_ndarray(inf_value, to_ndim=2) sup_value = gs.where(min_eig >= 0, math.inf, -1 / min_eig) sup_value = gs.to_ndarray(sup_value, to_ndim=2) domain = gs.concatenate((inf_value, sup_value), axis=1) return domain
def exp_domain(tangent_vec, base_point): """Compute the domain of the Euclidean exponential map. Compute the real interval of time where the Euclidean geodesic starting at point `base_point` in direction `tangent_vec` is defined. Parameters ---------- tangent_vec : array-like, shape=[..., n, n] Tangent vector at base point. base_point : array-like, shape=[..., n, n] Base point. Returns ------- exp_domain : array-like, shape=[..., 2] Interval of time where the geodesic is defined. """ invsqrt_base_point = SymmetricMatrices.powerm(base_point, -.5) reduced_vec = gs.matmul(invsqrt_base_point, tangent_vec) reduced_vec = gs.matmul(reduced_vec, invsqrt_base_point) eigvals = gs.linalg.eigvalsh(reduced_vec) min_eig = gs.amin(eigvals, axis=1) max_eig = gs.amax(eigvals, axis=1) inf_value = gs.where( max_eig <= 0., gs.array(-math.inf), - 1. / max_eig) inf_value = gs.to_ndarray(inf_value, to_ndim=2) sup_value = gs.where( min_eig >= 0., gs.array(-math.inf), - 1. / min_eig) sup_value = gs.to_ndarray(sup_value, to_ndim=2) domain = gs.concatenate((inf_value, sup_value), axis=1) return domain
def diameter(self, points): """Give the distance between two farthest points. Distance between the two points that are farthest away from each other in points. Parameters ---------- points : array-like, shape=[..., dim] Points. Returns ------- diameter : float Distance between two farthest points. """ diameter = 0.0 n_points = points.shape[0] for i in range(n_points - 1): dist_to_neighbors = self.dist(points[i, :], points[i + 1:, :]) dist_to_farthest_neighbor = gs.amax(dist_to_neighbors) diameter = gs.maximum(diameter, dist_to_farthest_neighbor) return diameter
def plot(self, points, ax=None, space=None, **point_draw_kwargs): if space == "SE3_GROUP": ax_s = AX_SCALE * gs.amax(gs.abs(points[:, 3:6])) elif space == "SO3_GROUP": ax_s = AX_SCALE * gs.amax(gs.abs(points[:, :3])) ax_s = float(ax_s) bounds = (-ax_s, ax_s) plt.setp( ax, xlim=bounds, ylim=bounds, zlim=bounds, xlabel="X", ylabel="Y", zlabel="Z", ) trihedrons = convert_to_trihedron(points, space=space) for t in trihedrons: t.draw(ax, **point_draw_kwargs)
def diameter(self, points): """ Distance between the two points that are farthest away from each other in points. """ diameter = 0.0 n_points = points.shape[0] for i in range(n_points - 1): dist_to_neighbors = self.dist(points[i, :], points[i + 1:, :]) dist_to_farthest_neighbor = gs.amax(dist_to_neighbors) diameter = gs.maximum(diameter, dist_to_farthest_neighbor) return diameter
def exp_domain(self, tangent_vec, base_point): base_point = gs.to_ndarray(base_point, to_ndim=3) tangent_vec = gs.to_ndarray(tangent_vec, to_ndim=3) invsqrt_base_point = gs.linalg.powerm(base_point, -.5) reduced_vec = gs.matmul(invsqrt_base_point, tangent_vec) reduced_vec = gs.matmul(reduced_vec, invsqrt_base_point) eigvals = gs.linalg.eigvalsh(reduced_vec) min_eig = gs.amin(eigvals, axis=1) max_eig = gs.amax(eigvals, axis=1) inf_value = gs.where(max_eig <= 0, -math.inf, -1 / max_eig) inf_value = gs.to_ndarray(inf_value, to_ndim=2) sup_value = gs.where(min_eig >= 0, math.inf, -1 / min_eig) sup_value = gs.to_ndarray(sup_value, to_ndim=2) domain = gs.concatenate((inf_value, sup_value), axis=1) return domain
def plot(points, ax=None, space=None, **point_draw_kwargs): """Plot trihedrons.""" ax_s = AX_SCALE * gs.amax(gs.abs(points[:, :3])) ax_s = float(ax_s) bounds = (-ax_s, ax_s) plt.setp( ax, xlim=bounds, ylim=bounds, zlim=bounds, xlabel="X", ylabel="Y", zlabel="Z", ) trihedrons = convert_to_trihedron(points, space=space) for t in trihedrons: t.draw(ax, **point_draw_kwargs)
def diameter(self, points): """Compute distance between the two points farthest from each other. Parameters ---------- points Returns ------- diameter """ diameter = 0.0 n_points = points.shape[0] for i in range(n_points - 1): dist_to_neighbors = self.dist(points[i, :], points[i + 1:, :]) dist_to_farthest_neighbor = gs.amax(dist_to_neighbors) diameter = gs.maximum(diameter, dist_to_farthest_neighbor) return diameter
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 plot(points, ax=None, space=None, point_type='extrinsic', **point_draw_kwargs): """Plot points in the 3D Special Euclidean Group. Plot points in the 3D Special Euclidean Group, by showing them as trihedrons. """ if space not in IMPLEMENTED: raise NotImplementedError( 'The plot function is not implemented' ' for space {}. The spaces available for visualization' ' are: {}.'.format(space, IMPLEMENTED)) if points is None: raise ValueError("No points given for plotting.") points = gs.to_ndarray(points, to_ndim=2) if space in ('SO3_GROUP', 'SE3_GROUP'): if ax is None: ax = plt.subplot(111, projection='3d') if space == 'SE3_GROUP': ax_s = AX_SCALE * gs.amax(gs.abs(points[:, 3:6])) elif space == 'SO3_GROUP': ax_s = AX_SCALE * gs.amax(gs.abs(points[:, :3])) plt.setp(ax, xlim=(-ax_s, ax_s), ylim=(-ax_s, ax_s), zlim=(-ax_s, ax_s), xlabel='X', ylabel='Y', zlabel='Z') trihedrons = convert_to_trihedron(points, space=space) for t in trihedrons: t.draw(ax, **point_draw_kwargs) elif space == 'S1': circle = Circle() ax = circle.set_ax(ax=ax) circle.add_points(points) circle.draw(ax, **point_draw_kwargs) elif space == 'S2': sphere = Sphere() ax = sphere.set_ax(ax=ax) sphere.add_points(points) sphere.draw(ax, **point_draw_kwargs) elif space == 'H2_poincare_disk': poincare_disk = PoincareDisk(point_type=point_type) ax = poincare_disk.set_ax(ax=ax) poincare_disk.add_points(points) poincare_disk.draw(ax, **point_draw_kwargs) elif space == 'poincare_polydisk': n_disks = points.shape[1] poincare_poly_disk = PoincarePolyDisk(point_type=point_type, n_disks=n_disks) n_columns = gs.ceil(n_disks**0.5) n_rows = gs.ceil(n_disks / n_columns) axis_list = [] for i_disk in range(n_disks): axis_list.append(ax.add_subplot(n_rows, n_columns, i_disk + 1)) for i_disk, ax in enumerate(axis_list): ax = poincare_poly_disk.set_ax(ax=ax) poincare_poly_disk.clear_points() poincare_poly_disk.add_points(points[:, i_disk, ...]) poincare_poly_disk.draw(ax, **point_draw_kwargs) elif space == 'H2_poincare_half_plane': poincare_half_plane = PoincareHalfPlane() ax = poincare_half_plane.set_ax(ax=ax) poincare_half_plane.add_points(points) poincare_half_plane.draw(ax, **point_draw_kwargs) elif space == 'H2_klein_disk': klein_disk = KleinDisk() ax = klein_disk.set_ax(ax=ax) klein_disk.add_points(points) klein_disk.draw(ax, **point_draw_kwargs) return ax
def plot(points, ax=None, space=None, point_type=None, **point_draw_kwargs): """Plot points in one of the implemented manifolds. The implemented manifolds are: - the special orthogonal group SO(3) - the special Euclidean group SE(3) - the circle S1 and the sphere S2 - the hyperbolic plane (the Poincare disk, the Poincare half plane and the Klein disk) - the Poincare polydisk - the Kendall shape space of 2D triangles - the Kendall shape space of 3D triangles Parameters ---------- points : array-like, shape=[..., dim] Points to be plotted. space: str, optional, {'SO3_GROUP', 'SE3_GROUP', 'S1', 'S2', 'H2_poincare_disk', 'H2_poincare_half_plane', 'H2_klein_disk', 'poincare_polydisk', 'S32', 'M32', 'S33', 'M33'} point_type: str, optional, {'extrinsic', 'ball', 'half-space', 'pre-shape'} """ if space not in IMPLEMENTED: raise NotImplementedError( 'The plot function is not implemented' ' for space {}. The spaces available for visualization' ' are: {}.'.format(space, IMPLEMENTED)) if points is None: raise ValueError("No points given for plotting.") if points.ndim < 2: points = gs.expand_dims(points, 0) if space in ('SO3_GROUP', 'SE3_GROUP'): if ax is None: ax = plt.subplot(111, projection='3d') if space == 'SE3_GROUP': ax_s = AX_SCALE * gs.amax(gs.abs(points[:, 3:6])) elif space == 'SO3_GROUP': ax_s = AX_SCALE * gs.amax(gs.abs(points[:, :3])) ax_s = float(ax_s) bounds = (-ax_s, ax_s) plt.setp(ax, xlim=bounds, ylim=bounds, zlim=bounds, xlabel='X', ylabel='Y', zlabel='Z') trihedrons = convert_to_trihedron(points, space=space) for t in trihedrons: t.draw(ax, **point_draw_kwargs) elif space == 'S1': circle = Circle() ax = circle.set_ax(ax=ax) circle.add_points(points) circle.draw(ax, **point_draw_kwargs) elif space == 'S2': sphere = Sphere() ax = sphere.set_ax(ax=ax) sphere.add_points(points) sphere.draw(ax, **point_draw_kwargs) elif space == 'H2_poincare_disk': if point_type is None: point_type = 'extrinsic' poincare_disk = PoincareDisk(point_type=point_type) ax = poincare_disk.set_ax(ax=ax) poincare_disk.add_points(points) poincare_disk.draw(ax, **point_draw_kwargs) plt.axis('off') elif space == 'poincare_polydisk': if point_type is None: point_type = 'extrinsic' n_disks = points.shape[1] poincare_poly_disk = PoincarePolyDisk(point_type=point_type, n_disks=n_disks) n_columns = int(gs.ceil(n_disks**0.5)) n_rows = int(gs.ceil(n_disks / n_columns)) axis_list = [] for i_disk in range(n_disks): axis_list.append(ax.add_subplot(n_rows, n_columns, i_disk + 1)) for i_disk, one_ax in enumerate(axis_list): ax = poincare_poly_disk.set_ax(ax=one_ax) poincare_poly_disk.clear_points() poincare_poly_disk.add_points(points[:, i_disk, ...]) poincare_poly_disk.draw(ax, **point_draw_kwargs) elif space == 'H2_poincare_half_plane': if point_type is None: point_type = 'half-space' poincare_half_plane = PoincareHalfPlane(point_type=point_type) ax = poincare_half_plane.set_ax(points=points, ax=ax) poincare_half_plane.add_points(points) poincare_half_plane.draw(ax, **point_draw_kwargs) elif space == 'H2_klein_disk': klein_disk = KleinDisk() ax = klein_disk.set_ax(ax=ax) klein_disk.add_points(points) klein_disk.draw(ax, **point_draw_kwargs) elif space == 'SE2_GROUP': plane = SpecialEuclidean2() ax = plane.set_ax(ax=ax) plane.add_points(points) plane.draw(ax, **point_draw_kwargs) elif space == 'S32': sphere = KendallSphere() sphere.add_points(points) sphere.draw() sphere.draw_points() ax = sphere.ax elif space == 'M32': sphere = KendallSphere(point_type='extrinsic') sphere.add_points(points) sphere.draw() sphere.draw_points() ax = sphere.ax elif space == 'S33': disk = KendallDisk() disk.add_points(points) disk.draw() disk.draw_points() ax = disk.ax elif space == 'M33': disk = KendallDisk(point_type='extrinsic') disk.add_points(points) disk.draw() disk.draw_points() ax = disk.ax return ax
def plot(points, ax=None, space=None, **point_draw_kwargs): """ Plot points in the 3D Special Euclidean Group, by showing them as trihedrons. """ if space not in IMPLEMENTED: raise NotImplementedError( 'The plot function is not implemented' ' for space {}. The spaces available for visualization' ' are: {}.'.format(space, IMPLEMENTED)) if points is None: raise ValueError("No points given for plotting.") points = gs.to_ndarray(points, to_ndim=2) if space in ('SO3_GROUP', 'SE3_GROUP'): if ax is None: ax = plt.subplot(111, projection='3d') if space == 'SE3_GROUP': ax_s = AX_SCALE * gs.amax(gs.abs(points[:, 3:6])) elif space == 'SO3_GROUP': ax_s = AX_SCALE * gs.amax(gs.abs(points[:, :3])) plt.setp(ax, xlim=(-ax_s, ax_s), ylim=(-ax_s, ax_s), zlim=(-ax_s, ax_s), xlabel='X', ylabel='Y', zlabel='Z') trihedrons = convert_to_trihedron(points, space=space) for t in trihedrons: t.draw(ax, **point_draw_kwargs) elif space == 'S1': circle = Circle() ax = circle.set_ax(ax=ax) circle.add_points(points) circle.draw(ax, **point_draw_kwargs) elif space == 'S2': sphere = Sphere() ax = sphere.set_ax(ax=ax) sphere.add_points(points) sphere.draw(ax, **point_draw_kwargs) elif space == 'H2_poincare_disk': poincare_disk = PoincareDisk() ax = poincare_disk.set_ax(ax=ax) poincare_disk.add_points(points) poincare_disk.draw(ax, **point_draw_kwargs) elif space == 'H2_poincare_half_plane': poincare_half_plane = PoincareHalfPlane() ax = poincare_half_plane.set_ax(ax=ax) poincare_half_plane.add_points(points) poincare_half_plane.draw(ax, **point_draw_kwargs) elif space == 'H2_klein_disk': klein_disk = KleinDisk() ax = klein_disk.set_ax(ax=ax) klein_disk.add_points(points) klein_disk.draw(ax, **point_draw_kwargs) return ax