Multichannel version of BIRD (S-BIRD) seeking Structured Sparsity

    Parameters
    ----------
     X : array, shape (n_channels, n_times)
        The numpy n_channels-vy-n_samples array to be denoised where n_channels
         is the number of sensors and n_samples the dimension
    scales : list of int
        The list of MDCT scales that will be used to built the
        dictionary Phi
    n_runs : int
        the number of runs (n_runs in the paper)
    p_above : float
        probability of appearance of the max above which the noise hypothesis
        is considered false
    p_active : float
        proportion of active channels (l in the paper)
    max_iter : int
        The maximum number of iterations in one pursuit.
    random_state : None | int | np.random.RandomState
        To specify the random generator state (seed).
    n_jobs : int
        The number of jobs to run in parallel.
    memory : instance of Memory
        The object to use to cache some computations. If cachedir is None, no
        caching is performed.
    verbose : bool
        verbose mode

    Returns
    -------
    X_denoise : array, shape (n_channels, n_times)
        The denoised data.

def s_bird(X, scales, n_runs, p_above, p_active=1, max_iter=100,
           random_state=None, n_jobs=1, memory=Memory(None), verbose=False):
    """ Multichannel version of BIRD (S-BIRD) seeking Structured Sparsity

    Parameters
    ----------
     X : array, shape (n_channels, n_times)
        The numpy n_channels-vy-n_samples array to be denoised where n_channels
         is the number of sensors and n_samples the dimension
    scales : list of int
        The list of MDCT scales that will be used to built the
        dictionary Phi
    n_runs : int
        the number of runs (n_runs in the paper)
    p_above : float
        probability of appearance of the max above which the noise hypothesis
        is considered false
    p_active : float
        proportion of active channels (l in the paper)
    max_iter : int
        The maximum number of iterations in one pursuit.
    random_state : None | int | np.random.RandomState
        To specify the random generator state (seed).
    n_jobs : int
        The number of jobs to run in parallel.
    memory : instance of Memory
        The object to use to cache some computations. If cachedir is None, no
        caching is performed.
    verbose : bool
        verbose mode

    Returns
    -------
    X_denoise : array, shape (n_channels, n_times)
        The denoised data.
    """
    X, prepad = _pad(X)
    # Computing Lambda_W(Phi, p_above)
    n_channels = X.shape[0]
    n_samples = float(X.shape[1])
    # size of the full shift-invariant dictionary
    M = np.sum(np.array(scales) / 2) * n_samples
    sigma = sqrt((1.0 - (2.0 / np.pi)) / float(n_samples))
    Lambda_W = sigma * sqrt(2.0) * erfinv((1.0 - p_above) ** (1.0 / float(M)))

    lint = int(n_channels * p_active)

    this_stop_crit = partial(stop_crit, lint=lint)  # XXX : check lint here
    this_selection_rule = partial(selection_rule, lint=lint)

    print("Starting S-BIRD with MDCT dictionary of %d Atoms."
          " Lambda_W=%1.3f, n_runs=%d, p_active=%1.1f" % (M, Lambda_W,
                                                          n_runs, p_active))
    denoised = _bird_core(X, scales, n_runs, Lambda_W, verbose=verbose,
                          stop_crit=this_stop_crit, n_jobs=n_jobs,
                          selection_rule=this_selection_rule,
                          max_iter=max_iter,
                          indep=False, memory=memory)

    return denoised[:, prepad:]