def null_space(M, k, k_skip=<NUM_LIT:1>, eigen_solver='<STR_LIT>',<EOL>random_state=None, solver_kwds=None):
eigen_solver, solver_kwds = check_eigen_solver(eigen_solver, solver_kwds,<EOL>size=M.shape[<NUM_LIT:0>],<EOL>nvec=k + k_skip)<EOL>random_state = check_random_state(random_state)<EOL>if eigen_solver == '<STR_LIT>':<EOL><INDENT>v0 = random_state.uniform(-<NUM_LIT:1>, <NUM_LIT:1>, M.shape[<NUM_LIT:0>])<EOL>try:<EOL><INDENT>eigen_values, eigen_vectors = eigsh(M, k + k_skip, sigma=<NUM_LIT:0.0>,<EOL>v0=v0,**(solver_kwds or {}))<EOL><DEDENT>except RuntimeError as msg:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>% msg)<EOL><DEDENT>return eigen_vectors[:, k_skip:], np.sum(eigen_values[k_skip:])<EOL><DEDENT>elif eigen_solver == '<STR_LIT>':<EOL><INDENT>if hasattr(M, '<STR_LIT>'):<EOL><INDENT>M = M.toarray()<EOL><DEDENT>eigen_values, eigen_vectors = eigh(M, eigvals=(<NUM_LIT:0>, k+k_skip),overwrite_a=True,<EOL>**(solver_kwds or {}))<EOL>index = np.argsort(np.abs(eigen_values))<EOL>eigen_vectors = eigen_vectors[:, index]<EOL>eigen_values = eigen_values[index]<EOL>return eigen_vectors[:, k_skip:k+<NUM_LIT:1>], np.sum(eigen_values[k_skip:k+<NUM_LIT:1>])<EOL><DEDENT>elif (eigen_solver == '<STR_LIT>' or eigen_solver == '<STR_LIT>'):<EOL><INDENT>try:<EOL><INDENT>M = sparse.identity(M.shape[<NUM_LIT:0>]) + M<EOL>n_components = min(k + k_skip + <NUM_LIT:10>, M.shape[<NUM_LIT:0>])<EOL>eigen_values, eigen_vectors = eigen_decomposition(M, n_components,<EOL>eigen_solver = eigen_solver,<EOL>drop_first = False,<EOL>largest = False,<EOL>random_state=random_state,<EOL>solver_kwds=solver_kwds)<EOL>eigen_values = eigen_values -<NUM_LIT:1><EOL>index = np.argsort(np.abs(eigen_values))<EOL>eigen_values = eigen_values[index]<EOL>eigen_vectors = eigen_vectors[:, index]<EOL>return eigen_vectors[:, k_skip:k+<NUM_LIT:1>], np.sum(eigen_values[k_skip:k+<NUM_LIT:1>])<EOL><DEDENT>except np.linalg.LinAlgError: <EOL><INDENT>warnings.warn("<STR_LIT>")<EOL>M = <NUM_LIT>*sparse.identity(M.shape[<NUM_LIT:0>]) + M<EOL>n_components = min(k + k_skip + <NUM_LIT:10>, M.shape[<NUM_LIT:0>])<EOL>eigen_values, eigen_vectors = eigen_decomposition(M, n_components,<EOL>eigen_solver = eigen_solver,<EOL>drop_first = False,<EOL>largest = False,<EOL>random_state=random_state,<EOL>solver_kwds=solver_kwds)<EOL>eigen_values = eigen_values - <NUM_LIT:2><EOL>index = np.argsort(np.abs(eigen_values))<EOL>eigen_values = eigen_values[index]<EOL>eigen_vectors = eigen_vectors[:, index]<EOL>return eigen_vectors[:, k_skip:k+<NUM_LIT:1>], np.sum(eigen_values[k_skip:k+<NUM_LIT:1>])<EOL><DEDENT><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>" % eigen_solver)<EOL><DEDENT>
Find the null space of a matrix M: eigenvectors associated with 0 eigenvalues

Parameters
----------
M : {array, matrix, sparse matrix, LinearOperator}
    Input covariance matrix: should be symmetric positive semi-definite
k : integer
    Number of eigenvalues/vectors to return
k_skip : integer, optional
    Number of low eigenvalues to skip.
eigen_solver : {'auto', 'dense', 'arpack', 'lobpcg', or 'amg'}
    'auto' :
        algorithm will attempt to choose the best method for input data
    'dense' :
        use standard dense matrix operations for the eigenvalue decomposition.
        For this method, M must be an array or matrix type.  This method should be avoided for large problems.
    'arpack' :
        use arnoldi iteration in shift-invert mode. For this method,
        M may be a dense matrix, sparse matrix, or general linear operator.
        Warning: ARPACK can be unstable for some problems.  It is best to
        try several random seeds in order to check results.
    'lobpcg' :
        Locally Optimal Block Preconditioned Conjugate Gradient Method.
        A preconditioned eigensolver for large symmetric positive definite
        (SPD) generalized eigenproblems.
    'amg' :
        AMG requires pyamg to be installed. It can be faster on very large,
        sparse problems, but may also lead to instabilities.
random_state: numpy.RandomState or int, optional
    The generator or seed used to determine the starting vector for arpack
    iterations.  Defaults to numpy.random.
solver_kwds : any additional keyword arguments to pass to the selected eigen_solver

Returns
-------
null_space : estimated k vectors of the null space
error : estimated error (sum of eigenvalues)

Notes
-----
dense solver key words: see
    http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.linalg.eigh.html
    for symmetric problems and
    http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.linalg.eig.html#scipy.linalg.eig
    for non symmetric problems.
arpack sovler key words: see
    http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.linalg.eigsh.html
    for symmetric problems and http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.linalg.eigs.html#scipy.sparse.linalg.eigs
    for non symmetric problems.
lobpcg solver keywords: see
    http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lobpcg.html
amg solver keywords: see
    http://pyamg.googlecode.com/svn/branches/1.0.x/Docs/html/pyamg.aggregation.html#module-pyamg.aggregation.aggregation
    (Note amg solver uses lobpcg and also accepts lobpcg keywords)