def belongs(self, point, atol=gs.atol): """Check whether point is of the form rotation, translation. Parameters ---------- point : array-like, shape=[..., n, n]. Point to be checked. atol : float Tolerance threshold. Returns ------- belongs : array-like, shape=[...,] Boolean denoting if point belongs to the group. """ n = self.n belongs = Matrices(n + 1, n + 1).belongs(point) if gs.all(belongs): rotation = point[..., :n, :n] belongs = self.rotations.belongs(rotation, atol=atol) last_line_except_last_term = point[..., n:, :-1] all_but_last_zeros = ~gs.any(last_line_except_last_term, axis=(-2, -1)) belongs = gs.logical_and(belongs, all_but_last_zeros) last_term = point[..., n, n] belongs = gs.logical_and(belongs, gs.isclose(last_term, 1., atol=atol)) return belongs
def belongs(self, point): """Check whether point is of the form rotation, translation. Parameters ---------- point : array-like, shape=[..., n, n]. Point to be checked. Returns ------- belongs : array-like, shape=[...,] Boolean denoting if point belongs to the group. """ point_dim1, point_dim2 = point.shape[-2:] belongs = (point_dim1 == point_dim2 == self.n + 1) rotation = point[..., :self.n, :self.n] rot_belongs = self.rotations.belongs(rotation) belongs = gs.logical_and(belongs, rot_belongs) last_line_except_last_term = point[..., self.n:, :-1] all_but_last_zeros = ~gs.any(last_line_except_last_term, axis=(-2, -1)) belongs = gs.logical_and(belongs, all_but_last_zeros) last_term = point[..., self.n:, self.n:] belongs = gs.logical_and(belongs, gs.all(last_term == 1, axis=(-2, -1))) if point.ndim == 2: return gs.squeeze(belongs) return gs.flatten(belongs)
def belongs(self, mat, atol=ATOL): """Evaluate if the rotation part of mat is a skew-symmetric matrix. Parameters ---------- mat : array-like, shape=[..., n + 1, n + 1] Square matrix to check. atol : float Tolerance for the equality evaluation. Optional, default: backend atol. Returns ------- belongs : array-like, shape=[...,] Boolean evaluating if rotation part of matrix is skew symmetric. """ point_dim1, point_dim2 = mat.shape[-2:] belongs = point_dim1 == point_dim2 == self.n + 1 rotation = mat[..., :self.n, :self.n] rot_belongs = self.skew.belongs(rotation, atol=atol) belongs = gs.logical_and(belongs, rot_belongs) last_line = mat[..., -1, :] all_zeros = ~gs.any(last_line, axis=-1) belongs = gs.logical_and(belongs, all_zeros) return belongs
def belongs(self, point, atol=TOLERANCE): """Test if a point belongs to the pre-shape space. This tests whether the point is centered and whether the point's Frobenius norm is 1. Parameters ---------- point : array-like, shape=[..., k_landmarks, m_ambient] Point in Matrices space. atol : float Tolerance at which to evaluate norm == 1 and mean == 0. Optional, default: 1e-6. Returns ------- belongs : array-like, shape=[...,] Boolean evaluating if point belongs to the pre-shape space. """ shape = point.shape[-2:] == (self.k_landmarks, self.m_ambient) frob_norm = self.embedding_metric.norm(point) diff = gs.abs(frob_norm - 1) is_centered = gs.logical_and(self.is_centered(point, atol), shape) return gs.logical_and( gs.less_equal(diff, atol), is_centered)
def _is_in_lie_algebra(self, tangent_vec, atol=TOLERANCE): """Project vector rotation part onto skew-symmetric matrices.""" point_dim1, point_dim2 = tangent_vec.shape[-2:] belongs = (point_dim1 == point_dim2 == self.n + 1) rotation = tangent_vec[..., :self.n, :self.n] rot_belongs = self.is_skew_symmetric(rotation, atol=atol) belongs = gs.logical_and(belongs, rot_belongs) last_line = tangent_vec[..., -1, :] all_zeros = ~gs.any(last_line, axis=-1) belongs = gs.logical_and(belongs, all_zeros) return belongs
def belongs(self, point, point_type=None): """Evaluate if a point belongs to SE(n). Parameters ---------- point : array-like, shape=[n_samples, {dim, [n + 1, n + 1]}] the point of which to check whether it belongs to SE(n) point_type : str, {'vector', 'matrix'}, optional default: self.default_point_type Returns ------- belongs : array-like, shape=[n_samples, 1] array of booleans indicating whether point belongs to SE(n) """ if point_type == 'vector': n_points, vec_dim = gs.shape(point) belongs = vec_dim == self.dimension belongs = gs.tile([belongs], (point.shape[0], )) belongs = gs.logical_and(belongs, self.rotations.belongs(point[:, :self.n])) return gs.flatten(belongs) if point_type == 'matrix': n_points, point_dim1, point_dim2 = point.shape belongs = (point_dim1 == point_dim2 == self.n + 1) belongs = [belongs] * n_points rotation = point[:, :self.n, :self.n] rot_belongs = self.rotations.belongs(rotation, point_type=point_type) belongs = gs.logical_and(belongs, rot_belongs) last_line_except_last_term = point[:, self.n:, :-1] all_but_last_zeros = ~gs.any(last_line_except_last_term, axis=(1, 2)) belongs = gs.logical_and(belongs, all_but_last_zeros) last_term = point[:, self.n:, self.n:] belongs = gs.logical_and(belongs, gs.all(last_term == 1, axis=(1, 2))) return gs.flatten(belongs) raise ValueError('Invalid point_type, expected \'vector\' or ' '\'matrix\'.')
def is_tangent(self, vector, base_point=None, atol=gs.atol): r"""Check if a vector is tangent to the manifold at the base point. Check if the (n,n)-matrix :math: `Y` is symmetric and verifies the relation :math: PY + YP = Y where :math: `P` represents the base point and :math: `Y` the vector. Parameters ---------- vector : array-like, shape=[..., n, n] Matrix to be checked. base_point : array-like, shape=[..., n, n] Base point. atol : int Optional, default: 1e-5. Returns ------- belongs : array-like, shape=[...,] Boolean evaluating if `vector` is tangent to the Grassmannian at `base_point`. """ diff = Matrices.mul(base_point, vector) + Matrices.mul( vector, base_point) - vector is_close = gs.all(gs.isclose(diff, 0., atol=atol)) return gs.logical_and(Matrices.is_symmetric(vector), is_close)
def belongs(self, mat, atol=TOLERANCE): """Check if a matrix is symmetric and invertible.""" is_symmetric = super(SPDMatrices, self).belongs(mat, atol) eigvalues, _ = gs.linalg.eigh(mat) is_positive = gs.all(eigvalues > 0, axis=-1) belongs = gs.logical_and(is_symmetric, is_positive) return belongs
def belongs(self, point, atol=gs.atol): """Evaluate if a point belongs to the manifold of Dirichlet distributions. Check that point defines parameters for a Dirichlet distributions, i.e. belongs to the positive quadrant of the Euclidean space. Parameters ---------- point : array-like, shape=[..., dim] Point to be checked. atol : float Tolerance to evaluate positivity. Optional, default: gs.atol Returns ------- belongs : array-like, shape=[...,] Boolean indicating whether point represents a Dirichlet distribution. """ point_dim = point.shape[-1] belongs = point_dim == self.dim belongs = gs.logical_and( belongs, gs.all(point >= atol, axis=-1)) return belongs
def belongs(mat, atol=TOLERANCE): """Check if a matrix is symmetric and invertible.""" is_symmetric = GeneralLinear.is_symmetric(mat) eigvalues, _ = gs.linalg.eigh(mat) is_positive = gs.all(eigvalues > 0, axis=-1) belongs = gs.logical_and(is_symmetric, is_positive) return belongs
def is_tangent(self, vector, base_point, atol=gs.atol): """Check whether the vector is tangent at base_point. Parameters ---------- vector : array-like, shape=[..., dim] Vector. base_point : array-like, shape=[..., dim] Point on the manifold. atol : float Absolute tolerance. Optional, default: backend atol. Returns ------- is_tangent : bool Boolean denoting if vector is a tangent vector at the base point. """ belongs = self.embedding_space.is_tangent(vector, base_point, atol) tangent_sub_applied = self.tangent_submersion(vector, base_point) constraint = gs.isclose(tangent_sub_applied, 0.0, atol=atol) value = self.value if value.ndim == 2: constraint = gs.all(constraint, axis=(-2, -1)) elif value.ndim == 1: constraint = gs.all(constraint, axis=-1) return gs.logical_and(belongs, constraint)
def belongs(self, point): """Test if a matrix is invertible and of the right size.""" point_shape = point.shape mat_dim_1, mat_dim_2 = point_shape[-2], point_shape[-1] det = gs.linalg.det(point) return gs.logical_and(mat_dim_1 == self.n and mat_dim_2 == self.n, det != 0.)
def is_isometry(tan_a, trans_a, endpoint): is_tangent = gs.isclose( sphere.metric.inner_product(endpoint, trans_a), 0., atol=1e-6) is_equinormal = gs.isclose( gs.linalg.norm(trans_a, axis=-1), gs.linalg.norm(tan_a, axis=-1)) return gs.logical_and(is_tangent, is_equinormal)
def belongs(self, point, atol=gs.atol): """Evaluate if a point belongs to the manifold. Parameters ---------- point : array-like, shape=[..., dim] Point to evaluate. atol : float Absolute tolerance. Optional, default: backend atol. Returns ------- belongs : array-like, shape=[...,] Boolean evaluating if point belongs to the manifold. """ belongs = self.embedding_space.belongs(point, atol) if not gs.any(belongs): return belongs value = self.value constraint = gs.isclose(self.submersion(point), value, atol=atol) if value.ndim == 2: constraint = gs.all(constraint, axis=(-2, -1)) elif value.ndim == 1: constraint = gs.all(constraint, axis=-1) return gs.logical_and(belongs, constraint)
def belongs(self, point): """Test if a matrix is invertible and of the right size.""" point = gs.to_ndarray(point, to_ndim=3) _, mat_dim_1, mat_dim_2 = point.shape det = gs.linalg.det(point) return gs.logical_and( mat_dim_1 == self.n and mat_dim_2 == self.n, gs.where(det != 0., gs.array(True), gs.array(False)))
def belongs(self, point): """Evaluate if a point belongs to SE(2) or SE(3). Parameters ---------- point : array-like, shape=[..., dimension] Point to check. Returns ------- belongs : array-like, shape=[...,] Boolean indicating whether point belongs to SE(2) or SE(3). """ point_dim = point.shape[-1] point_ndim = point.ndim belongs = gs.logical_and(point_dim == self.dim, point_ndim < 3) belongs = gs.logical_and( belongs, self.rotations.belongs(point[..., :self.rotations.dim])) return belongs
def belongs(self, point): """Evaluate if a point belongs to SE(3). Parameters ---------- point : array-like, shape=[..., 3] The point of which to check whether it belongs to SE(3). Returns ------- belongs : array-like, shape=[..., 1] Boolean indicating whether point belongs to SE(3). """ point_dim = point.shape[-1] point_ndim = point.ndim belongs = gs.logical_and(point_dim == self.dim, point_ndim < 3) belongs = gs.logical_and(belongs, self.rotations.belongs(point[..., :self.n])) return belongs
def test_load_optical_nerves(self): """Test that optical nerves belong to space of landmarks.""" data, labels, monkeys = data_utils.load_optical_nerves() result = data.shape n_monkeys = 11 n_eyes_per_monkey = 2 k_landmarks = 5 dim = 3 expected = (n_monkeys * n_eyes_per_monkey, k_landmarks, dim) self.assertAllClose(result, expected) landmarks_space = Landmarks(ambient_manifold=Euclidean(dim=dim), k_landmarks=k_landmarks) result = landmarks_space.belongs(data) self.assertTrue(gs.all(result)) result = gs.logical_and(labels >= 0, labels <= 1) self.assertTrue(gs.all(result)) result = gs.logical_and(monkeys >= 0, monkeys <= 11) self.assertTrue(gs.all(result))
def test_load_connectomes(self): """Test that the connectomes belong to SPD.""" spd = SPDMatrices(28) data, _, _ = data_utils.load_connectomes(as_vectors=True) result = data.shape expected = (86, 27 * 14) self.assertAllClose(result, expected) data, _, labels = data_utils.load_connectomes() result = spd.belongs(data) self.assertTrue(gs.all(result)) result = gs.logical_and(labels >= 0, labels <= 1) self.assertTrue(gs.all(result))
def belongs(self, mat, atol=gs.atol): r"""Check if the matrix belongs to the space. Parameters ---------- mat : array-like, shape=[..., n, n] Matrix to be checked. atol : float Tolerance. Optional, default: backend atol. Returns ------- belongs : array-like, shape=[...,] Boolean denoting if mat is an SPD matrix. """ is_symmetric = self.sym.belongs(mat, atol) eigvalues = gs.linalg.eigvalsh(mat) is_semipositive = gs.all(eigvalues > -atol, axis=-1) is_rankk = gs.sum(gs.where(eigvalues < atol, 0, 1), axis=-1) == self.rank belongs = gs.logical_and(gs.logical_and(is_symmetric, is_semipositive), is_rankk) return belongs
def belongs(self, mat, atol=TOLERANCE): """Check if mat belongs to the vector space of symmetric matrices. Parameters ---------- mat : array-like, shape=[..., n, n] Matrix to check. Returns ------- belongs : array-like, shape=[...,] Boolean evaluating if mat is a symmetric matrix. """ check_shape = self.embedding_manifold.belongs(mat) return gs.logical_and(check_shape, Matrices.is_symmetric(mat, atol))
def belongs(self, point, atol=gs.atol): r"""Check if the matrix belongs to `math:`R_*^{m\times n}`. Parameters ---------- point : array-like, shape=[..., m, n] Matrix to be checked. Returns ------- belongs : Boolean denoting if point is in `math:`R_*^{m\times n}` """ has_right_size = self.ambient_space.belongs(point) has_right_rank = gs.where( gs.linalg.matrix_rank(point) == self.rank, True, False) belongs = gs.logical_and(gs.array(has_right_size), has_right_rank) return belongs
def belongs(self, point): """Evaluate if a point belongs to the upper half space. Parameters ---------- point : array-like, shape=[..., dim] Point to be checked. Returns ------- belongs : array-like, shape=[...,] Array of booleans indicating whether the corresponding points belong to the upper half space. """ point_dim = point.shape[-1] belongs = point_dim == self.dim belongs = gs.logical_and(belongs, point[..., -1] > 0.) return belongs
def belongs(self, point): """Check if a matrix is invertible and of the right shape. Parameters ---------- point : array-like, shape=[..., n, n] Matrix to be checked. Returns ------- belongs : array-like, shape=[...,] Boolean denoting if point is in GL(n). """ point_shape = point.shape mat_dim_1, mat_dim_2 = point_shape[-2], point_shape[-1] det = gs.linalg.det(point) return gs.logical_and(mat_dim_1 == self.n and mat_dim_2 == self.n, det != 0.)
def is_spd(cls, mat, atol=gs.atol): """Check if a matrix is symmetric positive definite. Parameters ---------- mat : array-like, shape=[..., n, n] Matrix. atol : float Absolute tolerance. Optional, default: backend atol. Returns ------- is_spd : array-like, shape=[...,] Boolean evaluating if the matrix is symmetric positive definite. """ is_spd = gs.logical_and(cls.is_symmetric(mat, atol), cls.is_pd(mat)) return is_spd
def test_hands(self): """Test that hands belong to space of landmarks.""" data, labels, _ = data_utils.load_hands() result = data.shape n_hands = 52 k_landmarks = 22 dim = 3 expected = (n_hands, k_landmarks, dim) self.assertAllClose(result, expected) landmarks_space = Landmarks(ambient_manifold=Euclidean(dim=3), k_landmarks=k_landmarks) result = landmarks_space.belongs(data) self.assertTrue(gs.all(result)) result = gs.logical_and(labels >= 0, labels <= 1) self.assertTrue(gs.all(result))
def belongs(self, mat, atol=gs.atol): """Evaluate if mat is a skew-symmetric matrix. Parameters ---------- mat : array-like, shape=[..., n, n] Square matrix to check. atol : float Tolerance for the equality evaluation. Optional, default: backend atol. Returns ------- belongs : array-like, shape=[...,] Boolean evaluating if matrix is skew symmetric. """ is_skew = self.is_skew_symmetric(mat=mat, atol=atol) return gs.logical_and(is_skew, super(SkewSymmetricMatrices, self).belongs(mat))
def belongs(self, mat, atol=gs.atol): """Check if a matrix is symmetric with positive eigenvalues. Parameters ---------- mat : array-like, shape=[..., n, n] Matrix to be checked. atol : float Tolerance. Optional, default: backend atol. Returns ------- belongs : array-like, shape=[...,] Boolean denoting if mat is an SPD matrix. """ is_sym = self.ambient_space.belongs(mat, atol) is_pd = Matrices.is_pd(mat) belongs = gs.logical_and(is_sym, is_pd) return belongs
def belongs(self, point, atol=gs.atol): """Evaluate if a point belongs to the upper half space. Parameters ---------- point : array-like, shape=[..., dim] Point to be checked. atol : float Absolute tolerance to evaluate positivity of the last coordinate. Returns ------- belongs : array-like, shape=[...,] Array of booleans indicating whether the corresponding points belong to the upper half space. """ point_dim = point.shape[-1] belongs = point_dim == self.dim belongs = gs.logical_and(belongs, point[..., -1] >= atol) return belongs
def belongs(self, point, atol=gs.atol): """Evaluate if a matrix is symmetric. Parameters ---------- point : array-like, shape=[.., n, n] Point to test. atol : float Tolerance to evaluate equality with the transpose. Returns ------- belongs : array-like, shape=[...,] Boolean evaluating if point belongs to the space. """ belongs = super(SymmetricMatrices, self).belongs(point) if gs.any(belongs): is_symmetric = Matrices.is_symmetric(point, atol) return gs.logical_and(belongs, is_symmetric) return belongs