def test_fit_transform(): """Test fit_transform method for class ConnectivityMeasure""" n_subjects = 10 n_features = 49 n_samples = 200 # Generate signals and compute empirical covariances covs = [] signals = [] random_state = check_random_state(0) for k in range(n_subjects): signal = random_state.randn(n_samples, n_features) signals.append(signal) signal -= signal.mean(axis=0) covs.append((signal.T).dot(signal) / n_samples) input_covs = copy.copy(covs) kinds = ["correlation", "tangent", "precision", "partial correlation"] for kind in kinds: conn_measure = ConnectivityMeasure(kind=kind, cov_estimator=EmpiricalCovariance()) connectivities = conn_measure.fit_transform(signals) # Generic assert_true(isinstance(connectivities, np.ndarray)) assert_equal(len(connectivities), len(covs)) for k, cov_new in enumerate(connectivities): assert_array_equal(input_covs[k], covs[k]) assert(is_spd(covs[k], decimal=7)) # Positive definiteness if expected and output value checks if kind == "tangent": assert_array_almost_equal(cov_new, cov_new.T) gmean_sqrt = _map_eigenvalues(np.sqrt, conn_measure.mean_) assert(is_spd(gmean_sqrt, decimal=7)) assert(is_spd(conn_measure.whitening_, decimal=7)) assert_array_almost_equal(conn_measure.whitening_.dot( gmean_sqrt), np.eye(n_features)) assert_array_almost_equal(gmean_sqrt.dot( _map_eigenvalues(np.exp, cov_new)).dot(gmean_sqrt), covs[k]) elif kind == "precision": assert(is_spd(cov_new, decimal=7)) assert_array_almost_equal(cov_new.dot(covs[k]), np.eye(n_features)) elif kind == "correlation": assert(is_spd(cov_new, decimal=7)) d = np.sqrt(np.diag(np.diag(covs[k]))) assert_array_almost_equal(d.dot(cov_new).dot(d), covs[k]) elif kind == "partial correlation": prec = linalg.inv(covs[k]) d = np.sqrt(np.diag(np.diag(prec))) assert_array_almost_equal(d.dot(cov_new).dot(d), -prec + 2 * np.diag(np.diag(prec)))
def test_is_spd_with_symmetrical_matrix(): # matrix with negative eigenvalue matrix = np.array([[0, 1], [1, 0]]) assert not is_spd(matrix, verbose=0) # matrix with 0 eigenvalue matrix = np.arange(4).reshape(2, 2) assert not is_spd(matrix, verbose=0) # spd matrix matrix = np.array([[2, 1], [1, 1]]) assert is_spd(matrix, verbose=0)
def test_is_spd_with_non_symmetrical_matrix(): matrix = np.arange(4).reshape(4, 1) assert not is_spd(matrix, verbose=0) matrix = np.array([[1, 1e-3 + 9e-19], [1e-3, 1]]) assert is_spd(matrix, verbose=0) matrix = np.array([[1, 1e-3 + 1e-18], [1e-3, 1]]) assert not is_spd(matrix, verbose=0) matrix = np.array([[1, 1e-3 + 9e-8], [1e-3, 1]]) assert is_spd(matrix, decimal=4, verbose=0) matrix = np.array([[1, 1e-3 + 1e-7], [1e-3, 1]]) assert not is_spd(matrix, decimal=4, verbose=0)
def test_get_conn_matrix(conn_model_in, n_features): """ Test computing a functional connectivity matrix.""" network = 'Default' ID = '002' smooth = 2 coords = [(1, 2, 3), (4, 5, 6), (7, 8, 9)] node_size = 8 extract_strategy = 'zscore' roi = None atlas = None uatlas = None labels = [1, 2, 3] time_series = generate_signals(n_features=n_features, n_confounds=5, length=n_features, same_variance=False)[0] outs = get_conn_matrix( time_series, conn_model_in, tempfile.TemporaryDirectory(), node_size, smooth, False, network, ID, roi, False, False, True, True, atlas, uatlas, labels, coords, 3, False, 0, extract_strategy, ) conn_matrix_out, conn_model_out = outs[0], outs[1] assert isinstance(conn_matrix_out, np.ndarray) assert np.shape(conn_matrix_out) == np.shape(time_series) assert conn_model_in == conn_model_out if "corr" in conn_model_in: assert (is_spd(conn_matrix_out, decimal=7)) d = np.sqrt(np.diag(np.diag(conn_matrix_out))) assert_array_almost_equal(np.diag(conn_matrix_out), np.ones((n_features))) elif "partcorr" in conn_model_in: prec = np.linalg.inv(conn_matrix_out) d = np.sqrt(np.diag(np.diag(prec))) assert_array_almost_equal( d.dot(conn_matrix_out).dot(d), -prec + 2 * np.diag(np.diag(prec)))
def _check_spd(matrix): """Raise a ValueError if the input matrix is not symmetric positive definite. Parameters ---------- matrix : numpy.ndarray Input array. """ if not is_spd(matrix, decimal=7): raise ValueError('Expected a symmetric positive definite matrix.')
def check_mat(mat, prop): """Raise a ValueError if the input matrix does not satisfy the property. Parameters ---------- mat : numpy.ndarray Input array. prop : {'square', 'symmetric', 'spd'} Property to check. """ if prop == 'square': if mat.ndim != 2 or (mat.shape[0] != mat.shape[-1]): raise ValueError('Expected a square matrix, got array of shape' + ' {0}.'.format(mat.shape)) if prop == 'symmetric': if not np.allclose(mat, mat.T): raise ValueError('Expected a symmetric matrix.') if prop == 'spd': if not is_spd(mat): raise ValueError('Expected a symmetric positive definite matrix.')
def test_connectivity_measure_outputs(): n_subjects = 10 n_features = 49 # Generate signals and compute covariances emp_covs = [] ledoit_covs = [] signals = [] ledoit_estimator = LedoitWolf() for k in range(n_subjects): n_samples = 200 + k signal, _, _ = generate_signals(n_features=n_features, n_confounds=5, length=n_samples, same_variance=False) signals.append(signal) signal -= signal.mean(axis=0) emp_covs.append((signal.T).dot(signal) / n_samples) ledoit_covs.append(ledoit_estimator.fit(signal).covariance_) kinds = ["covariance", "correlation", "tangent", "precision", "partial correlation"] # Check outputs properties for cov_estimator, covs in zip([EmpiricalCovariance(), LedoitWolf()], [emp_covs, ledoit_covs]): input_covs = copy.copy(covs) for kind in kinds: conn_measure = ConnectivityMeasure(kind=kind, cov_estimator=cov_estimator) connectivities = conn_measure.fit_transform(signals) # Generic assert_true(isinstance(connectivities, np.ndarray)) assert_equal(len(connectivities), len(covs)) for k, cov_new in enumerate(connectivities): assert_array_equal(input_covs[k], covs[k]) assert(is_spd(covs[k], decimal=7)) # Positive definiteness if expected and output value checks if kind == "tangent": assert_array_almost_equal(cov_new, cov_new.T) gmean_sqrt = _map_eigenvalues(np.sqrt, conn_measure.mean_) assert(is_spd(gmean_sqrt, decimal=7)) assert(is_spd(conn_measure.whitening_, decimal=7)) assert_array_almost_equal(conn_measure.whitening_.dot( gmean_sqrt), np.eye(n_features)) assert_array_almost_equal(gmean_sqrt.dot( _map_eigenvalues(np.exp, cov_new)).dot(gmean_sqrt), covs[k]) elif kind == "precision": assert(is_spd(cov_new, decimal=7)) assert_array_almost_equal(cov_new.dot(covs[k]), np.eye(n_features)) elif kind == "correlation": assert(is_spd(cov_new, decimal=7)) d = np.sqrt(np.diag(np.diag(covs[k]))) if cov_estimator == EmpiricalCovariance(): assert_array_almost_equal(d.dot(cov_new).dot(d), covs[k]) assert_array_almost_equal(np.diag(cov_new), np.ones((n_features))) elif kind == "partial correlation": prec = linalg.inv(covs[k]) d = np.sqrt(np.diag(np.diag(prec))) assert_array_almost_equal(d.dot(cov_new).dot(d), -prec + 2 * np.diag(np.diag(prec))) # Check the mean_ for kind in kinds: conn_measure = ConnectivityMeasure(kind=kind) conn_measure.fit_transform(signals) assert_equal((conn_measure.mean_).shape, (n_features, n_features)) if kind != 'tangent': assert_array_almost_equal( conn_measure.mean_, np.mean(conn_measure.transform(signals), axis=0)) # Check that the mean isn't modified in transform conn_measure = ConnectivityMeasure(kind='covariance') conn_measure.fit(signals[:1]) mean = conn_measure.mean_ conn_measure.transform(signals[1:]) assert_array_equal(mean, conn_measure.mean_) # Check vectorization option for kind in kinds: conn_measure = ConnectivityMeasure(kind=kind) connectivities = conn_measure.fit_transform(signals) conn_measure = ConnectivityMeasure(vectorize=True, kind=kind) vectorized_connectivities = conn_measure.fit_transform(signals) assert_array_almost_equal(vectorized_connectivities, sym_matrix_to_vec(connectivities)) # Check not fitted error assert_raises_regex( ValueError, 'has not been fitted. ', ConnectivityMeasure().inverse_transform, vectorized_connectivities) # Check inverse transformation kinds.remove('tangent') for kind in kinds: # without vectorization: input matrices are returned with no change conn_measure = ConnectivityMeasure(kind=kind) connectivities = conn_measure.fit_transform(signals) assert_array_almost_equal( conn_measure.inverse_transform(connectivities), connectivities) # with vectorization: input vectors are reshaped into matrices # if diagonal has not been discarded conn_measure = ConnectivityMeasure(kind=kind, vectorize=True) vectorized_connectivities = conn_measure.fit_transform(signals) assert_array_almost_equal( conn_measure.inverse_transform(vectorized_connectivities), connectivities) # with vectorization if diagonal has been discarded for kind in ['correlation', 'partial correlation']: connectivities = ConnectivityMeasure(kind=kind).fit_transform(signals) conn_measure = ConnectivityMeasure(kind=kind, vectorize=True, discard_diagonal=True) vectorized_connectivities = conn_measure.fit_transform(signals) assert_array_almost_equal( conn_measure.inverse_transform(vectorized_connectivities), connectivities) for kind in ['covariance', 'precision']: connectivities = ConnectivityMeasure(kind=kind).fit_transform(signals) conn_measure = ConnectivityMeasure(kind=kind, vectorize=True, discard_diagonal=True) vectorized_connectivities = conn_measure.fit_transform(signals) diagonal = np.array([np.diagonal(conn) / sqrt(2) for conn in connectivities]) inverse_transformed = conn_measure.inverse_transform( vectorized_connectivities, diagonal=diagonal) assert_array_almost_equal(inverse_transformed, connectivities) assert_raises_regex(ValueError, 'can not reconstruct connectivity matrices', conn_measure.inverse_transform, vectorized_connectivities) # for 'tangent' kind, covariance matrices are reconstructed # without vectorization tangent_measure = ConnectivityMeasure(kind='tangent') displacements = tangent_measure.fit_transform(signals) covariances = ConnectivityMeasure(kind='covariance').fit_transform( signals) assert_array_almost_equal( tangent_measure.inverse_transform(displacements), covariances) # with vectorization # when diagonal has not been discarded tangent_measure = ConnectivityMeasure(kind='tangent', vectorize=True) vectorized_displacements = tangent_measure.fit_transform(signals) assert_array_almost_equal( tangent_measure.inverse_transform(vectorized_displacements), covariances) # when diagonal has been discarded tangent_measure = ConnectivityMeasure(kind='tangent', vectorize=True, discard_diagonal=True) vectorized_displacements = tangent_measure.fit_transform(signals) diagonal = np.array([np.diagonal(matrix) / sqrt(2) for matrix in displacements]) inverse_transformed = tangent_measure.inverse_transform( vectorized_displacements, diagonal=diagonal) assert_array_almost_equal(inverse_transformed, covariances) assert_raises_regex(ValueError, 'can not reconstruct connectivity matrices', tangent_measure.inverse_transform, vectorized_displacements)
def test_geometric_mean_properties(): n_matrices = 40 n_features = 15 spds = [] for k in range(n_matrices): spds.append(random_spd(n_features, eig_min=1., cond=10., random_state=0)) input_spds = copy.copy(spds) gmean = _geometric_mean(spds) # Generic assert_true(isinstance(spds, list)) for spd, input_spd in zip(spds, input_spds): assert_array_equal(spd, input_spd) assert(is_spd(gmean, decimal=7)) # Invariance under reordering spds.reverse() spds.insert(0, spds[1]) spds.pop(2) assert_array_almost_equal(_geometric_mean(spds), gmean) # Invariance under congruent transformation non_singular = random_non_singular(n_features, random_state=0) spds_cong = [non_singular.dot(spd).dot(non_singular.T) for spd in spds] assert_array_almost_equal(_geometric_mean(spds_cong), non_singular.dot(gmean).dot(non_singular.T)) # Invariance under inversion spds_inv = [linalg.inv(spd) for spd in spds] init = linalg.inv(np.mean(spds, axis=0)) assert_array_almost_equal(_geometric_mean(spds_inv, init=init), linalg.inv(gmean)) # Gradient norm is decreasing grad_norm = grad_geometric_mean(spds, tol=1e-20) difference = np.diff(grad_norm) assert_true(np.amax(difference) <= 0.) # Check warning if gradient norm in the last step is less than # tolerance max_iter = 1 tol = 1e-20 with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") gmean = _geometric_mean(spds, max_iter=max_iter, tol=tol) assert_equal(len(w), 1) grad_norm = grad_geometric_mean(spds, max_iter=max_iter, tol=tol) assert_equal(len(grad_norm), max_iter) assert_true(grad_norm[-1] > tol) # Evaluate convergence. A warning is printed if tolerance is not reached for p in [.5, 1.]: # proportion of badly conditionned matrices spds = [] for k in range(int(p * n_matrices)): spds.append(random_spd(n_features, eig_min=1e-2, cond=1e6, random_state=0)) for k in range(int(p * n_matrices), n_matrices): spds.append(random_spd(n_features, eig_min=1., cond=10., random_state=0)) if p < 1: max_iter = 30 else: max_iter = 60 gmean = _geometric_mean(spds, max_iter=max_iter, tol=1e-5)
def test_connectivity_measure_outputs(): n_subjects = 10 n_features = 49 # Generate signals and compute covariances emp_covs = [] ledoit_covs = [] signals = [] ledoit_estimator = LedoitWolf() for k in range(n_subjects): n_samples = 200 + k signal, _, _ = generate_signals(n_features=n_features, n_confounds=5, length=n_samples, same_variance=False) signals.append(signal) signal -= signal.mean(axis=0) emp_covs.append((signal.T).dot(signal) / n_samples) ledoit_covs.append(ledoit_estimator.fit(signal).covariance_) kinds = ["covariance", "correlation", "tangent", "precision", "partial correlation"] # Check outputs properties for cov_estimator, covs in zip([EmpiricalCovariance(), LedoitWolf()], [emp_covs, ledoit_covs]): input_covs = copy.copy(covs) for kind in kinds: conn_measure = ConnectivityMeasure(kind=kind, cov_estimator=cov_estimator) connectivities = conn_measure.fit_transform(signals) # Generic assert isinstance(connectivities, np.ndarray) assert len(connectivities) == len(covs) for k, cov_new in enumerate(connectivities): assert_array_equal(input_covs[k], covs[k]) assert(is_spd(covs[k], decimal=7)) # Positive definiteness if expected and output value checks if kind == "tangent": assert_array_almost_equal(cov_new, cov_new.T) gmean_sqrt = _map_eigenvalues(np.sqrt, conn_measure.mean_) assert(is_spd(gmean_sqrt, decimal=7)) assert(is_spd(conn_measure.whitening_, decimal=7)) assert_array_almost_equal(conn_measure.whitening_.dot( gmean_sqrt), np.eye(n_features)) assert_array_almost_equal(gmean_sqrt.dot( _map_eigenvalues(np.exp, cov_new)).dot(gmean_sqrt), covs[k]) elif kind == "precision": assert(is_spd(cov_new, decimal=7)) assert_array_almost_equal(cov_new.dot(covs[k]), np.eye(n_features)) elif kind == "correlation": assert(is_spd(cov_new, decimal=7)) d = np.sqrt(np.diag(np.diag(covs[k]))) if cov_estimator == EmpiricalCovariance(): assert_array_almost_equal(d.dot(cov_new).dot(d), covs[k]) assert_array_almost_equal(np.diag(cov_new), np.ones((n_features))) elif kind == "partial correlation": prec = linalg.inv(covs[k]) d = np.sqrt(np.diag(np.diag(prec))) assert_array_almost_equal(d.dot(cov_new).dot(d), -prec + 2 * np.diag(np.diag(prec))) # Check the mean_ for kind in kinds: conn_measure = ConnectivityMeasure(kind=kind) conn_measure.fit_transform(signals) assert (conn_measure.mean_).shape == (n_features, n_features) if kind != 'tangent': assert_array_almost_equal( conn_measure.mean_, np.mean(conn_measure.transform(signals), axis=0)) # Check that the mean isn't modified in transform conn_measure = ConnectivityMeasure(kind='covariance') conn_measure.fit(signals[:1]) mean = conn_measure.mean_ conn_measure.transform(signals[1:]) assert_array_equal(mean, conn_measure.mean_) # Check vectorization option for kind in kinds: conn_measure = ConnectivityMeasure(kind=kind) connectivities = conn_measure.fit_transform(signals) conn_measure = ConnectivityMeasure(vectorize=True, kind=kind) vectorized_connectivities = conn_measure.fit_transform(signals) assert_array_almost_equal(vectorized_connectivities, sym_matrix_to_vec(connectivities)) # Check not fitted error with pytest.raises(ValueError, match='has not been fitted. '): ConnectivityMeasure().inverse_transform(vectorized_connectivities) # Check inverse transformation kinds.remove('tangent') for kind in kinds: # without vectorization: input matrices are returned with no change conn_measure = ConnectivityMeasure(kind=kind) connectivities = conn_measure.fit_transform(signals) assert_array_almost_equal( conn_measure.inverse_transform(connectivities), connectivities) # with vectorization: input vectors are reshaped into matrices # if diagonal has not been discarded conn_measure = ConnectivityMeasure(kind=kind, vectorize=True) vectorized_connectivities = conn_measure.fit_transform(signals) assert_array_almost_equal( conn_measure.inverse_transform(vectorized_connectivities), connectivities) # with vectorization if diagonal has been discarded for kind in ['correlation', 'partial correlation']: connectivities = ConnectivityMeasure(kind=kind).fit_transform(signals) conn_measure = ConnectivityMeasure(kind=kind, vectorize=True, discard_diagonal=True) vectorized_connectivities = conn_measure.fit_transform(signals) assert_array_almost_equal( conn_measure.inverse_transform(vectorized_connectivities), connectivities) for kind in ['covariance', 'precision']: connectivities = ConnectivityMeasure(kind=kind).fit_transform(signals) conn_measure = ConnectivityMeasure(kind=kind, vectorize=True, discard_diagonal=True) vectorized_connectivities = conn_measure.fit_transform(signals) diagonal = np.array([np.diagonal(conn) / sqrt(2) for conn in connectivities]) inverse_transformed = conn_measure.inverse_transform( vectorized_connectivities, diagonal=diagonal) assert_array_almost_equal(inverse_transformed, connectivities) with pytest.raises(ValueError, match='can not reconstruct connectivity matrices'): conn_measure.inverse_transform(vectorized_connectivities) # for 'tangent' kind, covariance matrices are reconstructed # without vectorization tangent_measure = ConnectivityMeasure(kind='tangent') displacements = tangent_measure.fit_transform(signals) covariances = ConnectivityMeasure(kind='covariance').fit_transform( signals) assert_array_almost_equal( tangent_measure.inverse_transform(displacements), covariances) # with vectorization # when diagonal has not been discarded tangent_measure = ConnectivityMeasure(kind='tangent', vectorize=True) vectorized_displacements = tangent_measure.fit_transform(signals) assert_array_almost_equal( tangent_measure.inverse_transform(vectorized_displacements), covariances) # when diagonal has been discarded tangent_measure = ConnectivityMeasure(kind='tangent', vectorize=True, discard_diagonal=True) vectorized_displacements = tangent_measure.fit_transform(signals) diagonal = np.array([np.diagonal(matrix) / sqrt(2) for matrix in displacements]) inverse_transformed = tangent_measure.inverse_transform( vectorized_displacements, diagonal=diagonal) assert_array_almost_equal(inverse_transformed, covariances) with pytest.raises(ValueError, match='can not reconstruct connectivity matrices'): tangent_measure.inverse_transform(vectorized_displacements)
def test_geometric_mean_properties(): n_matrices = 40 n_features = 15 spds = [] for k in range(n_matrices): spds.append(random_spd(n_features, eig_min=1., cond=10., random_state=0)) input_spds = copy.copy(spds) gmean = _geometric_mean(spds) # Generic assert isinstance(spds, list) for spd, input_spd in zip(spds, input_spds): assert_array_equal(spd, input_spd) assert(is_spd(gmean, decimal=7)) # Invariance under reordering spds.reverse() spds.insert(0, spds[1]) spds.pop(2) assert_array_almost_equal(_geometric_mean(spds), gmean) # Invariance under congruent transformation non_singular = random_non_singular(n_features, random_state=0) spds_cong = [non_singular.dot(spd).dot(non_singular.T) for spd in spds] assert_array_almost_equal(_geometric_mean(spds_cong), non_singular.dot(gmean).dot(non_singular.T)) # Invariance under inversion spds_inv = [linalg.inv(spd) for spd in spds] init = linalg.inv(np.mean(spds, axis=0)) assert_array_almost_equal(_geometric_mean(spds_inv, init=init), linalg.inv(gmean)) # Gradient norm is decreasing grad_norm = grad_geometric_mean(spds, tol=1e-20) difference = np.diff(grad_norm) assert np.amax(difference) <= 0. # Check warning if gradient norm in the last step is less than # tolerance max_iter = 1 tol = 1e-20 with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") gmean = _geometric_mean(spds, max_iter=max_iter, tol=tol) assert len(w) == 1 grad_norm = grad_geometric_mean(spds, max_iter=max_iter, tol=tol) assert len(grad_norm) == max_iter assert grad_norm[-1] > tol # Evaluate convergence. A warning is printed if tolerance is not reached for p in [.5, 1.]: # proportion of badly conditionned matrices spds = [] for k in range(int(p * n_matrices)): spds.append(random_spd(n_features, eig_min=1e-2, cond=1e6, random_state=0)) for k in range(int(p * n_matrices), n_matrices): spds.append(random_spd(n_features, eig_min=1., cond=10., random_state=0)) if p < 1: max_iter = 30 else: max_iter = 60 gmean = _geometric_mean(spds, max_iter=max_iter, tol=1e-5)
def test_get_conn_matrix(conn_model_in, n_features): """ Test computing a functional connectivity matrix.""" tmp = tempfile.TemporaryDirectory() dir_path = str(tmp.name) os.makedirs(dir_path, exist_ok=True) subnet = 'Default' ID = '002' smooth = 2 coords = [(1, 2, 3), (4, 5, 6), (7, 8, 9)] node_radius = 8 signal = 'zscore' roi = None atlas = None parcellation = None labels = [1, 2, 3] time_series = generate_signals(n_features=n_features, n_confounds=5, length=n_features, same_variance=False)[0] outs = get_conn_matrix( time_series, conn_model_in, dir_path, node_radius, smooth, False, subnet, ID, roi, False, False, True, True, atlas, parcellation, labels, coords, 3, False, 0, signal, ) conn_matrix_out, conn_model_out = outs[0], outs[1] assert isinstance(conn_matrix_out, np.ndarray) assert np.shape(conn_matrix_out) == np.shape(time_series) assert conn_model_in == conn_model_out if "corr" in conn_model_in: assert (is_spd(conn_matrix_out, decimal=7)) d = np.sqrt(np.diag(np.diag(conn_matrix_out))) assert_array_almost_equal(np.diag(conn_matrix_out), np.ones(n_features)) elif "partcorr" in conn_model_in: prec = np.linalg.inv(conn_matrix_out) d = np.sqrt(np.diag(np.diag(prec))) assert_array_almost_equal( d.dot(conn_matrix_out).dot(d), -prec + 2 * np.diag(np.diag(prec))) tmp.cleanup()