{"action":"created","comment":{"url":"https://api.github.com/repos/nilearn/nilearn/pulls/comments/34710379","id":34710379,"diff_hunk":"@@ -0,0 +1,291 @@\n+\"\"\"Implementation of multiple proximal operators for TV-L1, S-LASSO, etc.\n+\n+\"\"\"\n+# Author: DOHMATOB Elvis Dopgima,\n+#         VAROQUAUX Gael,\n+#         GRAMFORT Alexandre,\n+# License: simplified BSD\n+\n+from math import sqrt\n+import numpy as np\n+from .objective_functions import tv_l1_from_gradient, div_id, gradient_id\n+\n+\n+def _prox_l1(y, alpha, copy=True):\n+    \"\"\"proximity operator for L1 norm\"\"\"\n+    shrink = np.zeros(y.shape)\n+    if copy:\n+        y = y.copy()\n+    y_nz = y.nonzero()\n+    shrink[y_nz] = np.maximum(1 - alpha / np.abs(y[y_nz]), 0)\n+    y *= shrink\n+    return y\n+\n+\n+def _prox_l1_with_intercept(x, tau):\n+    \"\"\"The same as prox_l1, but just for the n-1 components\"\"\"\n+    x[:-1] = _prox_l1(x[:-1], tau)\n+    return x\n+\n+\n+def _projector_on_tvl1_dual(grad, l1_ratio):\n+    \"\"\"\n+    modifies IN PLACE the gradient + id to project it\n+    on the l21 unit ball in the gradient direction and the L1 ball in the\n+    identity direction\n+    \"\"\"\n+\n+    # The l21 ball for the gradient direction\n+    if l1_ratio < 1.:\n+        end = len(grad) - int(l1_ratio > 0.)\n+        norm = np.sqrt(np.sum(grad[:end] * grad[:end], 0))\n+        norm.clip(1., out=norm)  # set everythx < 1 to 1\n+        for grad_comp in grad[:end]:\n+            grad_comp /= norm\n+\n+    # The L1 ball for the identity direction\n+    if l1_ratio > 0.:\n+        norm = np.abs(grad[-1])\n+        norm.clip(1., out=norm)\n+        grad[-1] /= norm\n+\n+    return grad\n+\n+\n+def _dual_gap_prox_tvl1(input_img_norm, new, gap, weight, l1_ratio=1.):\n+    \"\"\"\n+    Dual gap of total variation denoising\n+    see \"Total variation regularization for fMRI-based prediction of behavior\",\n+    by Michel et al. (2011) for a derivation of the dual gap\n+    \"\"\"\n+    tv_new = tv_l1_from_gradient(gradient_id(new, l1_ratio=l1_ratio))\n+    gap = gap.ravel()\n+    d_gap = np.dot(gap, gap) + 2 * weight * tv_new - input_img_norm + (\n+        new * new).sum()\n+    return 0.5 * d_gap\n+\n+\n+def _objective_function_prox_tvl1(\n+        input_img, output_img, gradient, weight):\n+    diff = (input_img - output_img).ravel()\n+    return (.5 * (diff * diff).sum()\n+            + weight * tv_l1_from_gradient(gradient))\n+\n+\n+def _prox_tvl1(input_img, l1_ratio=.05, weight=50, dgap_tol=5.e-5, x_tol=None,\n+              max_iter=200, check_gap_frequency=4, val_min=None, val_max=None,\n+              verbose=False, fista=True, init=None):\n+    \"\"\"\n+    Compute the TV-L1 proximal (ie total-variation +l1 denoising) on 3d images.\n+\n+    Find the argmin `res` of\n+        1/2 * ||im - res||^2 + weight * TVl1(res),\n+\n+    Parameters\n+    ----------\n+    input_img : ndarray of floats (2-d or 3-d)\n+        Input data to be denoised. `im` can be of any numeric type,\n+        but it is cast into an ndarray of floats for the computation\n+        of the denoised image.\n+\n+    weight : float, optional\n+        Denoising weight. The greater ``weight``, the more denoising (at\n+        the expense of fidelity to ``input``)\n+\n+    dgap_tol : float, optional\n+        Precision required. The distance to the exact solution is computed\n+        by the dual gap of the optimization problem and rescaled by the\n+        squared l2 norm of the image (for contrast invariance).\n+\n+    x_tol : float or None, optional\n+        The maximal relative difference between input and output. If\n+        specified, this specifies a stopping criterion on x, rather than\n+        the dual gap.\n+\n+    max_iter : int, optional\n+        Maximal number of iterations used for the optimization.\n+\n+    val_min : None or float, optional\n+        An optional lower bound constraint on the reconstructed image.\n+\n+    val_max : None or float, optional\n+        An optional upper bound constraint on the reconstructed image.\n+\n+    verbose : bool, optional\n+        If True, print the dual gap of the optimization\n+\n+    fista : bool, optional\n+        If True, uses a FISTA loop to perform the optimization.\n+        if False, uses an ISTA loop.\n+\n+    callback : callable\n+        Callable that takes the local variables at each\n+        steps. Useful for tracking.\n+\n+    init : array of shape shape as im\n+        Starting point for the optimization.\n+\n+    Returns\n+    -------\n+    out : ndarray\n+        TV-l1-denoised image.\n+\n+    Notes\n+    -----\n+    The principle of total variation denoising is explained in\n+    http://en.wikipedia.org/wiki/Total_variation_denoising\n+\n+    The principle of total variation denoising is to minimize the\n+    total variation of the image, which can be roughly described as\n+    the integral of the norm of the image gradient. Total variation\n+    denoising tends to produce \"cartoon-like\" images, that is,\n+    piecewise-constant images.\n+\n+    This function implements the FISTA (Fast Iterative Shrinkage\n+    Thresholding Algorithm) algorithm of Beck et Teboulle, adapted to\n+    total variation denoising in \"Fast gradient-based algorithms for\n+    constrained total variation image denoising and deblurring problems\"\n+    (2009).\n+\n+    For details on implementing the bound constraints, read the aforementioned\n+    Beck and Teboulle paper.\n+    \"\"\"\n+    weight = float(weight)\n+    input_img_flat = input_img.view()\n+    input_img_flat.shape = input_img.size\n+    input_img_norm = np.dot(input_img_flat, input_img_flat)\n+    if not input_img.dtype.kind == 'f':\n+        input_img = input_img.astype(np.float)\n+    shape = [len(input_img.shape) + 1] + list(input_img.shape)\n+    grad_im = np.zeros(shape)\n+    grad_aux = np.zeros(shape)\n+    t = 1.\n+    i = 0\n+    lipschitz_constant = 1.1 * (4 * input_img.ndim * (1 - l1_ratio)\n+                                ** 2 + l1_ratio ** 2)\n+\n+    # negated_output is the negated primal variable in the optimization\n+    # loop\n+    if init is None:\n+        negated_output = -input_img\n+    else:\n+        negated_output = -init\n+\n+    # Clipping values for the inner loop\n+    negated_val_min = np.inf\n+    negated_val_max = -np.inf\n+    if val_min is not None:\n+        negated_val_min = -val_min\n+    if val_max is not None:\n+        negated_val_max = -val_max\n+    if True or (val_min is not None or val_max is not None):\n+        # With bound constraints, the stopping criterion is on the\n+        # evolution of the output\n+        negated_output_old = negated_output.copy()\n+    grad_tmp = None\n+    old_dgap = np.inf\n+    dgap = np.inf\n+\n+    # A boolean to control if we are going to do a fista step\n+    fista_step = fista\n+\n+    while i < max_iter:\n+        grad_tmp = gradient_id(negated_output, l1_ratio=l1_ratio)\n+        grad_tmp *= 1. / (lipschitz_constant * weight)\n+        grad_aux += grad_tmp\n+        grad_tmp = _projector_on_tvl1_dual(\n+            grad_aux, l1_ratio\n+            )\n+\n+        # Careful, in the next few lines, grad_tmp and grad_aux are a\n+        # view on the same array, as _projector_on_tvl1_dual returns a view\n+        # on the input array\n+        t_new = 0.5 * (1. + sqrt(1. + 4. * t * t))\n+        t_factor = (t - 1.) / t_new\n+        if fista_step:\n+            grad_aux = (1 + t_factor) * grad_tmp - t_factor * grad_im\n+        else:\n+            grad_aux = grad_tmp\n+        grad_im = grad_tmp\n+        t = t_new\n+        gap = weight * div_id(grad_aux, l1_ratio=l1_ratio)\n+\n+        # Compute the primal variable\n+        negated_output = gap - input_img\n+        if (val_min is not None or val_max is not None):\n+            negated_output = negated_output.clip(negated_val_max,\n+                                                 negated_val_min,\n+                                                 out=negated_output)\n+        if (i % check_gap_frequency) == 0:\n+            if x_tol is None:\n+                # Stopping criterion based on the dual gap\n+                if val_min is not None or val_max is not None:\n+                    # We need to recompute the dual variable\n+                    gap = negated_output + input_img\n+                old_dgap = dgap\n+                dgap = _dual_gap_prox_tvl1(input_img_norm, -negated_output,\n+                                           gap, weight, l1_ratio=l1_ratio)\n+                if verbose:\n+                    print('\\tProxTVl1: Iteration % 2i, dual gap: % 6.3e' % (\n+                        i, dgap))\n+                if dgap < dgap_tol:\n+                    break\n+                if old_dgap < dgap:\n+                    # M-FISTA strategy: switch to an ISTA to have\n+                    # monotone convergence\n+                    fista_step = False\n+                elif fista:\n+                    fista_step = True\n+            else:\n+                # Stopping criterion based on x_tol\n+                diff = np.max(np.abs(negated_output_old - negated_output))\n+                diff /= np.max(np.abs(negated_output))\n+                if verbose:\n+                    print(('\\tProxTVl1 iteration % 2i, relative difference:'\n+                           ' % 6.3e, energy: % 6.3e' ) % (i, diff,\n+                            _objective_function_prox_tvl1(\n+                                input_img, -negated_output, gradient_id(\n+                                    negated_output, l1_ratio=l1_ratio),\n+                                weight)))\n+                if diff < x_tol:\n+                    break\n+                negated_output_old = negated_output\n+        i += 1\n+\n+    # Compute the primal variable, however, here we must use the ista\n+    # value, not the fista one\n+    output = input_img - weight * div_id(grad_im, l1_ratio=l1_ratio)\n+    if (val_min is not None or val_max is not None):\n+        output = output.clip(val_min, val_max, out=output)\n+    return output, dict(converged=(i < max_iter))\n+\n+\n+def _prox_tvl1_with_intercept(w, shape, l1_ratio, weight, dgap_tol,\n+                              max_iter=5000, init=None, verbose=False):\n+    \"\"\"\n+    Computation of TV-L1 prox, taking into account the intercept.\n+\n+    Parameters\n+    ----------\n+    weight : float\n+       Weight in prox. This would be something like `alpha_ * stepsize`,\n+       where `alpha_` is the effective (i.e. re-scaled) alpha.\n+\n+    w : ndarray, shape (w_size,)\n+        The point at which the prox is being computed\n+\n+    init : ndarray, shape (w_size - 1,), optional (default None)\n+        Initialization vector for the prox.\n+\n+    dgap_tol : float\n+        Dual-gap tolerance for TV-L1 prox operator approximation loop.\n+","path":"nilearn/decoding/proximal_operators.py","position":282,"original_position":282,"commit_id":"cad3997ecd39f8f840c82d880632c2df35d55c2c","original_commit_id":"4e7e25e87ea36b6065b37eb04f4fd5a773e70a73","user":{"login":"bthirion","id":234454,"avatar_url":"https://avatars.githubusercontent.com/u/234454?v=3","gravatar_id":"","url":"https://api.github.com/users/bthirion","html_url":"https://github.com/bthirion","followers_url":"https://api.github.com/users/bthirion/followers","following_url":"https://api.github.com/users/bthirion/following{/other_user}","gists_url":"https://api.github.com/users/bthirion/gists{/gist_id}","starred_url":"https://api.github.com/users/bthirion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bthirion/subscriptions","organizations_url":"https://api.github.com/users/bthirion/orgs","repos_url":"https://api.github.com/users/bthirion/repos","events_url":"https://api.github.com/users/bthirion/events{/privacy}","received_events_url":"https://api.github.com/users/bthirion/received_events","type":"User","site_admin":false},"body":"max_iter, init, verbose not in docstrings.","created_at":"2015-07-15T18:13:56Z","updated_at":"2015-07-15T18:13:56Z","html_url":"https://github.com/nilearn/nilearn/pull/657#discussion_r34710379","pull_request_url":"https://api.github.com/repos/nilearn/nilearn/pulls/657","_links":{"self":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/comments/34710379"},"html":{"href":"https://github.com/nilearn/nilearn/pull/657#discussion_r34710379"},"pull_request":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/657"}}},"pull_request":{"url":"https://api.github.com/repos/nilearn/nilearn/pulls/657","id":39890490,"html_url":"https://github.com/nilearn/nilearn/pull/657","diff_url":"https://github.com/nilearn/nilearn/pull/657.diff","patch_url":"https://github.com/nilearn/nilearn/pull/657.patch","issue_url":"https://api.github.com/repos/nilearn/nilearn/issues/657","number":657,"state":"open","locked":false,"title":"SpaceNet (all batteries loaded...). This PR succeeds PR #219 (aka unicorn factory)","user":{"login":"dohmatob","id":634068,"avatar_url":"https://avatars.githubusercontent.com/u/634068?v=3","gravatar_id":"","url":"https://api.github.com/users/dohmatob","html_url":"https://github.com/dohmatob","followers_url":"https://api.github.com/users/dohmatob/followers","following_url":"https://api.github.com/users/dohmatob/following{/other_user}","gists_url":"https://api.github.com/users/dohmatob/gists{/gist_id}","starred_url":"https://api.github.com/users/dohmatob/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dohmatob/subscriptions","organizations_url":"https://api.github.com/users/dohmatob/orgs","repos_url":"https://api.github.com/users/dohmatob/repos","events_url":"https://api.github.com/users/dohmatob/events{/privacy}","received_events_url":"https://api.github.com/users/dohmatob/received_events","type":"User","site_admin":false},"body":"This PR succeeds PR #219 (aka unicorn factory). All discussions should be done here henceforth. #219 is now classified, and should be referred to solely for histological purposes.","created_at":"2015-07-14T07:56:20Z","updated_at":"2015-07-15T18:13:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"59bc656675ad47faf440b6815316ae317172504d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/nilearn/nilearn/pulls/657/commits","review_comments_url":"https://api.github.com/repos/nilearn/nilearn/pulls/657/comments","review_comment_url":"https://api.github.com/repos/nilearn/nilearn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/nilearn/nilearn/issues/657/comments","statuses_url":"https://api.github.com/repos/nilearn/nilearn/statuses/cad3997ecd39f8f840c82d880632c2df35d55c2c","head":{"label":"dohmatob:sparse-models","ref":"sparse-models","sha":"cad3997ecd39f8f840c82d880632c2df35d55c2c","user":{"login":"dohmatob","id":634068,"avatar_url":"https://avatars.githubusercontent.com/u/634068?v=3","gravatar_id":"","url":"https://api.github.com/users/dohmatob","html_url":"https://github.com/dohmatob","followers_url":"https://api.github.com/users/dohmatob/followers","following_url":"https://api.github.com/users/dohmatob/following{/other_user}","gists_url":"https://api.github.com/users/dohmatob/gists{/gist_id}","starred_url":"https://api.github.com/users/dohmatob/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dohmatob/subscriptions","organizations_url":"https://api.github.com/users/dohmatob/orgs","repos_url":"https://api.github.com/users/dohmatob/repos","events_url":"https://api.github.com/users/dohmatob/events{/privacy}","received_events_url":"https://api.github.com/users/dohmatob/received_events","type":"User","site_admin":false},"repo":{"id":10718029,"name":"nilearn","full_name":"dohmatob/nilearn","owner":{"login":"dohmatob","id":634068,"avatar_url":"https://avatars.githubusercontent.com/u/634068?v=3","gravatar_id":"","url":"https://api.github.com/users/dohmatob","html_url":"https://github.com/dohmatob","followers_url":"https://api.github.com/users/dohmatob/followers","following_url":"https://api.github.com/users/dohmatob/following{/other_user}","gists_url":"https://api.github.com/users/dohmatob/gists{/gist_id}","starred_url":"https://api.github.com/users/dohmatob/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dohmatob/subscriptions","organizations_url":"https://api.github.com/users/dohmatob/orgs","repos_url":"https://api.github.com/users/dohmatob/repos","events_url":"https://api.github.com/users/dohmatob/events{/privacy}","received_events_url":"https://api.github.com/users/dohmatob/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dohmatob/nilearn","description":"NeuroImaging with the Scikit-learn: fMRI inverse inference tutorial","fork":true,"url":"https://api.github.com/repos/dohmatob/nilearn","forks_url":"https://api.github.com/repos/dohmatob/nilearn/forks","keys_url":"https://api.github.com/repos/dohmatob/nilearn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dohmatob/nilearn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dohmatob/nilearn/teams","hooks_url":"https://api.github.com/repos/dohmatob/nilearn/hooks","issue_events_url":"https://api.github.com/repos/dohmatob/nilearn/issues/events{/number}","events_url":"https://api.github.com/repos/dohmatob/nilearn/events","assignees_url":"https://api.github.com/repos/dohmatob/nilearn/assignees{/user}","branches_url":"https://api.github.com/repos/dohmatob/nilearn/branches{/branch}","tags_url":"https://api.github.com/repos/dohmatob/nilearn/tags","blobs_url":"https://api.github.com/repos/dohmatob/nilearn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dohmatob/nilearn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dohmatob/nilearn/git/refs{/sha}","trees_url":"https://api.github.com/repos/dohmatob/nilearn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dohmatob/nilearn/statuses/{sha}","languages_url":"https://api.github.com/repos/dohmatob/nilearn/languages","stargazers_url":"https://api.github.com/repos/dohmatob/nilearn/stargazers","contributors_url":"https://api.github.com/repos/dohmatob/nilearn/contributors","subscribers_url":"https://api.github.com/repos/dohmatob/nilearn/subscribers","subscription_url":"https://api.github.com/repos/dohmatob/nilearn/subscription","commits_url":"https://api.github.com/repos/dohmatob/nilearn/commits{/sha}","git_commits_url":"https://api.github.com/repos/dohmatob/nilearn/git/commits{/sha}","comments_url":"https://api.github.com/repos/dohmatob/nilearn/comments{/number}","issue_comment_url":"https://api.github.com/repos/dohmatob/nilearn/issues/comments{/number}","contents_url":"https://api.github.com/repos/dohmatob/nilearn/contents/{+path}","compare_url":"https://api.github.com/repos/dohmatob/nilearn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dohmatob/nilearn/merges","archive_url":"https://api.github.com/repos/dohmatob/nilearn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dohmatob/nilearn/downloads","issues_url":"https://api.github.com/repos/dohmatob/nilearn/issues{/number}","pulls_url":"https://api.github.com/repos/dohmatob/nilearn/pulls{/number}","milestones_url":"https://api.github.com/repos/dohmatob/nilearn/milestones{/number}","notifications_url":"https://api.github.com/repos/dohmatob/nilearn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dohmatob/nilearn/labels{/name}","releases_url":"https://api.github.com/repos/dohmatob/nilearn/releases{/id}","created_at":"2013-06-16T09:21:03Z","updated_at":"2015-05-18T08:46:19Z","pushed_at":"2015-07-15T17:02:24Z","git_url":"git://github.com/dohmatob/nilearn.git","ssh_url":"git@github.com:dohmatob/nilearn.git","clone_url":"https://github.com/dohmatob/nilearn.git","svn_url":"https://github.com/dohmatob/nilearn","homepage":"http://nilearn.github.com/","size":8838,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"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-15T18:13:14Z","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":13295,"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":90,"forks":71,"open_issues":90,"watchers":101,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/657"},"html":{"href":"https://github.com/nilearn/nilearn/pull/657"},"issue":{"href":"https://api.github.com/repos/nilearn/nilearn/issues/657"},"comments":{"href":"https://api.github.com/repos/nilearn/nilearn/issues/657/comments"},"review_comments":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/657/comments"},"review_comment":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/nilearn/nilearn/pulls/657/commits"},"statuses":{"href":"https://api.github.com/repos/nilearn/nilearn/statuses/cad3997ecd39f8f840c82d880632c2df35d55c2c"}}}}