# Buggy code
def fastica(
    X,
    n_components=None,
    algorithm="parallel",
    whiten=True,
    fun="logcosh",
    fun_args=None,
    max_iter=200,
    tol=1e-04,
    w_init=None,
    random_state=None,
    return_X_mean=False,
    compute_sources=True,
):
    """Perform Fast Independent Component Analysis.

    Parameters
    ----------
    X : array-like, shape (n_samples, n_features)
        Training vector, where n_samples is the number of samples and
        n_features is the number of features.

    n_components : int, optional
        Number of components to extract. If None no dimension reduction
        is performed.

    algorithm : {'parallel', 'deflation'}, optional
        Apply a parallel or deflational FASTICA algorithm.

    whiten : boolean, optional
        If True perform an initial whitening of the data.
        If False, the data is assumed to have already been
        preprocessed: it should be centered, normed and white.
        Otherwise you will get incorrect results.
        In this case the parameter n_components will be ignored.

    fun : string or function, optional. Default: 'logcosh'
        The functional form of the G function used in the
        approximation to neg-entropy. Could be either 'logcosh', 'exp',
        or 'cube'.
        You can also provide your own function. It should return a tuple
        containing the value of the function, and of its derivative, in the
        point. Example:

        def my_g(x):
            return x ** 3, 3 * x ** 2

    fun_args : dictionary, optional
        Arguments to send to the functional form.
        If empty or None and if fun='logcosh', fun_args will take value
        {'alpha' : 1.0}

    max_iter : int, optional
        Maximum number of iterations to perform.

    tol: float, optional
        A positive scalar giving the tolerance at which the
        un-mixing matrix is considered to have converged.

    w_init : (n_components, n_components) array, optional
        Initial un-mixing array of dimension (n.comp,n.comp).
        If None (default) then an array of normal r.v.'s is used.

    random_state : int or RandomState
        Pseudo number generator state used for random sampling.

    return_X_mean : bool, optional
        If True, X_mean is returned too.

    compute_sources : bool, optional
        If False, sources are not computes but only the rotation matrix. This
        can save memory when working with big data. Defaults to True.

    Returns
    -------
    K : array, shape (n_components, n_features) | None.
        If whiten is 'True', K is the pre-whitening matrix that projects data
        onto the first n_components principal components. If whiten is 'False',
        K is 'None'.

    W : array, shape (n_components, n_components)
        Estimated un-mixing matrix.
        The mixing matrix can be obtained by::

            w = np.dot(W, K.T)
            A = w.T * (w * w.T).I

    S : array, shape (n_components, n_samples) | None
        Estimated source matrix

    X_mean : array, shape (n_features, )
        The mean over features. Returned only if return_X_mean is True.

    Notes
    -----

    The data matrix X is considered to be a linear combination of
    non-Gaussian (independent) components i.e. X = AS where columns of S
    contain the independent components and A is a linear mixing
    matrix. In short ICA attempts to `un-mix' the data by estimating an
    un-mixing matrix W where ``S = W K X.``

    This implementation was originally made for data of shape
    [n_features, n_samples]. Now the input is transposed
    before the algorithm is applied. This makes it slightly
    faster for Fortran-ordered input.

    Implemented using FastICA:
    `A. Hyvarinen and E. Oja, Independent Component Analysis:
    Algorithms and Applications, Neural Networks, 13(4-5), 2000,
    pp. 411-430`

    """
    random_state = check_random_state(random_state)
    fun_args = {} if fun_args is None else fun_args
    # make interface compatible with other decompositions
    # a copy is required only for non whitened data
    X = array2d(X, copy=whiten).T

    alpha = fun_args.get("alpha", 1.0)
    if not 1 <= alpha <= 2:
        raise ValueError("alpha must be in [1,2]")

    if fun == "logcosh":
        g = _logcosh
    elif fun == "exp":
        g = _exp
    elif fun == "cube":
        g = _cube
    elif callable(fun):

        def g(x, fun_args):
            return fun(x, **fun_args)
    else:
        exc = ValueError if isinstance(fun, six.string_types) else TypeError
        raise exc(
            "Unknown function %r;"
            " should be one of 'logcosh', 'exp', 'cube' or callable" % fun
        )

    n, p = X.shape

    if not whiten and n_components is not None:
        n_components = None
        warnings.warn("Ignoring n_components with whiten=False.")

    if n_components is None:
        n_components = min(n, p)
    if n_components > min(n, p):
        n_components = min(n, p)
        print("n_components is too large: it will be set to %s" % n_components)

    if whiten:
        # Centering the columns (ie the variables)
        X_mean = X.mean(axis=-1)
        X -= X_mean[:, np.newaxis]

        # Whitening and preprocessing by PCA
        u, d, _ = linalg.svd(X, full_matrices=False)

        del _
        K = (u / d).T[:n_components]  # see (6.33) p.140
        del u, d
        X1 = np.dot(K, X)
        # see (13.6) p.267 Here X1 is white and data
        # in X has been projected onto a subspace by PCA
        X1 *= np.sqrt(p)
    else:
        # X must be casted to floats to avoid typing issues with numpy
        # 2.0 and the line below
        X1 = as_float_array(X, copy=False)  # copy has been taken care of

    if w_init is None:
        w_init = np.asarray(
            random_state.normal(size=(n_components, n_components)), dtype=X1.dtype
        )

    else:
        w_init = np.asarray(w_init)
        if w_init.shape != (n_components, n_components):
            raise ValueError(
                "w_init has invalid shape -- should be %(shape)s"
                % {"shape": (n_components, n_components)}
            )

    kwargs = {
        "tol": tol,
        "g": g,
        "fun_args": fun_args,
        "max_iter": max_iter,
        "w_init": w_init,
    }

    if algorithm == "parallel":
        W = _ica_par(X1, **kwargs)
    elif algorithm == "deflation":
        W = _ica_def(X1, **kwargs)
    else:
        raise ValueError("Invalid algorithm: must be either `parallel` or `deflation`.")
    del X1

    if whiten:
        if compute_sources:
            S = fast_dot(fast_dot(W, K), X).T
        else:
            S = None
        if return_X_mean:
            return K, W, S, X_mean
        else:
            return K, W, S
    else:
        if compute_sources:
            S = fast_dot(W, X).T
        else:
            S = None
        if return_X_mean:
            return None, W, S, None
        else:
            return None, W, S


