def _iterate_over_manifolds(self, func, args, intrinsic=False): cum_index = ( gs.cumsum(self.dims)[:-1] if intrinsic else gs.cumsum([k + 1 for k in self.dims]) ) arguments = {} float_args = {} for key, value in args.items(): if not isinstance(value, float): arguments[key] = gs.split(value, cum_index, axis=-1) else: float_args[key] = value args_list = [ {key: arguments[key][j] for key in arguments} for j in range(len(self.manifolds)) ] pool = joblib.Parallel(n_jobs=self.n_jobs) out = pool( joblib.delayed(self._get_method)( self.manifolds[i], func, {**args_list[i], **float_args} ) for i in range(len(self.manifolds)) ) return out
def test_cumsum(self): result = gs.cumsum(gs.arange(10)) expected = gs.array(([0, 1, 3, 6, 10, 15, 21, 28, 36, 45])) self.assertAllClose(result, expected) result = gs.cumsum(gs.arange(10).reshape(2, 5), axis=1) expected = gs.array(([[0, 1, 3, 6, 10], [5, 11, 18, 26, 35]])) self.assertAllClose(result, expected)
def _iterate_over_metrics( self, func, args, intrinsic=False): cum_index = gs.cumsum(self.dims, axis=0)[:-1] if intrinsic else \ gs.cumsum(gs.array([k + 1 for k in self.dims]), axis=0) arguments = { key: gs.split(args[key], cum_index, axis=1) for key in args.keys()} args_list = [{key: arguments[key][j] for key in args.keys()} for j in range(self.n_metrics)] pool = joblib.Parallel(n_jobs=self.n_jobs, prefer='threads') out = pool( joblib.delayed(self._get_method)( self.metrics[i], func, args_list[i]) for i in range( self.n_metrics)) return out
def _iterate_over_manifolds( self, func, args, intrinsic=False): cum_index = gs.cumsum(self.dims)[:-1] if intrinsic else \ gs.cumsum([k + 1 for k in self.dims]) arguments = {key: gs.split( args[key], cum_index, axis=1) for key in args.keys()} args_list = [{key: arguments[key][j] for key in args.keys()} for j in range(len(self.manifolds))] pool = joblib.Parallel(n_jobs=self.n_jobs) out = pool( joblib.delayed(self._get_method)( self.manifolds[i], func, args_list[i]) for i in range( len(self.manifolds))) return out
def square_root_velocity_inverse(self, srv, starting_point): """Retrieve a curve from sqrt velocity rep and starting point. Parameters ---------- srv : starting_point : Returns ------- curve : """ if not isinstance(self.ambient_metric, EuclideanMetric): raise AssertionError('The square root velocity inverse is only ' 'implemented for dicretized curves embedded ' 'in a Euclidean space.') if gs.ndim(srv) != gs.ndim(starting_point): starting_point = gs.transpose(gs.tile(starting_point, (1, 1, 1)), axes=(1, 0, 2)) srv_shape = srv.shape srv = gs.to_ndarray(srv, to_ndim=3) n_curves, n_sampling_points_minus_one, n_coords = srv.shape srv = gs.reshape(srv, (n_curves * n_sampling_points_minus_one, n_coords)) srv_norm = self.ambient_metric.norm(srv) delta_points = 1 / n_sampling_points_minus_one * srv_norm * srv delta_points = gs.reshape(delta_points, srv_shape) curve = gs.concatenate((starting_point, delta_points), -2) curve = gs.cumsum(curve, -2) return curve
def test_fit_to_target_explained_variance(self): X = self.spd.random_point(n_samples=5) target = 0.90 tpca = TangentPCA(self.spd_metric, n_components=target) tpca.fit(X) result = gs.cumsum(tpca.explained_variance_ratio_)[-1] > target expected = True self.assertAllClose(result, expected)
def log(self, point, base_point): """Compute Riemannian logarithm of a curve wrt a base curve. Parameters ---------- point : array-like, shape=[..., n_sampling_points, ambient_dim] Discrete curve. base_point : array-like, shape=[..., n_sampling_points, ambient_dim] Discrete curve to use as base point. Returns ------- log : array-like, shape=[..., n_sampling_points, ambient_dim] Tangent vector to a discrete curve. """ if not isinstance(self.ambient_metric, EuclideanMetric): raise AssertionError('The logarithm map is only implemented ' 'for discrete curves embedded in a ' 'Euclidean space.') point = gs.to_ndarray(point, to_ndim=3) base_point = gs.to_ndarray(base_point, to_ndim=3) n_curves, n_sampling_points, n_coords = point.shape curve_srv = self.square_root_velocity(point) base_curve_srv = self.square_root_velocity(base_point) base_curve_velocity = (n_sampling_points - 1) * (base_point[:, 1:, :] - base_point[:, :-1, :]) base_curve_velocity_norm = self.pointwise_norm(base_curve_velocity, base_point[:, :-1, :]) inner_prod = self.pointwise_inner_product(curve_srv - base_curve_srv, base_curve_velocity, base_point[:, :-1, :]) coef_1 = gs.sqrt(base_curve_velocity_norm) coef_2 = 1 / base_curve_velocity_norm**(3 / 2) * inner_prod term_1 = gs.einsum('ij,ijk->ijk', coef_1, curve_srv - base_curve_srv) term_2 = gs.einsum('ij,ijk->ijk', coef_2, base_curve_velocity) log_derivative = term_1 + term_2 log_starting_points = self.ambient_metric.log( point=point[:, 0, :], base_point=base_point[:, 0, :]) log_starting_points = gs.to_ndarray( log_starting_points, to_ndim=3, axis=1) log_cumsum = gs.hstack( [gs.zeros((n_curves, 1, n_coords)), gs.cumsum(log_derivative, -2)]) log = log_starting_points + 1 / (n_sampling_points - 1) * log_cumsum return log
def log(self, curve, base_curve): """Compute Riemannian logarithm of a curve wrt a base curve. Parameters ---------- curve : base_curve : Returns ------- log : """ if not isinstance(self.ambient_metric, EuclideanMetric): raise AssertionError('The logarithm map is only implemented ' 'for dicretized curves embedded in a ' 'Euclidean space.') curve = gs.to_ndarray(curve, to_ndim=3) base_curve = gs.to_ndarray(base_curve, to_ndim=3) n_curves, n_sampling_points, n_coords = curve.shape curve_srv = self.square_root_velocity(curve) base_curve_srv = self.square_root_velocity(base_curve) base_curve_velocity = (n_sampling_points - 1) * (base_curve[:, 1:, :] - base_curve[:, :-1, :]) base_curve_velocity_norm = self.pointwise_norm(base_curve_velocity, base_curve[:, :-1, :]) inner_prod = self.pointwise_inner_product(curve_srv - base_curve_srv, base_curve_velocity, base_curve[:, :-1, :]) coef_1 = gs.sqrt(base_curve_velocity_norm) coef_2 = 1 / base_curve_velocity_norm**(3 / 2) * inner_prod term_1 = gs.einsum('ij,ijk->ijk', coef_1, curve_srv - base_curve_srv) term_2 = gs.einsum('ij,ijk->ijk', coef_2, base_curve_velocity) log_derivative = term_1 + term_2 log_starting_points = self.ambient_metric.log( point=curve[:, 0, :], base_point=base_curve[:, 0, :]) log_starting_points = gs.transpose( gs.tile(log_starting_points, (1, 1, 1)), (1, 0, 2)) log_cumsum = gs.hstack( [gs.zeros((n_curves, 1, n_coords)), gs.cumsum(log_derivative, -2)]) log = log_starting_points + 1 / (n_sampling_points - 1) * log_cumsum return log
def _circle_variances(mean, var, n_samples, points): """Compute the minimizer of the variance functional. Parameters ---------- mean : float Mean angle. var : float Variance of the angles. n_samples : int Number of samples. points : array-like, shape=[n,] Data set of ordered angles. References --------- ..[HH15] Hotz, T. and S. F. Huckemann (2015), "Intrinsic means on the circle: Uniqueness, locus and asymptotics", Annals of the Institute of Statistical Mathematics 67 (1), 177–193. https://arxiv.org/abs/1108.2141 """ means = (mean + gs.linspace(0.0, 2 * gs.pi, n_samples + 1)[:-1]) % (2 * gs.pi) means = gs.where(means >= gs.pi, means - 2 * gs.pi, means) parts = gs.array([sum(points) / n_samples if means[0] < 0 else 0]) m_plus = means >= 0 left_sums = gs.cumsum(points) right_sums = left_sums[-1] - left_sums i = gs.arange(n_samples, dtype=right_sums.dtype) j = i[1:] parts2 = right_sums[:-1] / (n_samples - j) first_term = parts2[:1] parts2 = gs.where(m_plus[1:], left_sums[:-1] / j, parts2) parts = gs.concatenate([parts, first_term, parts2[1:]]) # Formula (6) from [HH15]_ plus_vec = (4 * gs.pi * i / n_samples) * (gs.pi + parts - mean) - ( 2 * gs.pi * i / n_samples ) ** 2 minus_vec = (4 * gs.pi * (n_samples - i) / n_samples) * (gs.pi - parts + mean) - ( 2 * gs.pi * (n_samples - i) / n_samples ) ** 2 minus_vec = gs.where(m_plus, plus_vec, minus_vec) means = gs.transpose(gs.vstack([means, var + minus_vec])) return means
def square_root_velocity_inverse(self, srv, starting_point): """Retrieve a curve from sqrt velocity rep and starting point. Parameters ---------- srv : array-like, shape=[..., n_sampling_points - 1, ambient_dim] Square-root velocity representation of a discrete curve. starting_point : array-like, shape=[..., ambient_dim] Point of the ambient manifold to use as start of the retrieved curve. Returns ------- curve : array-like, shape=[..., n_sampling_points, ambient_dim] Curve retrieved from its square-root velocity. """ if not isinstance(self.ambient_metric, EuclideanMetric): raise AssertionError('The square root velocity inverse is only ' 'implemented for discrete curves embedded ' 'in a Euclidean space.') if gs.ndim(srv) != gs.ndim(starting_point): starting_point = gs.to_ndarray( starting_point, to_ndim=srv.ndim, axis=1) srv_shape = srv.shape srv = gs.to_ndarray(srv, to_ndim=3) n_curves, n_sampling_points_minus_one, n_coords = srv.shape srv = gs.reshape(srv, (n_curves * n_sampling_points_minus_one, n_coords)) srv_norm = self.ambient_metric.norm(srv) delta_points = gs.einsum( '...,...i->...i', 1 / n_sampling_points_minus_one * srv_norm, srv) delta_points = gs.reshape(delta_points, srv_shape) curve = gs.concatenate((starting_point, delta_points), -2) curve = gs.cumsum(curve, -2) return curve