Exemplo n.º 1
0
    def fit(self, X, y=None):
        if self.cov_estimator is None:
            self.cov_estimator_ = EmpiricalCovariance(
                assume_centered=True)
        else:
            self.cov_estimator_ = clone(self.cov_estimator)

        if self.kind == 'tangent':
            covs = [self.cov_estimator_.fit(x).covariance_ for x in X]
            self.mean_cov_ = spd_mfd.frechet_mean(covs, max_iter=30, tol=1e-7)
            self.whitening_ = spd_mfd.inv_sqrtm(self.mean_cov_)
        return self
Exemplo n.º 2
0
def test_frechet_mean():  # TODO: test suite and split in several tests
    """Testing frechet_mean function"""
    n = random.randint(3, 50)
    shape = random.randint(1, 50)
    spds = []
    for k in xrange(n):
        eig_min = random.uniform(1e-7, 1.)
        eig_max = random.uniform(1., 1e7)
        spds.append(my_mfd.random_spd(shape, eig_min, eig_max))
    fre = my_mfd.frechet_mean(spds)

    # Generic
    assert_tuple_equal(fre.shape, spds[0].shape)
    assert_array_almost_equal(fre, fre.T)
    assert_array_less(0., linalg.eigvals(fre))

    # Check error for non spd enteries
    mat1 = np.ones((shape, shape))
    with assert_raises_regexp(ValueError, "at least one matrix is not real " +\
    "spd"):
        my_mfd.frechet_mean([mat1])

    # Check warning if gradient norm in the last step is less than tolerance
    for (tol, max_iter) in [(1e-10, 1), (1e-3, 50)]:
        with warnings.catch_warnings(record=True) as w:
            fre = my_mfd.frechet_mean(spds, max_iter=max_iter, tol=tol)
            grad_norm = my_mfd.grad_frechet_mean(spds, max_iter=max_iter,
                                                  tol=tol)
            if grad_norm[-1] > tol:
                assert_equal(len(w), 2)
                assert_equal(len(grad_norm), max_iter)

    # Gradient norm is decreasing
    assert_array_less(np.diff(grad_norm), 0.)

    decimal = 5
    tol = 10 ** (-2 * decimal)
    fre = my_mfd.frechet_mean(spds, tol=tol)

    # Adaptative version requires less iterations than non adaptaive
    grad_norm = my_mfd.grad_frechet_mean(spds, tol=tol)
    grad_norm_fast = my_mfd.grad_frechet_mean(spds, tol=tol, adaptative=True)
    assert(len(grad_norm_fast) == len(grad_norm))

    # Invariance under reordering
    spds.reverse()
    spds.insert(0, spds[2])
    spds.pop(3)
    fre_new = my_mfd.frechet_mean(spds, tol=tol)
    assert_array_almost_equal(fre_new, fre)

    # Invariance under congruant transformation
    c = my_mfd.random_non_singular(shape)
    spds_cong = [c.dot(spd).dot(c.T) for spd in spds]
    fre_new = my_mfd.frechet_mean(spds_cong, tol=tol)
    assert_array_almost_equal(fre_new, c.dot(fre).dot(c.T))

    # Invariance under inversion
    spds_inv = [linalg.inv(spd) for spd in spds]
    fre_new = my_mfd.frechet_mean(spds_inv, tol=tol)
    assert_array_almost_equal(fre_new, linalg.inv(fre), decimal=decimal)

    # Approximate Frechet mean is close to the exact one
    decimal = 7
    tol = 0.5 * 10 ** (-decimal)

    # Diagonal matrices: exact Frechet mean is geometric mean
    diags = []
    for k in xrange(n):
        diags.append(my_mfd.random_diagonal_spd(shape, 1e-5, 1e5))
    exact_fre = np.prod(my_mfd.my_stack(diags), axis=0) ** \
                (1 / float(len(diags)))
    app_fre = my_mfd.frechet_mean(diags, max_iter=10, tol=tol)
    assert_array_almost_equal(app_fre, exact_fre, decimal)

    # 2 matrices
    spd1 = my_mfd.random_spd(shape)
    spd2 = my_mfd.random_spd(shape)
    spd2_sqrt = my_mfd.sqrtm(spd2)
    spd2_inv_sqrt = my_mfd.inv_sqrtm(spd2)
    exact_fre = spd2_sqrt.dot(
    my_mfd.sqrtm(spd2_inv_sqrt.dot(spd1).dot(spd2_inv_sqrt))).dot(spd2_sqrt)
    app_fre = my_mfd.frechet_mean([spd1, spd2], tol=tol)
    assert_array_almost_equal(app_fre, exact_fre, decimal)

    # Single geodesic matrices : TODO
    S = np.random.rand(shape, shape)
    S = S + S.T
    times = np.empty(n, dtype=float)
    spds = []
    for k in xrange(n):
        t_k = random.uniform(-2., -1.)
        times[k] = t_k
        spds.append(c.dot(my_mfd.expm(t_k * S)).dot(c.T))