{"action":"created","comment":{"url":"https://api.github.com/repos/nilearn/nilearn/pulls/comments/34958349","id":34958349,"diff_hunk":"@@ -0,0 +1,394 @@\n+import warnings\n+from math import floor, sqrt\n+\n+import numpy as np\n+from scipy import linalg\n+\n+from sklearn.base import BaseEstimator, TransformerMixin, clone\n+from sklearn.covariance import EmpiricalCovariance\n+from .._utils.extmath import is_spd\n+\n+\n+def _check_mat(mat, prop):\n+    \"\"\"Raise a ValueError if the input matrix does not satisfy the property.\n+\n+    Parameters\n+    ----------\n+    mat : numpy.ndarray\n+        Input array.\n+\n+    prop : {'square', 'symmetric', 'spd'}\n+        Property to check.\n+    \"\"\"\n+    if prop == 'square':\n+        if mat.ndim != 2 or (mat.shape[0] != mat.shape[-1]):\n+            raise ValueError('Expected a square matrix, got array of shape' +\n+                             ' {0}.'.format(mat.shape))\n+    if prop == 'symmetric':\n+        if not np.allclose(mat, mat.T):\n+            raise ValueError('Expected a symmetric matrix.')\n+\n+    if prop == 'spd':\n+        if not is_spd(mat, decimal=7):\n+            raise ValueError('Expected a symmetric positive definite matrix.')\n+\n+\n+def _map_eig(function, vals, vecs):\n+    \"\"\"Return the symmetric matrix with eigenvectors vecs and eigenvalues\n+    obtained by applying the function to vals.\n+\n+    Parameters\n+    ----------\n+    function : function\n+        The function to apply.\n+\n+    vals : numpy.ndarray, shape (M, )\n+        Input argument of the function.\n+\n+    vecs : numpy.ndarray, shape (M, M)\n+        Unitary matrix.\n+\n+    Returns\n+    -------\n+    output : numpy.ndarray, shape (M, M)\n+        The symmetric matrix obtained after transforming the eigenvalues, with\n+        eigenvectors the columns of vecs.\n+    \"\"\"\n+    return np.dot(vecs * function(vals), vecs.T)\n+\n+\n+def _map_sym(function, sym):\n+    \"\"\"Matrix function, for real symmetric matrices. The function is applied\n+    to the eigenvalues of sym.\n+\n+    Parameters\n+    ----------\n+    function : function\n+        The function to apply.\n+\n+    sym : numpy.ndarray, shape (M, M)\n+        The matrix to be transformed.\n+\n+    Returns\n+    -------\n+    output : numpy.ndarray, shape (M, M)\n+        The new symmetric matrix obtained after transforming the eigenvalues.\n+\n+    Note\n+    ----\n+    If input matrix is not real symmetric, no error is reported but result will\n+    be wrong.\n+    \"\"\"\n+    vals, vecs = linalg.eigh(sym)\n+    return _map_eig(function, vals, vecs)\n+\n+\n+def _geometric_mean(mats, init=None, max_iter=10, tol=1e-7):\n+    \"\"\"Compute the geometric mean of symmetric positive definite matrices.\n+\n+    The geometric mean of n positive definite matrices\n+    M_1, ..., M_n is the minimizer of the sum of squared distances from an\n+    arbitrary matrix to each input matrix M_k\n+\n+    gmean(M_1, ..., M_n) = argmin_X sum_{k=1}^N dist(X, M_k)^2\n+\n+    where the used distance is related to matrices logarithm\n+\n+    dist(X, M_k) = ||log(X^{-1/2} M_k X^{-1/2)}||\n+\n+    In case of positive numbers, this mean is the usual geometric mean.\n+\n+    See Algorithm 3 of:\n+        P. Thomas Fletcher, Sarang Joshi. Riemannian Geometry for the\n+        Statistical Analysis of Diffusion Tensor Data. Signal Processing, 2007.\n+\n+    Parameters\n+    ----------\n+    mats : list of numpy.ndarray, shape of each (n_features, n_features)\n+        List of matrices whose geometric mean to compute. Raise an error if the\n+        arrays are not all symmetric positive definite of the same shape.\n+\n+    init : numpy.ndarray, shape (n_features, n_features) or None, optional\n+        Initialization matrix. Raise an error if the array is not symmetric\n+        positive definite of the same shape as the elements of mats. Set to the\n+        arithmetic mean of mats if None.\n+\n+    max_iter : int, optional (default to 10)\n+        Maximal number of iterations.\n+\n+    tol : float, optional (default to 1e-7)\n+        Tolerance.\n+\n+    Returns\n+    -------\n+    gmean : numpy.ndarray, shape (n_features, n_features)\n+        Geometric mean of the matrices.\n+    \"\"\"\n+    # Shape and symmetry positive definiteness checks\n+    n_features = mats[0].shape[0]\n+    for mat in mats:\n+        _check_mat(mat, 'square')\n+        if mat.shape[0] != n_features:\n+            raise ValueError(\"Matrices are not of the same shape.\")\n+        _check_mat(mat, 'spd')\n+\n+    # Initialization\n+    mats = np.array(mats)\n+    if init is None:\n+        gmean = np.mean(mats, axis=0)\n+    else:\n+        _check_mat(init, 'square')\n+        if init.shape[0] != n_features:\n+            raise ValueError(\"Initialization has not the correct shape.\")\n+        _check_mat(init, 'spd')\n+        gmean = init\n+\n+    norm_old = np.inf\n+    step = 1.\n+\n+    # Gradient descent\n+    for n in range(max_iter):\n+        # Computation of the gradient\n+        vals_gmean, vecs_gmean = linalg.eigh(gmean)\n+        gmean_inv_sqrt = _map_eig(np.sqrt, 1. / vals_gmean, vecs_gmean)\n+        whitened_mats = [gmean_inv_sqrt.dot(mat).dot(gmean_inv_sqrt)\n+                         for mat in mats]\n+        logs = [_map_sym(np.log, w_mat) for w_mat in whitened_mats]\n+        logs_mean = np.mean(logs, axis=0)  # Covariant derivative is\n+                                           # - gmean.dot(logms_mean)\n+        if np.any(np.isnan(logs_mean)):\n+            raise FloatingPointError(\"Nan value after logarithm operation.\")\n+\n+        norm = np.linalg.norm(logs_mean)  # Norm of the covariant derivative on\n+                                          # the tangent space at point gmean\n+\n+        # Update of the minimizer\n+        vals_log, vecs_log = linalg.eigh(logs_mean)\n+        gmean_sqrt = _map_eig(np.sqrt, vals_gmean, vecs_gmean)\n+        # Move along the geodesic\n+        gmean = gmean_sqrt.dot(\n+            _map_eig(np.exp, vals_log * step, vecs_log)).dot(gmean_sqrt)\n+\n+        # Update the norm and the step size\n+        if norm < norm_old:\n+            norm_old = norm\n+        if norm > norm_old:\n+            step = step / 2.\n+            norm = norm_old\n+        if tol is not None and norm / gmean.size < tol:\n+            break\n+    if tol is not None and norm / gmean.size >= tol:\n+        warnings.warn(\"Maximum number of iterations {0} reached without \"\n+                      \"getting to the requested tolerance level \"\n+                      \"{1}.\".format(max_iter, tol))\n+\n+    return gmean\n+\n+\n+def sym_to_vec(sym, isometry=True):\n+    \"\"\"Return the flattened lower triangular part of an array.\n+\n+    Acts on the last two dimensions of the array if not 2-dimensional.\n+\n+    Parameters\n+    ----------\n+    sym : numpy.ndarray, shape (..., p, p)\n+        Input array.\n+\n+    isometry : bool, optional (default to True)\n+        If True, off diagonal terms of sym are multiplied by sqrt(2).\n+","path":"nilearn/connectivity/embedding.py","position":200,"original_position":200,"commit_id":"22f2e7cf22b22f7681977e91b8d4b275c17aec7f","original_commit_id":"22f2e7cf22b22f7681977e91b8d4b275c17aec7f","user":{"login":"salma1601","id":7080143,"avatar_url":"https://avatars.githubusercontent.com/u/7080143?v=3","gravatar_id":"","url":"https://api.github.com/users/salma1601","html_url":"https://github.com/salma1601","followers_url":"https://api.github.com/users/salma1601/followers","following_url":"https://api.github.com/users/salma1601/following{/other_user}","gists_url":"https://api.github.com/users/salma1601/gists{/gist_id}","starred_url":"https://api.github.com/users/salma1601/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/salma1601/subscriptions","organizations_url":"https://api.github.com/users/salma1601/orgs","repos_url":"https://api.github.com/users/salma1601/repos","events_url":"https://api.github.com/users/salma1601/events{/privacy}","received_events_url":"https://api.github.com/users/salma1601/received_events","type":"User","site_admin":false},"body":"You are right, I removed it. I used it with the option to transform p-values.","created_at":"2015-07-19T14:00:26Z","updated_at":"2015-07-19T14:00:26Z","html_url":"https://github.com/nilearn/nilearn/pull/677#discussion_r34958349","pull_request_url":"https://api.github.com/repos/nilearn/nilearn/pulls/677","_links":{"self":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/comments/34958349"},"html":{"href":"https://github.com/nilearn/nilearn/pull/677#discussion_r34958349"},"pull_request":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/677"}}},"pull_request":{"url":"https://api.github.com/repos/nilearn/nilearn/pulls/677","id":40036725,"html_url":"https://github.com/nilearn/nilearn/pull/677","diff_url":"https://github.com/nilearn/nilearn/pull/677.diff","patch_url":"https://github.com/nilearn/nilearn/pull/677.patch","issue_url":"https://api.github.com/repos/nilearn/nilearn/issues/677","number":677,"state":"open","locked":false,"title":"Tangent classif","user":{"login":"salma1601","id":7080143,"avatar_url":"https://avatars.githubusercontent.com/u/7080143?v=3","gravatar_id":"","url":"https://api.github.com/users/salma1601","html_url":"https://github.com/salma1601","followers_url":"https://api.github.com/users/salma1601/followers","following_url":"https://api.github.com/users/salma1601/following{/other_user}","gists_url":"https://api.github.com/users/salma1601/gists{/gist_id}","starred_url":"https://api.github.com/users/salma1601/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/salma1601/subscriptions","organizations_url":"https://api.github.com/users/salma1601/orgs","repos_url":"https://api.github.com/users/salma1601/repos","events_url":"https://api.github.com/users/salma1601/events{/privacy}","received_events_url":"https://api.github.com/users/salma1601/received_events","type":"User","site_admin":false},"body":"Classification on ADHD with different measures of connectivity. Addresses most comments of PR #227, except moving functions _cov_to_corr and prec_to_partial to nilearn._utils.\r\nI am wondering if the name 'tangent' is a good one.","created_at":"2015-07-15T15:39:11Z","updated_at":"2015-07-19T14:00:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6d02198232f901ee597a803d4ebda741a44766bb","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/nilearn/nilearn/pulls/677/commits","review_comments_url":"https://api.github.com/repos/nilearn/nilearn/pulls/677/comments","review_comment_url":"https://api.github.com/repos/nilearn/nilearn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/nilearn/nilearn/issues/677/comments","statuses_url":"https://api.github.com/repos/nilearn/nilearn/statuses/22f2e7cf22b22f7681977e91b8d4b275c17aec7f","head":{"label":"salma1601:tangent_classif","ref":"tangent_classif","sha":"22f2e7cf22b22f7681977e91b8d4b275c17aec7f","user":{"login":"salma1601","id":7080143,"avatar_url":"https://avatars.githubusercontent.com/u/7080143?v=3","gravatar_id":"","url":"https://api.github.com/users/salma1601","html_url":"https://github.com/salma1601","followers_url":"https://api.github.com/users/salma1601/followers","following_url":"https://api.github.com/users/salma1601/following{/other_user}","gists_url":"https://api.github.com/users/salma1601/gists{/gist_id}","starred_url":"https://api.github.com/users/salma1601/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/salma1601/subscriptions","organizations_url":"https://api.github.com/users/salma1601/orgs","repos_url":"https://api.github.com/users/salma1601/repos","events_url":"https://api.github.com/users/salma1601/events{/privacy}","received_events_url":"https://api.github.com/users/salma1601/received_events","type":"User","site_admin":false},"repo":{"id":18172102,"name":"nilearn","full_name":"salma1601/nilearn","owner":{"login":"salma1601","id":7080143,"avatar_url":"https://avatars.githubusercontent.com/u/7080143?v=3","gravatar_id":"","url":"https://api.github.com/users/salma1601","html_url":"https://github.com/salma1601","followers_url":"https://api.github.com/users/salma1601/followers","following_url":"https://api.github.com/users/salma1601/following{/other_user}","gists_url":"https://api.github.com/users/salma1601/gists{/gist_id}","starred_url":"https://api.github.com/users/salma1601/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/salma1601/subscriptions","organizations_url":"https://api.github.com/users/salma1601/orgs","repos_url":"https://api.github.com/users/salma1601/repos","events_url":"https://api.github.com/users/salma1601/events{/privacy}","received_events_url":"https://api.github.com/users/salma1601/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/salma1601/nilearn","description":"Machine learning for NeuroImaging in Python","fork":true,"url":"https://api.github.com/repos/salma1601/nilearn","forks_url":"https://api.github.com/repos/salma1601/nilearn/forks","keys_url":"https://api.github.com/repos/salma1601/nilearn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/salma1601/nilearn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/salma1601/nilearn/teams","hooks_url":"https://api.github.com/repos/salma1601/nilearn/hooks","issue_events_url":"https://api.github.com/repos/salma1601/nilearn/issues/events{/number}","events_url":"https://api.github.com/repos/salma1601/nilearn/events","assignees_url":"https://api.github.com/repos/salma1601/nilearn/assignees{/user}","branches_url":"https://api.github.com/repos/salma1601/nilearn/branches{/branch}","tags_url":"https://api.github.com/repos/salma1601/nilearn/tags","blobs_url":"https://api.github.com/repos/salma1601/nilearn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/salma1601/nilearn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/salma1601/nilearn/git/refs{/sha}","trees_url":"https://api.github.com/repos/salma1601/nilearn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/salma1601/nilearn/statuses/{sha}","languages_url":"https://api.github.com/repos/salma1601/nilearn/languages","stargazers_url":"https://api.github.com/repos/salma1601/nilearn/stargazers","contributors_url":"https://api.github.com/repos/salma1601/nilearn/contributors","subscribers_url":"https://api.github.com/repos/salma1601/nilearn/subscribers","subscription_url":"https://api.github.com/repos/salma1601/nilearn/subscription","commits_url":"https://api.github.com/repos/salma1601/nilearn/commits{/sha}","git_commits_url":"https://api.github.com/repos/salma1601/nilearn/git/commits{/sha}","comments_url":"https://api.github.com/repos/salma1601/nilearn/comments{/number}","issue_comment_url":"https://api.github.com/repos/salma1601/nilearn/issues/comments{/number}","contents_url":"https://api.github.com/repos/salma1601/nilearn/contents/{+path}","compare_url":"https://api.github.com/repos/salma1601/nilearn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/salma1601/nilearn/merges","archive_url":"https://api.github.com/repos/salma1601/nilearn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/salma1601/nilearn/downloads","issues_url":"https://api.github.com/repos/salma1601/nilearn/issues{/number}","pulls_url":"https://api.github.com/repos/salma1601/nilearn/pulls{/number}","milestones_url":"https://api.github.com/repos/salma1601/nilearn/milestones{/number}","notifications_url":"https://api.github.com/repos/salma1601/nilearn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/salma1601/nilearn/labels{/name}","releases_url":"https://api.github.com/repos/salma1601/nilearn/releases{/id}","created_at":"2014-03-27T10:26:53Z","updated_at":"2015-07-02T13:06:52Z","pushed_at":"2015-07-16T10:35:30Z","git_url":"git://github.com/salma1601/nilearn.git","ssh_url":"git@github.com:salma1601/nilearn.git","clone_url":"https://github.com/salma1601/nilearn.git","svn_url":"https://github.com/salma1601/nilearn","homepage":"http://nilearn.github.io","size":35133,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"tangent_salma"}},"base":{"label":"nilearn:master","ref":"master","sha":"ddef38a299ed0fedeee5f16f6cc08060dd998018","user":{"login":"nilearn","id":4646912,"avatar_url":"https://avatars.githubusercontent.com/u/4646912?v=3","gravatar_id":"","url":"https://api.github.com/users/nilearn","html_url":"https://github.com/nilearn","followers_url":"https://api.github.com/users/nilearn/followers","following_url":"https://api.github.com/users/nilearn/following{/other_user}","gists_url":"https://api.github.com/users/nilearn/gists{/gist_id}","starred_url":"https://api.github.com/users/nilearn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nilearn/subscriptions","organizations_url":"https://api.github.com/users/nilearn/orgs","repos_url":"https://api.github.com/users/nilearn/repos","events_url":"https://api.github.com/users/nilearn/events{/privacy}","received_events_url":"https://api.github.com/users/nilearn/received_events","type":"Organization","site_admin":false},"repo":{"id":1235740,"name":"nilearn","full_name":"nilearn/nilearn","owner":{"login":"nilearn","id":4646912,"avatar_url":"https://avatars.githubusercontent.com/u/4646912?v=3","gravatar_id":"","url":"https://api.github.com/users/nilearn","html_url":"https://github.com/nilearn","followers_url":"https://api.github.com/users/nilearn/followers","following_url":"https://api.github.com/users/nilearn/following{/other_user}","gists_url":"https://api.github.com/users/nilearn/gists{/gist_id}","starred_url":"https://api.github.com/users/nilearn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nilearn/subscriptions","organizations_url":"https://api.github.com/users/nilearn/orgs","repos_url":"https://api.github.com/users/nilearn/repos","events_url":"https://api.github.com/users/nilearn/events{/privacy}","received_events_url":"https://api.github.com/users/nilearn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nilearn/nilearn","description":"Machine learning for NeuroImaging in Python","fork":false,"url":"https://api.github.com/repos/nilearn/nilearn","forks_url":"https://api.github.com/repos/nilearn/nilearn/forks","keys_url":"https://api.github.com/repos/nilearn/nilearn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nilearn/nilearn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nilearn/nilearn/teams","hooks_url":"https://api.github.com/repos/nilearn/nilearn/hooks","issue_events_url":"https://api.github.com/repos/nilearn/nilearn/issues/events{/number}","events_url":"https://api.github.com/repos/nilearn/nilearn/events","assignees_url":"https://api.github.com/repos/nilearn/nilearn/assignees{/user}","branches_url":"https://api.github.com/repos/nilearn/nilearn/branches{/branch}","tags_url":"https://api.github.com/repos/nilearn/nilearn/tags","blobs_url":"https://api.github.com/repos/nilearn/nilearn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nilearn/nilearn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nilearn/nilearn/git/refs{/sha}","trees_url":"https://api.github.com/repos/nilearn/nilearn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nilearn/nilearn/statuses/{sha}","languages_url":"https://api.github.com/repos/nilearn/nilearn/languages","stargazers_url":"https://api.github.com/repos/nilearn/nilearn/stargazers","contributors_url":"https://api.github.com/repos/nilearn/nilearn/contributors","subscribers_url":"https://api.github.com/repos/nilearn/nilearn/subscribers","subscription_url":"https://api.github.com/repos/nilearn/nilearn/subscription","commits_url":"https://api.github.com/repos/nilearn/nilearn/commits{/sha}","git_commits_url":"https://api.github.com/repos/nilearn/nilearn/git/commits{/sha}","comments_url":"https://api.github.com/repos/nilearn/nilearn/comments{/number}","issue_comment_url":"https://api.github.com/repos/nilearn/nilearn/issues/comments{/number}","contents_url":"https://api.github.com/repos/nilearn/nilearn/contents/{+path}","compare_url":"https://api.github.com/repos/nilearn/nilearn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nilearn/nilearn/merges","archive_url":"https://api.github.com/repos/nilearn/nilearn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nilearn/nilearn/downloads","issues_url":"https://api.github.com/repos/nilearn/nilearn/issues{/number}","pulls_url":"https://api.github.com/repos/nilearn/nilearn/pulls{/number}","milestones_url":"https://api.github.com/repos/nilearn/nilearn/milestones{/number}","notifications_url":"https://api.github.com/repos/nilearn/nilearn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nilearn/nilearn/labels{/name}","releases_url":"https://api.github.com/repos/nilearn/nilearn/releases{/id}","created_at":"2011-01-09T19:02:23Z","updated_at":"2015-07-14T23:48:39Z","pushed_at":"2015-07-19T13:27:46Z","git_url":"git://github.com/nilearn/nilearn.git","ssh_url":"git@github.com:nilearn/nilearn.git","clone_url":"https://github.com/nilearn/nilearn.git","svn_url":"https://github.com/nilearn/nilearn","homepage":"http://nilearn.github.io","size":14006,"stargazers_count":101,"watchers_count":101,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":71,"mirror_url":null,"open_issues_count":84,"forks":71,"open_issues":84,"watchers":101,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/677"},"html":{"href":"https://github.com/nilearn/nilearn/pull/677"},"issue":{"href":"https://api.github.com/repos/nilearn/nilearn/issues/677"},"comments":{"href":"https://api.github.com/repos/nilearn/nilearn/issues/677/comments"},"review_comments":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/677/comments"},"review_comment":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/677/commits"},"statuses":{"href":"https://api.github.com/repos/nilearn/nilearn/statuses/22f2e7cf22b22f7681977e91b8d4b275c17aec7f"}}}}