# Traceback (IndexError)
======================================================================
ERROR: sklearn.tests.test_common.test_regressors_train('RANSACRegressor', <class 'sklearn.linear_model.ransac.RANSACRegr
essor'>, array([[-0.44836249, -0.47282444, -1.20608008, ..., -0.75500806,
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\nose\case.py", line 197, in runTest
self.test(*self.arg)
File "C:\Python27\lib\site-packages\sklearn\tests\test_common.py", line 850, in check_regressors_train
assert_raises(ValueError, regressor.fit, X, y[:-1])
File "C:\Python27\lib\unittest\case.py", line 473, in assertRaises
callableObj(*args, **kwargs)
File "C:\Python27\lib\site-packages\sklearn\linear_model\ransac.py", line 261, in fit
y_subset = y[subset_idxs]
IndexError: index 199 is out of bounds for axis 0 with size 199

# Fixed code
def fastica(
    X,
    n_components=None,
    algorithm="parallel",
    whiten=True,
    fun="logcosh",
    fun_args=None,
    max_iter=200,
    tol=1e-04,
    w_init=None,
    random_state=None,
    return_X_mean=False,
    compute_sources=True,
):
    """Perform Fast Independent Component Analysis.

    Parameters
    ----------
    X : array-like, shape (n_samples, n_features)
        Training vector, where n_samples is the number of samples and
        n_features is the number of features.

    n_components : int, optional
        Number of components to extract. If None no dimension reduction
        is performed.

    algorithm : {'parallel', 'deflation'}, optional
        Apply a parallel or deflational FASTICA algorithm.

    whiten : boolean, optional
        If True perform an initial whitening of the data.
        If False, the data is assumed to have already been
        preprocessed: it should be centered, normed and white.
        Otherwise you will get incorrect results.
        In this case the parameter n_components will be ignored.

    fun : string or function, optional. Default: 'logcosh'
        The functional form of the G function used in the
        approximation to neg-entropy. Could be either 'logcosh', 'exp',
        or 'cube'.
        You can also provide your own function. It should return a tuple
        containing the value of the function, and of its derivative, in the
        point. Example:

        def my_g(x):
            return x ** 3, 3 * x ** 2

    fun_args : dictionary, optional
        Arguments to send to the functional form.
        If empty or None and if fun='logcosh', fun_args will take value
        {'alpha' : 1.0}

    max_iter : int, optional
        Maximum number of iterations to perform.

    tol: float, optional
        A positive scalar giving the tolerance at which the
        un-mixing matrix is considered to have converged.

    w_init : (n_components, n_components) array, optional
        Initial un-mixing array of dimension (n.comp,n.comp).
        If None (default) then an array of normal r.v.'s is used.

    random_state : int or RandomState
        Pseudo number generator state used for random sampling.

    return_X_mean : bool, optional
        If True, X_mean is returned too.

    compute_sources : bool, optional
        If False, sources are not computed, but only the rotation matrix.
        This can save memory when working with big data. Defaults to True.

    Returns
    -------
    K : array, shape (n_components, n_features) | None.
        If whiten is 'True', K is the pre-whitening matrix that projects data
        onto the first n_components principal components. If whiten is 'False',
        K is 'None'.

    W : array, shape (n_components, n_components)
        Estimated un-mixing matrix.
        The mixing matrix can be obtained by::

            w = np.dot(W, K.T)
            A = w.T * (w * w.T).I

    S : array, shape (n_components, n_samples) | None
        Estimated source matrix

    X_mean : array, shape (n_features, )
        The mean over features. Returned only if return_X_mean is True.

    Notes
    -----

    The data matrix X is considered to be a linear combination of
    non-Gaussian (independent) components i.e. X = AS where columns of S
    contain the independent components and A is a linear mixing
    matrix. In short ICA attempts to `un-mix' the data by estimating an
    un-mixing matrix W where ``S = W K X.``

    This implementation was originally made for data of shape
    [n_features, n_samples]. Now the input is transposed
    before the algorithm is applied. This makes it slightly
    faster for Fortran-ordered input.

    Implemented using FastICA:
    `A. Hyvarinen and E. Oja, Independent Component Analysis:
    Algorithms and Applications, Neural Networks, 13(4-5), 2000,
    pp. 411-430`

    """
    random_state = check_random_state(random_state)
    fun_args = {} if fun_args is None else fun_args
    # make interface compatible with other decompositions
    # a copy is required only for non whitened data
    X = array2d(X, copy=whiten).T

    alpha = fun_args.get("alpha", 1.0)
    if not 1 <= alpha <= 2:
        raise ValueError("alpha must be in [1,2]")

    if fun == "logcosh":
        g = _logcosh
    elif fun == "exp":
        g = _exp
    elif fun == "cube":
        g = _cube
    elif callable(fun):

        def g(x, fun_args):
            return fun(x, **fun_args)
    else:
        exc = ValueError if isinstance(fun, six.string_types) else TypeError
        raise exc(
            "Unknown function %r;"
            " should be one of 'logcosh', 'exp', 'cube' or callable" % fun
        )

    n, p = X.shape

    if not whiten and n_components is not None:
        n_components = None
        warnings.warn("Ignoring n_components with whiten=False.")

    if n_components is None:
        n_components = min(n, p)
    if n_components > min(n, p):
        n_components = min(n, p)
        print("n_components is too large: it will be set to %s" % n_components)

    if whiten:
        # Centering the columns (ie the variables)
        X_mean = X.mean(axis=-1)
        X -= X_mean[:, np.newaxis]

        # Whitening and preprocessing by PCA
        u, d, _ = linalg.svd(X, full_matrices=False)

        del _
        K = (u / d).T[:n_components]  # see (6.33) p.140
        del u, d
        X1 = np.dot(K, X)
        # see (13.6) p.267 Here X1 is white and data
        # in X has been projected onto a subspace by PCA
        X1 *= np.sqrt(p)
    else:
        # X must be casted to floats to avoid typing issues with numpy
        # 2.0 and the line below
        X1 = as_float_array(X, copy=False)  # copy has been taken care of

    if w_init is None:
        w_init = np.asarray(
            random_state.normal(size=(n_components, n_components)), dtype=X1.dtype
        )

    else:
        w_init = np.asarray(w_init)
        if w_init.shape != (n_components, n_components):
            raise ValueError(
                "w_init has invalid shape -- should be %(shape)s"
                % {"shape": (n_components, n_components)}
            )

    kwargs = {
        "tol": tol,
        "g": g,
        "fun_args": fun_args,
        "max_iter": max_iter,
        "w_init": w_init,
    }

    if algorithm == "parallel":
        W = _ica_par(X1, **kwargs)
    elif algorithm == "deflation":
        W = _ica_def(X1, **kwargs)
    else:
        raise ValueError("Invalid algorithm: must be either `parallel` or `deflation`.")
    del X1

    if whiten:
        if compute_sources:
            S = fast_dot(fast_dot(W, K), X).T
        else:
            S = None
        if return_X_mean:
            return K, W, S, X_mean
        else:
            return K, W, S
    else:
        if compute_sources:
            S = fast_dot(W, X).T
        else:
            S = None
        if return_X_mean:
            return None, W, S, None
        else:
            return None, W, S