def log(self, point, base_point): """Compute Riemannian logarithm of a point wrt a base point. If point_type = 'poincare' then base_point belongs to the Poincare ball and point is a vector in the Euclidean space of the same dimension as the ball. Parameters ---------- point : array-like, shape=[..., dim] Point in hyperbolic space. base_point : array-like, shape=[..., dim] Point in hyperbolic space. Returns ------- log : array-like, shape=[..., dim] Tangent vector at the base point equal to the Riemannian logarithm of point at the base point. """ add_base_point = self.mobius_add(-base_point, point) norm_add =\ gs.expand_dims(gs.linalg.norm( add_base_point, axis=-1), axis=-1) norm_base_point =\ gs.expand_dims(gs.linalg.norm( base_point, axis=-1), axis=-1) log = (1 - norm_base_point**2) * gs.arctanh(norm_add) mask_0 = gs.isclose(gs.squeeze(norm_add, axis=-1), 0.) mask_non0 = ~mask_0 add_base_point = gs.assignment( add_base_point, gs.zeros_like(add_base_point[mask_0]), mask_0) add_base_point = gs.assignment( add_base_point, add_base_point[mask_non0] / norm_add[mask_non0], mask_non0) log = gs.einsum( '...i,...j->...j', log, add_base_point) return log
def log(self, point, base_point): """Compute Riemannian logarithm of a point wrt a base point. If point_type = 'poincare' then base_point belongs to the Poincare ball and point is a vector in the Euclidean space of the same dimension as the ball. Parameters ---------- point : array-like, shape=[n_samples, dim] Point in hyperbolic space. base_point : array-like, shape=[n_samples, dim] Point in hyperbolic space. Returns ------- log : array-like, shape=[n_samples, dim] Tangent vector at the base point equal to the Riemannian logarithm of point at the base point. """ base_point = gs.to_ndarray(base_point, to_ndim=2) point = gs.to_ndarray(point, to_ndim=2) add_base_point = self.mobius_add(-base_point, point) norm_add =\ gs.expand_dims(gs.linalg.norm( add_base_point, axis=-1), axis=-1) norm_base_point =\ gs.expand_dims(gs.linalg.norm( base_point, axis=-1), axis=-1) log = (1 - norm_base_point**2) * gs.arctanh(norm_add) log = gs.einsum('...i,...j->...j', log, (add_base_point / norm_add)) mask_0 = gs.isclose(gs.squeeze(norm_add, axis=-1), 0.) if gs.any(mask_0): log[mask_0] = 0 return log
} sinch_close_0 = { "function": lambda x: gs.sinh(x) / x, "coefficients": SINHC_TAYLOR_COEFFS, } cosh_close_0 = {"function": gs.cosh, "coefficients": COSH_TAYLOR_COEFFS} inv_sinch_close_0 = { "function": lambda x: x / gs.sinh(x), "coefficients": INV_SINHC_TAYLOR_COEFFS, } inv_tanh_close_0 = { "function": lambda x: x / gs.tanh(x), "coefficients": INV_TANH_TAYLOR_COEFFS, } arctanh_card_close_0 = { "function": lambda x: gs.arctanh(x) / x, "coefficients": ARCTANH_CARD_TAYLOR_COEFFS, } def from_vector_to_diagonal_matrix(vector, num_diag=0): """Create diagonal matrices from rows of a matrix. Parameters ---------- vector : array-like, shape=[m, n] num_diag : int number of diagonal in result matrix. If 0, the result matrix is a diagonal matrix; if positive, the result matrix has an upper-right non-zero diagonal; if negative, the result matrix has a lower-left non-zero diagonal.
} sinch_close_0 = { 'function': lambda x: gs.sinh(x) / x, 'coefficients': SINHC_TAYLOR_COEFFS } cosh_close_0 = {'function': gs.cosh, 'coefficients': COSH_TAYLOR_COEFFS} inv_sinch_close_0 = { 'function': lambda x: x / gs.sinh(x), 'coefficients': INV_SINHC_TAYLOR_COEFFS } inv_tanh_close_0 = { 'function': lambda x: x / gs.tanh(x), 'coefficients': INV_TANH_TAYLOR_COEFFS } arctanh_card_close_0 = { 'function': lambda x: gs.arctanh(x) / x, 'coefficients': ARCTANH_CARD_TAYLOR_COEFFS } def from_vector_to_diagonal_matrix(vector): """Create diagonal matrices from rows of a matrix. Parameters ---------- vector : array-like, shape=[m, n] Returns ------- diagonals : array-like, shape=[m, n, n] 3-dimensional array where the `i`-th n-by-n array `diagonals[i, :, :]`
def log(self, point, base_point): """Compute Riemannian logarithm of a point wrt a base point. If point_type = 'poincare' then base_point belongs to the Poincare ball and point is a vector in the Euclidean space of the same dimension as the ball. Parameters ---------- point : array-like, shape=[n_samples, dimension + 1] Point in hyperbolic space. base_point : array-like, shape=[n_samples, dimension + 1] Point in hyperbolic space. Returns ------- log : array-like, shape=[n_samples, dimension + 1] Tangent vector at the base point equal to the Riemannian logarithm of point at the base point. """ if self.point_type == 'extrinsic': point = gs.to_ndarray(point, to_ndim=2) base_point = gs.to_ndarray(base_point, to_ndim=2) angle = self.dist(base_point, point) / self.scale angle = gs.to_ndarray(angle, to_ndim=1) angle = gs.to_ndarray(angle, to_ndim=2) mask_0 = gs.isclose(angle, 0.) mask_else = ~mask_0 mask_0_float = gs.cast(mask_0, gs.float32) mask_else_float = gs.cast(mask_else, gs.float32) coef_1 = gs.zeros_like(angle) coef_2 = gs.zeros_like(angle) coef_1 += mask_0_float * (1. + INV_SINH_TAYLOR_COEFFS[1] * angle**2 + INV_SINH_TAYLOR_COEFFS[3] * angle**4 + INV_SINH_TAYLOR_COEFFS[5] * angle**6 + INV_SINH_TAYLOR_COEFFS[7] * angle**8) coef_2 += mask_0_float * (1. + INV_TANH_TAYLOR_COEFFS[1] * angle**2 + INV_TANH_TAYLOR_COEFFS[3] * angle**4 + INV_TANH_TAYLOR_COEFFS[5] * angle**6 + INV_TANH_TAYLOR_COEFFS[7] * angle**8) # This avoids dividing by 0. angle += mask_0_float * 1. coef_1 += mask_else_float * (angle / gs.sinh(angle)) coef_2 += mask_else_float * (angle / gs.tanh(angle)) log = (gs.einsum('ni,nj->nj', coef_1, point) - gs.einsum('ni,nj->nj', coef_2, base_point)) return log elif self.point_type == 'ball': add_base_point = self.mobius_add(-base_point, point) norm_add = gs.to_ndarray(gs.linalg.norm(add_base_point, axis=-1), 2, -1) norm_add = gs.repeat(norm_add, base_point.shape[-1], -1) norm_base_point = gs.to_ndarray( gs.linalg.norm(base_point, axis=-1), 2, -1) norm_base_point = gs.repeat(norm_base_point, base_point.shape[-1], -1) log = (1 - norm_base_point**2) * gs.arctanh(norm_add)\ * (add_base_point / norm_add) mask_0 = gs.all(gs.isclose(norm_add, 0.)) log[mask_0] = 0 return log else: raise NotImplementedError( 'log is only implemented for ball and extrinsic')