Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
|
@ -0,0 +1,29 @@
|
|||
Copyright (c) 2003, The Regents of the University of California, through
|
||||
Lawrence Berkeley National Laboratory (subject to receipt of any required
|
||||
approvals from U.S. Dept. of Energy)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
(2) Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
(3) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of
|
||||
Energy nor the names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,66 @@
|
|||
"""
|
||||
Linear Solvers
|
||||
==============
|
||||
|
||||
The default solver is SuperLU (included in the scipy distribution),
|
||||
which can solve real or complex linear systems in both single and
|
||||
double precisions. It is automatically replaced by UMFPACK, if
|
||||
available. Note that UMFPACK works in double precision only, so
|
||||
switch it off by::
|
||||
|
||||
>>> use_solver(useUmfpack=False)
|
||||
|
||||
to solve in the single precision. See also use_solver documentation.
|
||||
|
||||
Example session::
|
||||
|
||||
>>> from scipy.sparse import csc_matrix, spdiags
|
||||
>>> from numpy import array
|
||||
>>> from scipy.sparse.linalg import spsolve, use_solver
|
||||
>>>
|
||||
>>> print("Inverting a sparse linear system:")
|
||||
>>> print("The sparse matrix (constructed from diagonals):")
|
||||
>>> a = spdiags([[1, 2, 3, 4, 5], [6, 5, 8, 9, 10]], [0, 1], 5, 5)
|
||||
>>> b = array([1, 2, 3, 4, 5])
|
||||
>>> print("Solve: single precision complex:")
|
||||
>>> use_solver( useUmfpack = False )
|
||||
>>> a = a.astype('F')
|
||||
>>> x = spsolve(a, b)
|
||||
>>> print(x)
|
||||
>>> print("Error: ", a*x-b)
|
||||
>>>
|
||||
>>> print("Solve: double precision complex:")
|
||||
>>> use_solver( useUmfpack = True )
|
||||
>>> a = a.astype('D')
|
||||
>>> x = spsolve(a, b)
|
||||
>>> print(x)
|
||||
>>> print("Error: ", a*x-b)
|
||||
>>>
|
||||
>>> print("Solve: double precision:")
|
||||
>>> a = a.astype('d')
|
||||
>>> x = spsolve(a, b)
|
||||
>>> print(x)
|
||||
>>> print("Error: ", a*x-b)
|
||||
>>>
|
||||
>>> print("Solve: single precision:")
|
||||
>>> use_solver( useUmfpack = False )
|
||||
>>> a = a.astype('f')
|
||||
>>> x = spsolve(a, b.astype('f'))
|
||||
>>> print(x)
|
||||
>>> print("Error: ", a*x-b)
|
||||
|
||||
"""
|
||||
|
||||
#import umfpack
|
||||
#__doc__ = '\n\n'.join( (__doc__, umfpack.__doc__) )
|
||||
#del umfpack
|
||||
|
||||
from .linsolve import *
|
||||
from ._superlu import SuperLU
|
||||
from . import _add_newdocs
|
||||
|
||||
__all__ = [s for s in dir() if not s.startswith('_')]
|
||||
|
||||
from scipy._lib._testutils import PytestTester
|
||||
test = PytestTester(__name__)
|
||||
del PytestTester
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,152 @@
|
|||
from numpy.lib import add_newdoc
|
||||
|
||||
add_newdoc('scipy.sparse.linalg.dsolve._superlu', 'SuperLU',
|
||||
"""
|
||||
LU factorization of a sparse matrix.
|
||||
|
||||
Factorization is represented as::
|
||||
|
||||
Pr * A * Pc = L * U
|
||||
|
||||
To construct these `SuperLU` objects, call the `splu` and `spilu`
|
||||
functions.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
shape
|
||||
nnz
|
||||
perm_c
|
||||
perm_r
|
||||
L
|
||||
U
|
||||
|
||||
Methods
|
||||
-------
|
||||
solve
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
.. versionadded:: 0.14.0
|
||||
|
||||
Examples
|
||||
--------
|
||||
The LU decomposition can be used to solve matrix equations. Consider:
|
||||
|
||||
>>> import numpy as np
|
||||
>>> from scipy.sparse import csc_matrix, linalg as sla
|
||||
>>> A = csc_matrix([[1,2,0,4],[1,0,0,1],[1,0,2,1],[2,2,1,0.]])
|
||||
|
||||
This can be solved for a given right-hand side:
|
||||
|
||||
>>> lu = sla.splu(A)
|
||||
>>> b = np.array([1, 2, 3, 4])
|
||||
>>> x = lu.solve(b)
|
||||
>>> A.dot(x)
|
||||
array([ 1., 2., 3., 4.])
|
||||
|
||||
The ``lu`` object also contains an explicit representation of the
|
||||
decomposition. The permutations are represented as mappings of
|
||||
indices:
|
||||
|
||||
>>> lu.perm_r
|
||||
array([0, 2, 1, 3], dtype=int32)
|
||||
>>> lu.perm_c
|
||||
array([2, 0, 1, 3], dtype=int32)
|
||||
|
||||
The L and U factors are sparse matrices in CSC format:
|
||||
|
||||
>>> lu.L.A
|
||||
array([[ 1. , 0. , 0. , 0. ],
|
||||
[ 0. , 1. , 0. , 0. ],
|
||||
[ 0. , 0. , 1. , 0. ],
|
||||
[ 1. , 0.5, 0.5, 1. ]])
|
||||
>>> lu.U.A
|
||||
array([[ 2., 0., 1., 4.],
|
||||
[ 0., 2., 1., 1.],
|
||||
[ 0., 0., 1., 1.],
|
||||
[ 0., 0., 0., -5.]])
|
||||
|
||||
The permutation matrices can be constructed:
|
||||
|
||||
>>> Pr = csc_matrix((np.ones(4), (lu.perm_r, np.arange(4))))
|
||||
>>> Pc = csc_matrix((np.ones(4), (np.arange(4), lu.perm_c)))
|
||||
|
||||
We can reassemble the original matrix:
|
||||
|
||||
>>> (Pr.T * (lu.L * lu.U) * Pc.T).A
|
||||
array([[ 1., 2., 0., 4.],
|
||||
[ 1., 0., 0., 1.],
|
||||
[ 1., 0., 2., 1.],
|
||||
[ 2., 2., 1., 0.]])
|
||||
""")
|
||||
|
||||
add_newdoc('scipy.sparse.linalg.dsolve._superlu', 'SuperLU', ('solve',
|
||||
"""
|
||||
solve(rhs[, trans])
|
||||
|
||||
Solves linear system of equations with one or several right-hand sides.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rhs : ndarray, shape (n,) or (n, k)
|
||||
Right hand side(s) of equation
|
||||
trans : {'N', 'T', 'H'}, optional
|
||||
Type of system to solve::
|
||||
|
||||
'N': A * x == rhs (default)
|
||||
'T': A^T * x == rhs
|
||||
'H': A^H * x == rhs
|
||||
|
||||
i.e., normal, transposed, and hermitian conjugate.
|
||||
|
||||
Returns
|
||||
-------
|
||||
x : ndarray, shape ``rhs.shape``
|
||||
Solution vector(s)
|
||||
"""))
|
||||
|
||||
add_newdoc('scipy.sparse.linalg.dsolve._superlu', 'SuperLU', ('L',
|
||||
"""
|
||||
Lower triangular factor with unit diagonal as a
|
||||
`scipy.sparse.csc_matrix`.
|
||||
|
||||
.. versionadded:: 0.14.0
|
||||
"""))
|
||||
|
||||
add_newdoc('scipy.sparse.linalg.dsolve._superlu', 'SuperLU', ('U',
|
||||
"""
|
||||
Upper triangular factor as a `scipy.sparse.csc_matrix`.
|
||||
|
||||
.. versionadded:: 0.14.0
|
||||
"""))
|
||||
|
||||
add_newdoc('scipy.sparse.linalg.dsolve._superlu', 'SuperLU', ('shape',
|
||||
"""
|
||||
Shape of the original matrix as a tuple of ints.
|
||||
"""))
|
||||
|
||||
add_newdoc('scipy.sparse.linalg.dsolve._superlu', 'SuperLU', ('nnz',
|
||||
"""
|
||||
Number of nonzero elements in the matrix.
|
||||
"""))
|
||||
|
||||
add_newdoc('scipy.sparse.linalg.dsolve._superlu', 'SuperLU', ('perm_c',
|
||||
"""
|
||||
Permutation Pc represented as an array of indices.
|
||||
|
||||
The column permutation matrix can be reconstructed via:
|
||||
|
||||
>>> Pc = np.zeros((n, n))
|
||||
>>> Pc[np.arange(n), perm_c] = 1
|
||||
"""))
|
||||
|
||||
add_newdoc('scipy.sparse.linalg.dsolve._superlu', 'SuperLU', ('perm_r',
|
||||
"""
|
||||
Permutation Pr represented as an array of indices.
|
||||
|
||||
The row permutation matrix can be reconstructed via:
|
||||
|
||||
>>> Pr = np.zeros((n, n))
|
||||
>>> Pr[perm_r, np.arange(n)] = 1
|
||||
"""))
|
Binary file not shown.
626
venv/Lib/site-packages/scipy/sparse/linalg/dsolve/linsolve.py
Normal file
626
venv/Lib/site-packages/scipy/sparse/linalg/dsolve/linsolve.py
Normal file
|
@ -0,0 +1,626 @@
|
|||
from warnings import warn
|
||||
|
||||
import numpy as np
|
||||
from numpy import asarray
|
||||
from scipy.sparse import (isspmatrix_csc, isspmatrix_csr, isspmatrix,
|
||||
SparseEfficiencyWarning, csc_matrix, csr_matrix)
|
||||
from scipy.sparse.sputils import is_pydata_spmatrix
|
||||
from scipy.linalg import LinAlgError
|
||||
import copy
|
||||
|
||||
from . import _superlu
|
||||
|
||||
noScikit = False
|
||||
try:
|
||||
import scikits.umfpack as umfpack
|
||||
except ImportError:
|
||||
noScikit = True
|
||||
|
||||
useUmfpack = not noScikit
|
||||
|
||||
__all__ = ['use_solver', 'spsolve', 'splu', 'spilu', 'factorized',
|
||||
'MatrixRankWarning', 'spsolve_triangular']
|
||||
|
||||
|
||||
class MatrixRankWarning(UserWarning):
|
||||
pass
|
||||
|
||||
|
||||
def use_solver(**kwargs):
|
||||
"""
|
||||
Select default sparse direct solver to be used.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
useUmfpack : bool, optional
|
||||
Use UMFPACK over SuperLU. Has effect only if scikits.umfpack is
|
||||
installed. Default: True
|
||||
assumeSortedIndices : bool, optional
|
||||
Allow UMFPACK to skip the step of sorting indices for a CSR/CSC matrix.
|
||||
Has effect only if useUmfpack is True and scikits.umfpack is installed.
|
||||
Default: False
|
||||
|
||||
Notes
|
||||
-----
|
||||
The default sparse solver is umfpack when available
|
||||
(scikits.umfpack is installed). This can be changed by passing
|
||||
useUmfpack = False, which then causes the always present SuperLU
|
||||
based solver to be used.
|
||||
|
||||
Umfpack requires a CSR/CSC matrix to have sorted column/row indices. If
|
||||
sure that the matrix fulfills this, pass ``assumeSortedIndices=True``
|
||||
to gain some speed.
|
||||
|
||||
"""
|
||||
if 'useUmfpack' in kwargs:
|
||||
globals()['useUmfpack'] = kwargs['useUmfpack']
|
||||
if useUmfpack and 'assumeSortedIndices' in kwargs:
|
||||
umfpack.configure(assumeSortedIndices=kwargs['assumeSortedIndices'])
|
||||
|
||||
def _get_umf_family(A):
|
||||
"""Get umfpack family string given the sparse matrix dtype."""
|
||||
_families = {
|
||||
(np.float64, np.int32): 'di',
|
||||
(np.complex128, np.int32): 'zi',
|
||||
(np.float64, np.int64): 'dl',
|
||||
(np.complex128, np.int64): 'zl'
|
||||
}
|
||||
|
||||
f_type = np.sctypeDict[A.dtype.name]
|
||||
i_type = np.sctypeDict[A.indices.dtype.name]
|
||||
|
||||
try:
|
||||
family = _families[(f_type, i_type)]
|
||||
|
||||
except KeyError:
|
||||
msg = 'only float64 or complex128 matrices with int32 or int64' \
|
||||
' indices are supported! (got: matrix: %s, indices: %s)' \
|
||||
% (f_type, i_type)
|
||||
raise ValueError(msg)
|
||||
|
||||
# See gh-8278. Considered converting only if
|
||||
# A.shape[0]*A.shape[1] > np.iinfo(np.int32).max,
|
||||
# but that didn't always fix the issue.
|
||||
family = family[0] + "l"
|
||||
A_new = copy.copy(A)
|
||||
A_new.indptr = np.array(A.indptr, copy=False, dtype=np.int64)
|
||||
A_new.indices = np.array(A.indices, copy=False, dtype=np.int64)
|
||||
|
||||
return family, A_new
|
||||
|
||||
def spsolve(A, b, permc_spec=None, use_umfpack=True):
|
||||
"""Solve the sparse linear system Ax=b, where b may be a vector or a matrix.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
A : ndarray or sparse matrix
|
||||
The square matrix A will be converted into CSC or CSR form
|
||||
b : ndarray or sparse matrix
|
||||
The matrix or vector representing the right hand side of the equation.
|
||||
If a vector, b.shape must be (n,) or (n, 1).
|
||||
permc_spec : str, optional
|
||||
How to permute the columns of the matrix for sparsity preservation.
|
||||
(default: 'COLAMD')
|
||||
|
||||
- ``NATURAL``: natural ordering.
|
||||
- ``MMD_ATA``: minimum degree ordering on the structure of A^T A.
|
||||
- ``MMD_AT_PLUS_A``: minimum degree ordering on the structure of A^T+A.
|
||||
- ``COLAMD``: approximate minimum degree column ordering
|
||||
use_umfpack : bool, optional
|
||||
if True (default) then use umfpack for the solution. This is
|
||||
only referenced if b is a vector and ``scikit-umfpack`` is installed.
|
||||
|
||||
Returns
|
||||
-------
|
||||
x : ndarray or sparse matrix
|
||||
the solution of the sparse linear equation.
|
||||
If b is a vector, then x is a vector of size A.shape[1]
|
||||
If b is a matrix, then x is a matrix of size (A.shape[1], b.shape[1])
|
||||
|
||||
Notes
|
||||
-----
|
||||
For solving the matrix expression AX = B, this solver assumes the resulting
|
||||
matrix X is sparse, as is often the case for very sparse inputs. If the
|
||||
resulting X is dense, the construction of this sparse result will be
|
||||
relatively expensive. In that case, consider converting A to a dense
|
||||
matrix and using scipy.linalg.solve or its variants.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy.sparse import csc_matrix
|
||||
>>> from scipy.sparse.linalg import spsolve
|
||||
>>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float)
|
||||
>>> B = csc_matrix([[2, 0], [-1, 0], [2, 0]], dtype=float)
|
||||
>>> x = spsolve(A, B)
|
||||
>>> np.allclose(A.dot(x).todense(), B.todense())
|
||||
True
|
||||
"""
|
||||
|
||||
if is_pydata_spmatrix(A):
|
||||
A = A.to_scipy_sparse().tocsc()
|
||||
|
||||
if not (isspmatrix_csc(A) or isspmatrix_csr(A)):
|
||||
A = csc_matrix(A)
|
||||
warn('spsolve requires A be CSC or CSR matrix format',
|
||||
SparseEfficiencyWarning)
|
||||
|
||||
# b is a vector only if b have shape (n,) or (n, 1)
|
||||
b_is_sparse = isspmatrix(b) or is_pydata_spmatrix(b)
|
||||
if not b_is_sparse:
|
||||
b = asarray(b)
|
||||
b_is_vector = ((b.ndim == 1) or (b.ndim == 2 and b.shape[1] == 1))
|
||||
|
||||
# sum duplicates for non-canonical format
|
||||
A.sum_duplicates()
|
||||
A = A.asfptype() # upcast to a floating point format
|
||||
result_dtype = np.promote_types(A.dtype, b.dtype)
|
||||
if A.dtype != result_dtype:
|
||||
A = A.astype(result_dtype)
|
||||
if b.dtype != result_dtype:
|
||||
b = b.astype(result_dtype)
|
||||
|
||||
# validate input shapes
|
||||
M, N = A.shape
|
||||
if (M != N):
|
||||
raise ValueError("matrix must be square (has shape %s)" % ((M, N),))
|
||||
|
||||
if M != b.shape[0]:
|
||||
raise ValueError("matrix - rhs dimension mismatch (%s - %s)"
|
||||
% (A.shape, b.shape[0]))
|
||||
|
||||
use_umfpack = use_umfpack and useUmfpack
|
||||
|
||||
if b_is_vector and use_umfpack:
|
||||
if b_is_sparse:
|
||||
b_vec = b.toarray()
|
||||
else:
|
||||
b_vec = b
|
||||
b_vec = asarray(b_vec, dtype=A.dtype).ravel()
|
||||
|
||||
if noScikit:
|
||||
raise RuntimeError('Scikits.umfpack not installed.')
|
||||
|
||||
if A.dtype.char not in 'dD':
|
||||
raise ValueError("convert matrix data to double, please, using"
|
||||
" .astype(), or set linsolve.useUmfpack = False")
|
||||
|
||||
umf_family, A = _get_umf_family(A)
|
||||
umf = umfpack.UmfpackContext(umf_family)
|
||||
x = umf.linsolve(umfpack.UMFPACK_A, A, b_vec,
|
||||
autoTranspose=True)
|
||||
else:
|
||||
if b_is_vector and b_is_sparse:
|
||||
b = b.toarray()
|
||||
b_is_sparse = False
|
||||
|
||||
if not b_is_sparse:
|
||||
if isspmatrix_csc(A):
|
||||
flag = 1 # CSC format
|
||||
else:
|
||||
flag = 0 # CSR format
|
||||
|
||||
options = dict(ColPerm=permc_spec)
|
||||
x, info = _superlu.gssv(N, A.nnz, A.data, A.indices, A.indptr,
|
||||
b, flag, options=options)
|
||||
if info != 0:
|
||||
warn("Matrix is exactly singular", MatrixRankWarning)
|
||||
x.fill(np.nan)
|
||||
if b_is_vector:
|
||||
x = x.ravel()
|
||||
else:
|
||||
# b is sparse
|
||||
Afactsolve = factorized(A)
|
||||
|
||||
if not (isspmatrix_csc(b) or is_pydata_spmatrix(b)):
|
||||
warn('spsolve is more efficient when sparse b '
|
||||
'is in the CSC matrix format', SparseEfficiencyWarning)
|
||||
b = csc_matrix(b)
|
||||
|
||||
# Create a sparse output matrix by repeatedly applying
|
||||
# the sparse factorization to solve columns of b.
|
||||
data_segs = []
|
||||
row_segs = []
|
||||
col_segs = []
|
||||
for j in range(b.shape[1]):
|
||||
bj = np.asarray(b[:, j].todense()).ravel()
|
||||
xj = Afactsolve(bj)
|
||||
w = np.flatnonzero(xj)
|
||||
segment_length = w.shape[0]
|
||||
row_segs.append(w)
|
||||
col_segs.append(np.full(segment_length, j, dtype=int))
|
||||
data_segs.append(np.asarray(xj[w], dtype=A.dtype))
|
||||
sparse_data = np.concatenate(data_segs)
|
||||
sparse_row = np.concatenate(row_segs)
|
||||
sparse_col = np.concatenate(col_segs)
|
||||
x = A.__class__((sparse_data, (sparse_row, sparse_col)),
|
||||
shape=b.shape, dtype=A.dtype)
|
||||
|
||||
if is_pydata_spmatrix(b):
|
||||
x = b.__class__(x)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
def splu(A, permc_spec=None, diag_pivot_thresh=None,
|
||||
relax=None, panel_size=None, options=dict()):
|
||||
"""
|
||||
Compute the LU decomposition of a sparse, square matrix.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
A : sparse matrix
|
||||
Sparse matrix to factorize. Should be in CSR or CSC format.
|
||||
permc_spec : str, optional
|
||||
How to permute the columns of the matrix for sparsity preservation.
|
||||
(default: 'COLAMD')
|
||||
|
||||
- ``NATURAL``: natural ordering.
|
||||
- ``MMD_ATA``: minimum degree ordering on the structure of A^T A.
|
||||
- ``MMD_AT_PLUS_A``: minimum degree ordering on the structure of A^T+A.
|
||||
- ``COLAMD``: approximate minimum degree column ordering
|
||||
|
||||
diag_pivot_thresh : float, optional
|
||||
Threshold used for a diagonal entry to be an acceptable pivot.
|
||||
See SuperLU user's guide for details [1]_
|
||||
relax : int, optional
|
||||
Expert option for customizing the degree of relaxing supernodes.
|
||||
See SuperLU user's guide for details [1]_
|
||||
panel_size : int, optional
|
||||
Expert option for customizing the panel size.
|
||||
See SuperLU user's guide for details [1]_
|
||||
options : dict, optional
|
||||
Dictionary containing additional expert options to SuperLU.
|
||||
See SuperLU user guide [1]_ (section 2.4 on the 'Options' argument)
|
||||
for more details. For example, you can specify
|
||||
``options=dict(Equil=False, IterRefine='SINGLE'))``
|
||||
to turn equilibration off and perform a single iterative refinement.
|
||||
|
||||
Returns
|
||||
-------
|
||||
invA : scipy.sparse.linalg.SuperLU
|
||||
Object, which has a ``solve`` method.
|
||||
|
||||
See also
|
||||
--------
|
||||
spilu : incomplete LU decomposition
|
||||
|
||||
Notes
|
||||
-----
|
||||
This function uses the SuperLU library.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] SuperLU http://crd.lbl.gov/~xiaoye/SuperLU/
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy.sparse import csc_matrix
|
||||
>>> from scipy.sparse.linalg import splu
|
||||
>>> A = csc_matrix([[1., 0., 0.], [5., 0., 2.], [0., -1., 0.]], dtype=float)
|
||||
>>> B = splu(A)
|
||||
>>> x = np.array([1., 2., 3.], dtype=float)
|
||||
>>> B.solve(x)
|
||||
array([ 1. , -3. , -1.5])
|
||||
>>> A.dot(B.solve(x))
|
||||
array([ 1., 2., 3.])
|
||||
>>> B.solve(A.dot(x))
|
||||
array([ 1., 2., 3.])
|
||||
"""
|
||||
|
||||
if is_pydata_spmatrix(A):
|
||||
csc_construct_func = lambda *a, cls=type(A): cls(csc_matrix(*a))
|
||||
A = A.to_scipy_sparse().tocsc()
|
||||
else:
|
||||
csc_construct_func = csc_matrix
|
||||
|
||||
if not isspmatrix_csc(A):
|
||||
A = csc_matrix(A)
|
||||
warn('splu requires CSC matrix format', SparseEfficiencyWarning)
|
||||
|
||||
# sum duplicates for non-canonical format
|
||||
A.sum_duplicates()
|
||||
A = A.asfptype() # upcast to a floating point format
|
||||
|
||||
M, N = A.shape
|
||||
if (M != N):
|
||||
raise ValueError("can only factor square matrices") # is this true?
|
||||
|
||||
_options = dict(DiagPivotThresh=diag_pivot_thresh, ColPerm=permc_spec,
|
||||
PanelSize=panel_size, Relax=relax)
|
||||
if options is not None:
|
||||
_options.update(options)
|
||||
|
||||
# Ensure that no column permutations are applied
|
||||
if (_options["ColPerm"] == "NATURAL"):
|
||||
_options["SymmetricMode"] = True
|
||||
|
||||
return _superlu.gstrf(N, A.nnz, A.data, A.indices, A.indptr,
|
||||
csc_construct_func=csc_construct_func,
|
||||
ilu=False, options=_options)
|
||||
|
||||
|
||||
def spilu(A, drop_tol=None, fill_factor=None, drop_rule=None, permc_spec=None,
|
||||
diag_pivot_thresh=None, relax=None, panel_size=None, options=None):
|
||||
"""
|
||||
Compute an incomplete LU decomposition for a sparse, square matrix.
|
||||
|
||||
The resulting object is an approximation to the inverse of `A`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
A : (N, N) array_like
|
||||
Sparse matrix to factorize
|
||||
drop_tol : float, optional
|
||||
Drop tolerance (0 <= tol <= 1) for an incomplete LU decomposition.
|
||||
(default: 1e-4)
|
||||
fill_factor : float, optional
|
||||
Specifies the fill ratio upper bound (>= 1.0) for ILU. (default: 10)
|
||||
drop_rule : str, optional
|
||||
Comma-separated string of drop rules to use.
|
||||
Available rules: ``basic``, ``prows``, ``column``, ``area``,
|
||||
``secondary``, ``dynamic``, ``interp``. (Default: ``basic,area``)
|
||||
|
||||
See SuperLU documentation for details.
|
||||
|
||||
Remaining other options
|
||||
Same as for `splu`
|
||||
|
||||
Returns
|
||||
-------
|
||||
invA_approx : scipy.sparse.linalg.SuperLU
|
||||
Object, which has a ``solve`` method.
|
||||
|
||||
See also
|
||||
--------
|
||||
splu : complete LU decomposition
|
||||
|
||||
Notes
|
||||
-----
|
||||
To improve the better approximation to the inverse, you may need to
|
||||
increase `fill_factor` AND decrease `drop_tol`.
|
||||
|
||||
This function uses the SuperLU library.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy.sparse import csc_matrix
|
||||
>>> from scipy.sparse.linalg import spilu
|
||||
>>> A = csc_matrix([[1., 0., 0.], [5., 0., 2.], [0., -1., 0.]], dtype=float)
|
||||
>>> B = spilu(A)
|
||||
>>> x = np.array([1., 2., 3.], dtype=float)
|
||||
>>> B.solve(x)
|
||||
array([ 1. , -3. , -1.5])
|
||||
>>> A.dot(B.solve(x))
|
||||
array([ 1., 2., 3.])
|
||||
>>> B.solve(A.dot(x))
|
||||
array([ 1., 2., 3.])
|
||||
"""
|
||||
|
||||
if is_pydata_spmatrix(A):
|
||||
csc_construct_func = lambda *a, cls=type(A): cls(csc_matrix(*a))
|
||||
A = A.to_scipy_sparse().tocsc()
|
||||
else:
|
||||
csc_construct_func = csc_matrix
|
||||
|
||||
if not isspmatrix_csc(A):
|
||||
A = csc_matrix(A)
|
||||
warn('splu requires CSC matrix format', SparseEfficiencyWarning)
|
||||
|
||||
# sum duplicates for non-canonical format
|
||||
A.sum_duplicates()
|
||||
A = A.asfptype() # upcast to a floating point format
|
||||
|
||||
M, N = A.shape
|
||||
if (M != N):
|
||||
raise ValueError("can only factor square matrices") # is this true?
|
||||
|
||||
_options = dict(ILU_DropRule=drop_rule, ILU_DropTol=drop_tol,
|
||||
ILU_FillFactor=fill_factor,
|
||||
DiagPivotThresh=diag_pivot_thresh, ColPerm=permc_spec,
|
||||
PanelSize=panel_size, Relax=relax)
|
||||
if options is not None:
|
||||
_options.update(options)
|
||||
|
||||
# Ensure that no column permutations are applied
|
||||
if (_options["ColPerm"] == "NATURAL"):
|
||||
_options["SymmetricMode"] = True
|
||||
|
||||
return _superlu.gstrf(N, A.nnz, A.data, A.indices, A.indptr,
|
||||
csc_construct_func=csc_construct_func,
|
||||
ilu=True, options=_options)
|
||||
|
||||
|
||||
def factorized(A):
|
||||
"""
|
||||
Return a function for solving a sparse linear system, with A pre-factorized.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
A : (N, N) array_like
|
||||
Input.
|
||||
|
||||
Returns
|
||||
-------
|
||||
solve : callable
|
||||
To solve the linear system of equations given in `A`, the `solve`
|
||||
callable should be passed an ndarray of shape (N,).
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy.sparse.linalg import factorized
|
||||
>>> A = np.array([[ 3. , 2. , -1. ],
|
||||
... [ 2. , -2. , 4. ],
|
||||
... [-1. , 0.5, -1. ]])
|
||||
>>> solve = factorized(A) # Makes LU decomposition.
|
||||
>>> rhs1 = np.array([1, -2, 0])
|
||||
>>> solve(rhs1) # Uses the LU factors.
|
||||
array([ 1., -2., -2.])
|
||||
|
||||
"""
|
||||
if is_pydata_spmatrix(A):
|
||||
A = A.to_scipy_sparse().tocsc()
|
||||
|
||||
if useUmfpack:
|
||||
if noScikit:
|
||||
raise RuntimeError('Scikits.umfpack not installed.')
|
||||
|
||||
if not isspmatrix_csc(A):
|
||||
A = csc_matrix(A)
|
||||
warn('splu requires CSC matrix format', SparseEfficiencyWarning)
|
||||
|
||||
A = A.asfptype() # upcast to a floating point format
|
||||
|
||||
if A.dtype.char not in 'dD':
|
||||
raise ValueError("convert matrix data to double, please, using"
|
||||
" .astype(), or set linsolve.useUmfpack = False")
|
||||
|
||||
umf_family, A = _get_umf_family(A)
|
||||
umf = umfpack.UmfpackContext(umf_family)
|
||||
|
||||
# Make LU decomposition.
|
||||
umf.numeric(A)
|
||||
|
||||
def solve(b):
|
||||
return umf.solve(umfpack.UMFPACK_A, A, b, autoTranspose=True)
|
||||
|
||||
return solve
|
||||
else:
|
||||
return splu(A).solve
|
||||
|
||||
|
||||
def spsolve_triangular(A, b, lower=True, overwrite_A=False, overwrite_b=False,
|
||||
unit_diagonal=False):
|
||||
"""
|
||||
Solve the equation `A x = b` for `x`, assuming A is a triangular matrix.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
A : (M, M) sparse matrix
|
||||
A sparse square triangular matrix. Should be in CSR format.
|
||||
b : (M,) or (M, N) array_like
|
||||
Right-hand side matrix in `A x = b`
|
||||
lower : bool, optional
|
||||
Whether `A` is a lower or upper triangular matrix.
|
||||
Default is lower triangular matrix.
|
||||
overwrite_A : bool, optional
|
||||
Allow changing `A`. The indices of `A` are going to be sorted and zero
|
||||
entries are going to be removed.
|
||||
Enabling gives a performance gain. Default is False.
|
||||
overwrite_b : bool, optional
|
||||
Allow overwriting data in `b`.
|
||||
Enabling gives a performance gain. Default is False.
|
||||
If `overwrite_b` is True, it should be ensured that
|
||||
`b` has an appropriate dtype to be able to store the result.
|
||||
unit_diagonal : bool, optional
|
||||
If True, diagonal elements of `a` are assumed to be 1 and will not be
|
||||
referenced.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
Returns
|
||||
-------
|
||||
x : (M,) or (M, N) ndarray
|
||||
Solution to the system `A x = b`. Shape of return matches shape of `b`.
|
||||
|
||||
Raises
|
||||
------
|
||||
LinAlgError
|
||||
If `A` is singular or not triangular.
|
||||
ValueError
|
||||
If shape of `A` or shape of `b` do not match the requirements.
|
||||
|
||||
Notes
|
||||
-----
|
||||
.. versionadded:: 0.19.0
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy.sparse import csr_matrix
|
||||
>>> from scipy.sparse.linalg import spsolve_triangular
|
||||
>>> A = csr_matrix([[3, 0, 0], [1, -1, 0], [2, 0, 1]], dtype=float)
|
||||
>>> B = np.array([[2, 0], [-1, 0], [2, 0]], dtype=float)
|
||||
>>> x = spsolve_triangular(A, B)
|
||||
>>> np.allclose(A.dot(x), B)
|
||||
True
|
||||
"""
|
||||
|
||||
if is_pydata_spmatrix(A):
|
||||
A = A.to_scipy_sparse().tocsr()
|
||||
|
||||
# Check the input for correct type and format.
|
||||
if not isspmatrix_csr(A):
|
||||
warn('CSR matrix format is required. Converting to CSR matrix.',
|
||||
SparseEfficiencyWarning)
|
||||
A = csr_matrix(A)
|
||||
elif not overwrite_A:
|
||||
A = A.copy()
|
||||
|
||||
if A.shape[0] != A.shape[1]:
|
||||
raise ValueError(
|
||||
'A must be a square matrix but its shape is {}.'.format(A.shape))
|
||||
|
||||
# sum duplicates for non-canonical format
|
||||
A.sum_duplicates()
|
||||
|
||||
b = np.asanyarray(b)
|
||||
|
||||
if b.ndim not in [1, 2]:
|
||||
raise ValueError(
|
||||
'b must have 1 or 2 dims but its shape is {}.'.format(b.shape))
|
||||
if A.shape[0] != b.shape[0]:
|
||||
raise ValueError(
|
||||
'The size of the dimensions of A must be equal to '
|
||||
'the size of the first dimension of b but the shape of A is '
|
||||
'{} and the shape of b is {}.'.format(A.shape, b.shape))
|
||||
|
||||
# Init x as (a copy of) b.
|
||||
x_dtype = np.result_type(A.data, b, np.float64)
|
||||
if overwrite_b:
|
||||
if np.can_cast(b.dtype, x_dtype, casting='same_kind'):
|
||||
x = b
|
||||
else:
|
||||
raise ValueError(
|
||||
'Cannot overwrite b (dtype {}) with result '
|
||||
'of type {}.'.format(b.dtype, x_dtype))
|
||||
else:
|
||||
x = b.astype(x_dtype, copy=True)
|
||||
|
||||
# Choose forward or backward order.
|
||||
if lower:
|
||||
row_indices = range(len(b))
|
||||
else:
|
||||
row_indices = range(len(b) - 1, -1, -1)
|
||||
|
||||
# Fill x iteratively.
|
||||
for i in row_indices:
|
||||
|
||||
# Get indices for i-th row.
|
||||
indptr_start = A.indptr[i]
|
||||
indptr_stop = A.indptr[i + 1]
|
||||
if lower:
|
||||
A_diagonal_index_row_i = indptr_stop - 1
|
||||
A_off_diagonal_indices_row_i = slice(indptr_start, indptr_stop - 1)
|
||||
else:
|
||||
A_diagonal_index_row_i = indptr_start
|
||||
A_off_diagonal_indices_row_i = slice(indptr_start + 1, indptr_stop)
|
||||
|
||||
# Check regularity and triangularity of A.
|
||||
if not unit_diagonal and (indptr_stop <= indptr_start
|
||||
or A.indices[A_diagonal_index_row_i] < i):
|
||||
raise LinAlgError(
|
||||
'A is singular: diagonal {} is zero.'.format(i))
|
||||
if A.indices[A_diagonal_index_row_i] > i:
|
||||
raise LinAlgError(
|
||||
'A is not triangular: A[{}, {}] is nonzero.'
|
||||
''.format(i, A.indices[A_diagonal_index_row_i]))
|
||||
|
||||
# Incorporate off-diagonal entries.
|
||||
A_column_indices_in_row_i = A.indices[A_off_diagonal_indices_row_i]
|
||||
A_values_in_row_i = A.data[A_off_diagonal_indices_row_i]
|
||||
x[i] -= np.dot(x[A_column_indices_in_row_i].T, A_values_in_row_i)
|
||||
|
||||
# Compute i-th entry of x.
|
||||
if not unit_diagonal:
|
||||
x[i] /= A.data[A_diagonal_index_row_i]
|
||||
|
||||
return x
|
53
venv/Lib/site-packages/scipy/sparse/linalg/dsolve/setup.py
Normal file
53
venv/Lib/site-packages/scipy/sparse/linalg/dsolve/setup.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
from os.path import join, dirname
|
||||
import sys
|
||||
import glob
|
||||
|
||||
|
||||
def configuration(parent_package='',top_path=None):
|
||||
from numpy.distutils.misc_util import Configuration
|
||||
from scipy._build_utils.system_info import get_info
|
||||
from scipy._build_utils import numpy_nodepr_api
|
||||
|
||||
config = Configuration('dsolve',parent_package,top_path)
|
||||
config.add_data_dir('tests')
|
||||
|
||||
lapack_opt = get_info('lapack_opt',notfound_action=2)
|
||||
if sys.platform == 'win32':
|
||||
superlu_defs = [('NO_TIMER',1)]
|
||||
else:
|
||||
superlu_defs = []
|
||||
superlu_defs.append(('USE_VENDOR_BLAS',1))
|
||||
|
||||
superlu_src = join(dirname(__file__), 'SuperLU', 'SRC')
|
||||
|
||||
sources = sorted(glob.glob(join(superlu_src, '*.c')))
|
||||
headers = list(glob.glob(join(superlu_src, '*.h')))
|
||||
|
||||
config.add_library('superlu_src',
|
||||
sources=sources,
|
||||
macros=superlu_defs,
|
||||
include_dirs=[superlu_src],
|
||||
)
|
||||
|
||||
# Extension
|
||||
ext_sources = ['_superlumodule.c',
|
||||
'_superlu_utils.c',
|
||||
'_superluobject.c']
|
||||
|
||||
config.add_extension('_superlu',
|
||||
sources=ext_sources,
|
||||
libraries=['superlu_src'],
|
||||
depends=(sources + headers),
|
||||
extra_info=lapack_opt,
|
||||
**numpy_nodepr_api
|
||||
)
|
||||
|
||||
# Add license files
|
||||
config.add_data_files('SuperLU/License.txt')
|
||||
|
||||
return config
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from numpy.distutils.core import setup
|
||||
setup(**configuration(top_path='').todict())
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,777 @@
|
|||
import sys
|
||||
import threading
|
||||
|
||||
import numpy as np
|
||||
from numpy import array, finfo, arange, eye, all, unique, ones, dot
|
||||
import numpy.random as random
|
||||
from numpy.testing import (
|
||||
assert_array_almost_equal, assert_almost_equal,
|
||||
assert_equal, assert_array_equal, assert_, assert_allclose,
|
||||
assert_warns, suppress_warnings)
|
||||
import pytest
|
||||
from pytest import raises as assert_raises
|
||||
|
||||
import scipy.linalg
|
||||
from scipy.linalg import norm, inv
|
||||
from scipy.sparse import (spdiags, SparseEfficiencyWarning, csc_matrix,
|
||||
csr_matrix, identity, isspmatrix, dok_matrix, lil_matrix, bsr_matrix)
|
||||
from scipy.sparse.linalg import SuperLU
|
||||
from scipy.sparse.linalg.dsolve import (spsolve, use_solver, splu, spilu,
|
||||
MatrixRankWarning, _superlu, spsolve_triangular, factorized)
|
||||
import scipy.sparse
|
||||
|
||||
from scipy._lib._testutils import check_free_memory
|
||||
|
||||
|
||||
sup_sparse_efficiency = suppress_warnings()
|
||||
sup_sparse_efficiency.filter(SparseEfficiencyWarning)
|
||||
|
||||
# scikits.umfpack is not a SciPy dependency but it is optionally used in
|
||||
# dsolve, so check whether it's available
|
||||
try:
|
||||
import scikits.umfpack as umfpack
|
||||
has_umfpack = True
|
||||
except ImportError:
|
||||
has_umfpack = False
|
||||
|
||||
def toarray(a):
|
||||
if isspmatrix(a):
|
||||
return a.toarray()
|
||||
else:
|
||||
return a
|
||||
|
||||
|
||||
def setup_bug_8278():
|
||||
N = 2 ** 6
|
||||
h = 1/N
|
||||
Ah1D = scipy.sparse.diags([-1, 2, -1], [-1, 0, 1],
|
||||
shape=(N-1, N-1))/(h**2)
|
||||
eyeN = scipy.sparse.eye(N - 1)
|
||||
A = (scipy.sparse.kron(eyeN, scipy.sparse.kron(eyeN, Ah1D))
|
||||
+ scipy.sparse.kron(eyeN, scipy.sparse.kron(Ah1D, eyeN))
|
||||
+ scipy.sparse.kron(Ah1D, scipy.sparse.kron(eyeN, eyeN)))
|
||||
b = np.random.rand((N-1)**3)
|
||||
return A, b
|
||||
|
||||
|
||||
class TestFactorized(object):
|
||||
def setup_method(self):
|
||||
n = 5
|
||||
d = arange(n) + 1
|
||||
self.n = n
|
||||
self.A = spdiags((d, 2*d, d[::-1]), (-3, 0, 5), n, n).tocsc()
|
||||
random.seed(1234)
|
||||
|
||||
def _check_singular(self):
|
||||
A = csc_matrix((5,5), dtype='d')
|
||||
b = ones(5)
|
||||
assert_array_almost_equal(0. * b, factorized(A)(b))
|
||||
|
||||
def _check_non_singular(self):
|
||||
# Make a diagonal dominant, to make sure it is not singular
|
||||
n = 5
|
||||
a = csc_matrix(random.rand(n, n))
|
||||
b = ones(n)
|
||||
|
||||
expected = splu(a).solve(b)
|
||||
assert_array_almost_equal(factorized(a)(b), expected)
|
||||
|
||||
def test_singular_without_umfpack(self):
|
||||
use_solver(useUmfpack=False)
|
||||
with assert_raises(RuntimeError, match="Factor is exactly singular"):
|
||||
self._check_singular()
|
||||
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_singular_with_umfpack(self):
|
||||
use_solver(useUmfpack=True)
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(RuntimeWarning, "divide by zero encountered in double_scalars")
|
||||
assert_warns(umfpack.UmfpackWarning, self._check_singular)
|
||||
|
||||
def test_non_singular_without_umfpack(self):
|
||||
use_solver(useUmfpack=False)
|
||||
self._check_non_singular()
|
||||
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_non_singular_with_umfpack(self):
|
||||
use_solver(useUmfpack=True)
|
||||
self._check_non_singular()
|
||||
|
||||
def test_cannot_factorize_nonsquare_matrix_without_umfpack(self):
|
||||
use_solver(useUmfpack=False)
|
||||
msg = "can only factor square matrices"
|
||||
with assert_raises(ValueError, match=msg):
|
||||
factorized(self.A[:, :4])
|
||||
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_factorizes_nonsquare_matrix_with_umfpack(self):
|
||||
use_solver(useUmfpack=True)
|
||||
# does not raise
|
||||
factorized(self.A[:,:4])
|
||||
|
||||
def test_call_with_incorrectly_sized_matrix_without_umfpack(self):
|
||||
use_solver(useUmfpack=False)
|
||||
solve = factorized(self.A)
|
||||
b = random.rand(4)
|
||||
B = random.rand(4, 3)
|
||||
BB = random.rand(self.n, 3, 9)
|
||||
|
||||
with assert_raises(ValueError, match="is of incompatible size"):
|
||||
solve(b)
|
||||
with assert_raises(ValueError, match="is of incompatible size"):
|
||||
solve(B)
|
||||
with assert_raises(ValueError,
|
||||
match="object too deep for desired array"):
|
||||
solve(BB)
|
||||
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_call_with_incorrectly_sized_matrix_with_umfpack(self):
|
||||
use_solver(useUmfpack=True)
|
||||
solve = factorized(self.A)
|
||||
b = random.rand(4)
|
||||
B = random.rand(4, 3)
|
||||
BB = random.rand(self.n, 3, 9)
|
||||
|
||||
# does not raise
|
||||
solve(b)
|
||||
msg = "object too deep for desired array"
|
||||
with assert_raises(ValueError, match=msg):
|
||||
solve(B)
|
||||
with assert_raises(ValueError, match=msg):
|
||||
solve(BB)
|
||||
|
||||
def test_call_with_cast_to_complex_without_umfpack(self):
|
||||
use_solver(useUmfpack=False)
|
||||
solve = factorized(self.A)
|
||||
b = random.rand(4)
|
||||
for t in [np.complex64, np.complex128]:
|
||||
with assert_raises(TypeError, match="Cannot cast array data"):
|
||||
solve(b.astype(t))
|
||||
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_call_with_cast_to_complex_with_umfpack(self):
|
||||
use_solver(useUmfpack=True)
|
||||
solve = factorized(self.A)
|
||||
b = random.rand(4)
|
||||
for t in [np.complex64, np.complex128]:
|
||||
assert_warns(np.ComplexWarning, solve, b.astype(t))
|
||||
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_assume_sorted_indices_flag(self):
|
||||
# a sparse matrix with unsorted indices
|
||||
unsorted_inds = np.array([2, 0, 1, 0])
|
||||
data = np.array([10, 16, 5, 0.4])
|
||||
indptr = np.array([0, 1, 2, 4])
|
||||
A = csc_matrix((data, unsorted_inds, indptr), (3, 3))
|
||||
b = ones(3)
|
||||
|
||||
# should raise when incorrectly assuming indices are sorted
|
||||
use_solver(useUmfpack=True, assumeSortedIndices=True)
|
||||
with assert_raises(RuntimeError,
|
||||
match="UMFPACK_ERROR_invalid_matrix"):
|
||||
factorized(A)
|
||||
|
||||
# should sort indices and succeed when not assuming indices are sorted
|
||||
use_solver(useUmfpack=True, assumeSortedIndices=False)
|
||||
expected = splu(A.copy()).solve(b)
|
||||
|
||||
assert_equal(A.has_sorted_indices, 0)
|
||||
assert_array_almost_equal(factorized(A)(b), expected)
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_bug_8278(self):
|
||||
check_free_memory(8000)
|
||||
use_solver(useUmfpack=True)
|
||||
A, b = setup_bug_8278()
|
||||
A = A.tocsc()
|
||||
f = factorized(A)
|
||||
x = f(b)
|
||||
assert_array_almost_equal(A @ x, b)
|
||||
|
||||
|
||||
class TestLinsolve(object):
|
||||
def setup_method(self):
|
||||
use_solver(useUmfpack=False)
|
||||
|
||||
def test_singular(self):
|
||||
A = csc_matrix((5,5), dtype='d')
|
||||
b = array([1, 2, 3, 4, 5],dtype='d')
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(MatrixRankWarning, "Matrix is exactly singular")
|
||||
x = spsolve(A, b)
|
||||
assert_(not np.isfinite(x).any())
|
||||
|
||||
def test_singular_gh_3312(self):
|
||||
# "Bad" test case that leads SuperLU to call LAPACK with invalid
|
||||
# arguments. Check that it fails moderately gracefully.
|
||||
ij = np.array([(17, 0), (17, 6), (17, 12), (10, 13)], dtype=np.int32)
|
||||
v = np.array([0.284213, 0.94933781, 0.15767017, 0.38797296])
|
||||
A = csc_matrix((v, ij.T), shape=(20, 20))
|
||||
b = np.arange(20)
|
||||
|
||||
try:
|
||||
# should either raise a runtimeerror or return value
|
||||
# appropriate for singular input
|
||||
x = spsolve(A, b)
|
||||
assert_(not np.isfinite(x).any())
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
def test_twodiags(self):
|
||||
A = spdiags([[1, 2, 3, 4, 5], [6, 5, 8, 9, 10]], [0, 1], 5, 5)
|
||||
b = array([1, 2, 3, 4, 5])
|
||||
|
||||
# condition number of A
|
||||
cond_A = norm(A.todense(),2) * norm(inv(A.todense()),2)
|
||||
|
||||
for t in ['f','d','F','D']:
|
||||
eps = finfo(t).eps # floating point epsilon
|
||||
b = b.astype(t)
|
||||
|
||||
for format in ['csc','csr']:
|
||||
Asp = A.astype(t).asformat(format)
|
||||
|
||||
x = spsolve(Asp,b)
|
||||
|
||||
assert_(norm(b - Asp*x) < 10 * cond_A * eps)
|
||||
|
||||
def test_bvector_smoketest(self):
|
||||
Adense = array([[0., 1., 1.],
|
||||
[1., 0., 1.],
|
||||
[0., 0., 1.]])
|
||||
As = csc_matrix(Adense)
|
||||
random.seed(1234)
|
||||
x = random.randn(3)
|
||||
b = As*x
|
||||
x2 = spsolve(As, b)
|
||||
|
||||
assert_array_almost_equal(x, x2)
|
||||
|
||||
def test_bmatrix_smoketest(self):
|
||||
Adense = array([[0., 1., 1.],
|
||||
[1., 0., 1.],
|
||||
[0., 0., 1.]])
|
||||
As = csc_matrix(Adense)
|
||||
random.seed(1234)
|
||||
x = random.randn(3, 4)
|
||||
Bdense = As.dot(x)
|
||||
Bs = csc_matrix(Bdense)
|
||||
x2 = spsolve(As, Bs)
|
||||
assert_array_almost_equal(x, x2.todense())
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_non_square(self):
|
||||
# A is not square.
|
||||
A = ones((3, 4))
|
||||
b = ones((4, 1))
|
||||
assert_raises(ValueError, spsolve, A, b)
|
||||
# A2 and b2 have incompatible shapes.
|
||||
A2 = csc_matrix(eye(3))
|
||||
b2 = array([1.0, 2.0])
|
||||
assert_raises(ValueError, spsolve, A2, b2)
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_example_comparison(self):
|
||||
row = array([0,0,1,2,2,2])
|
||||
col = array([0,2,2,0,1,2])
|
||||
data = array([1,2,3,-4,5,6])
|
||||
sM = csr_matrix((data,(row,col)), shape=(3,3), dtype=float)
|
||||
M = sM.todense()
|
||||
|
||||
row = array([0,0,1,1,0,0])
|
||||
col = array([0,2,1,1,0,0])
|
||||
data = array([1,1,1,1,1,1])
|
||||
sN = csr_matrix((data, (row,col)), shape=(3,3), dtype=float)
|
||||
N = sN.todense()
|
||||
|
||||
sX = spsolve(sM, sN)
|
||||
X = scipy.linalg.solve(M, N)
|
||||
|
||||
assert_array_almost_equal(X, sX.todense())
|
||||
|
||||
@sup_sparse_efficiency
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_shape_compatibility(self):
|
||||
use_solver(useUmfpack=True)
|
||||
A = csc_matrix([[1., 0], [0, 2]])
|
||||
bs = [
|
||||
[1, 6],
|
||||
array([1, 6]),
|
||||
[[1], [6]],
|
||||
array([[1], [6]]),
|
||||
csc_matrix([[1], [6]]),
|
||||
csr_matrix([[1], [6]]),
|
||||
dok_matrix([[1], [6]]),
|
||||
bsr_matrix([[1], [6]]),
|
||||
array([[1., 2., 3.], [6., 8., 10.]]),
|
||||
csc_matrix([[1., 2., 3.], [6., 8., 10.]]),
|
||||
csr_matrix([[1., 2., 3.], [6., 8., 10.]]),
|
||||
dok_matrix([[1., 2., 3.], [6., 8., 10.]]),
|
||||
bsr_matrix([[1., 2., 3.], [6., 8., 10.]]),
|
||||
]
|
||||
|
||||
for b in bs:
|
||||
x = np.linalg.solve(A.toarray(), toarray(b))
|
||||
for spmattype in [csc_matrix, csr_matrix, dok_matrix, lil_matrix]:
|
||||
x1 = spsolve(spmattype(A), b, use_umfpack=True)
|
||||
x2 = spsolve(spmattype(A), b, use_umfpack=False)
|
||||
|
||||
# check solution
|
||||
if x.ndim == 2 and x.shape[1] == 1:
|
||||
# interprets also these as "vectors"
|
||||
x = x.ravel()
|
||||
|
||||
assert_array_almost_equal(toarray(x1), x, err_msg=repr((b, spmattype, 1)))
|
||||
assert_array_almost_equal(toarray(x2), x, err_msg=repr((b, spmattype, 2)))
|
||||
|
||||
# dense vs. sparse output ("vectors" are always dense)
|
||||
if isspmatrix(b) and x.ndim > 1:
|
||||
assert_(isspmatrix(x1), repr((b, spmattype, 1)))
|
||||
assert_(isspmatrix(x2), repr((b, spmattype, 2)))
|
||||
else:
|
||||
assert_(isinstance(x1, np.ndarray), repr((b, spmattype, 1)))
|
||||
assert_(isinstance(x2, np.ndarray), repr((b, spmattype, 2)))
|
||||
|
||||
# check output shape
|
||||
if x.ndim == 1:
|
||||
# "vector"
|
||||
assert_equal(x1.shape, (A.shape[1],))
|
||||
assert_equal(x2.shape, (A.shape[1],))
|
||||
else:
|
||||
# "matrix"
|
||||
assert_equal(x1.shape, x.shape)
|
||||
assert_equal(x2.shape, x.shape)
|
||||
|
||||
A = csc_matrix((3, 3))
|
||||
b = csc_matrix((1, 3))
|
||||
assert_raises(ValueError, spsolve, A, b)
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_ndarray_support(self):
|
||||
A = array([[1., 2.], [2., 0.]])
|
||||
x = array([[1., 1.], [0.5, -0.5]])
|
||||
b = array([[2., 0.], [2., 2.]])
|
||||
|
||||
assert_array_almost_equal(x, spsolve(A, b))
|
||||
|
||||
def test_gssv_badinput(self):
|
||||
N = 10
|
||||
d = arange(N) + 1.0
|
||||
A = spdiags((d, 2*d, d[::-1]), (-3, 0, 5), N, N)
|
||||
|
||||
for spmatrix in (csc_matrix, csr_matrix):
|
||||
A = spmatrix(A)
|
||||
b = np.arange(N)
|
||||
|
||||
def not_c_contig(x):
|
||||
return x.repeat(2)[::2]
|
||||
|
||||
def not_1dim(x):
|
||||
return x[:,None]
|
||||
|
||||
def bad_type(x):
|
||||
return x.astype(bool)
|
||||
|
||||
def too_short(x):
|
||||
return x[:-1]
|
||||
|
||||
badops = [not_c_contig, not_1dim, bad_type, too_short]
|
||||
|
||||
for badop in badops:
|
||||
msg = "%r %r" % (spmatrix, badop)
|
||||
# Not C-contiguous
|
||||
assert_raises((ValueError, TypeError), _superlu.gssv,
|
||||
N, A.nnz, badop(A.data), A.indices, A.indptr,
|
||||
b, int(spmatrix == csc_matrix), err_msg=msg)
|
||||
assert_raises((ValueError, TypeError), _superlu.gssv,
|
||||
N, A.nnz, A.data, badop(A.indices), A.indptr,
|
||||
b, int(spmatrix == csc_matrix), err_msg=msg)
|
||||
assert_raises((ValueError, TypeError), _superlu.gssv,
|
||||
N, A.nnz, A.data, A.indices, badop(A.indptr),
|
||||
b, int(spmatrix == csc_matrix), err_msg=msg)
|
||||
|
||||
def test_sparsity_preservation(self):
|
||||
ident = csc_matrix([
|
||||
[1, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 1]])
|
||||
b = csc_matrix([
|
||||
[0, 1],
|
||||
[1, 0],
|
||||
[0, 0]])
|
||||
x = spsolve(ident, b)
|
||||
assert_equal(ident.nnz, 3)
|
||||
assert_equal(b.nnz, 2)
|
||||
assert_equal(x.nnz, 2)
|
||||
assert_allclose(x.A, b.A, atol=1e-12, rtol=1e-12)
|
||||
|
||||
def test_dtype_cast(self):
|
||||
A_real = scipy.sparse.csr_matrix([[1, 2, 0],
|
||||
[0, 0, 3],
|
||||
[4, 0, 5]])
|
||||
A_complex = scipy.sparse.csr_matrix([[1, 2, 0],
|
||||
[0, 0, 3],
|
||||
[4, 0, 5 + 1j]])
|
||||
b_real = np.array([1,1,1])
|
||||
b_complex = np.array([1,1,1]) + 1j*np.array([1,1,1])
|
||||
x = spsolve(A_real, b_real)
|
||||
assert_(np.issubdtype(x.dtype, np.floating))
|
||||
x = spsolve(A_real, b_complex)
|
||||
assert_(np.issubdtype(x.dtype, np.complexfloating))
|
||||
x = spsolve(A_complex, b_real)
|
||||
assert_(np.issubdtype(x.dtype, np.complexfloating))
|
||||
x = spsolve(A_complex, b_complex)
|
||||
assert_(np.issubdtype(x.dtype, np.complexfloating))
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.skipif(not has_umfpack, reason="umfpack not available")
|
||||
def test_bug_8278(self):
|
||||
check_free_memory(8000)
|
||||
use_solver(useUmfpack=True)
|
||||
A, b = setup_bug_8278()
|
||||
x = spsolve(A, b)
|
||||
assert_array_almost_equal(A @ x, b)
|
||||
|
||||
|
||||
class TestSplu(object):
|
||||
def setup_method(self):
|
||||
use_solver(useUmfpack=False)
|
||||
n = 40
|
||||
d = arange(n) + 1
|
||||
self.n = n
|
||||
self.A = spdiags((d, 2*d, d[::-1]), (-3, 0, 5), n, n)
|
||||
random.seed(1234)
|
||||
|
||||
def _smoketest(self, spxlu, check, dtype):
|
||||
if np.issubdtype(dtype, np.complexfloating):
|
||||
A = self.A + 1j*self.A.T
|
||||
else:
|
||||
A = self.A
|
||||
|
||||
A = A.astype(dtype)
|
||||
lu = spxlu(A)
|
||||
|
||||
rng = random.RandomState(1234)
|
||||
|
||||
# Input shapes
|
||||
for k in [None, 1, 2, self.n, self.n+2]:
|
||||
msg = "k=%r" % (k,)
|
||||
|
||||
if k is None:
|
||||
b = rng.rand(self.n)
|
||||
else:
|
||||
b = rng.rand(self.n, k)
|
||||
|
||||
if np.issubdtype(dtype, np.complexfloating):
|
||||
b = b + 1j*rng.rand(*b.shape)
|
||||
b = b.astype(dtype)
|
||||
|
||||
x = lu.solve(b)
|
||||
check(A, b, x, msg)
|
||||
|
||||
x = lu.solve(b, 'T')
|
||||
check(A.T, b, x, msg)
|
||||
|
||||
x = lu.solve(b, 'H')
|
||||
check(A.T.conj(), b, x, msg)
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_splu_smoketest(self):
|
||||
self._internal_test_splu_smoketest()
|
||||
|
||||
def _internal_test_splu_smoketest(self):
|
||||
# Check that splu works at all
|
||||
def check(A, b, x, msg=""):
|
||||
eps = np.finfo(A.dtype).eps
|
||||
r = A * x
|
||||
assert_(abs(r - b).max() < 1e3*eps, msg)
|
||||
|
||||
self._smoketest(splu, check, np.float32)
|
||||
self._smoketest(splu, check, np.float64)
|
||||
self._smoketest(splu, check, np.complex64)
|
||||
self._smoketest(splu, check, np.complex128)
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_spilu_smoketest(self):
|
||||
self._internal_test_spilu_smoketest()
|
||||
|
||||
def _internal_test_spilu_smoketest(self):
|
||||
errors = []
|
||||
|
||||
def check(A, b, x, msg=""):
|
||||
r = A * x
|
||||
err = abs(r - b).max()
|
||||
assert_(err < 1e-2, msg)
|
||||
if b.dtype in (np.float64, np.complex128):
|
||||
errors.append(err)
|
||||
|
||||
self._smoketest(spilu, check, np.float32)
|
||||
self._smoketest(spilu, check, np.float64)
|
||||
self._smoketest(spilu, check, np.complex64)
|
||||
self._smoketest(spilu, check, np.complex128)
|
||||
|
||||
assert_(max(errors) > 1e-5)
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_spilu_drop_rule(self):
|
||||
# Test passing in the drop_rule argument to spilu.
|
||||
A = identity(2)
|
||||
|
||||
rules = [
|
||||
b'basic,area'.decode('ascii'), # unicode
|
||||
b'basic,area', # ascii
|
||||
[b'basic', b'area'.decode('ascii')]
|
||||
]
|
||||
for rule in rules:
|
||||
# Argument should be accepted
|
||||
assert_(isinstance(spilu(A, drop_rule=rule), SuperLU))
|
||||
|
||||
def test_splu_nnz0(self):
|
||||
A = csc_matrix((5,5), dtype='d')
|
||||
assert_raises(RuntimeError, splu, A)
|
||||
|
||||
def test_spilu_nnz0(self):
|
||||
A = csc_matrix((5,5), dtype='d')
|
||||
assert_raises(RuntimeError, spilu, A)
|
||||
|
||||
def test_splu_basic(self):
|
||||
# Test basic splu functionality.
|
||||
n = 30
|
||||
rng = random.RandomState(12)
|
||||
a = rng.rand(n, n)
|
||||
a[a < 0.95] = 0
|
||||
# First test with a singular matrix
|
||||
a[:, 0] = 0
|
||||
a_ = csc_matrix(a)
|
||||
# Matrix is exactly singular
|
||||
assert_raises(RuntimeError, splu, a_)
|
||||
|
||||
# Make a diagonal dominant, to make sure it is not singular
|
||||
a += 4*eye(n)
|
||||
a_ = csc_matrix(a)
|
||||
lu = splu(a_)
|
||||
b = ones(n)
|
||||
x = lu.solve(b)
|
||||
assert_almost_equal(dot(a, x), b)
|
||||
|
||||
def test_splu_perm(self):
|
||||
# Test the permutation vectors exposed by splu.
|
||||
n = 30
|
||||
a = random.random((n, n))
|
||||
a[a < 0.95] = 0
|
||||
# Make a diagonal dominant, to make sure it is not singular
|
||||
a += 4*eye(n)
|
||||
a_ = csc_matrix(a)
|
||||
lu = splu(a_)
|
||||
# Check that the permutation indices do belong to [0, n-1].
|
||||
for perm in (lu.perm_r, lu.perm_c):
|
||||
assert_(all(perm > -1))
|
||||
assert_(all(perm < n))
|
||||
assert_equal(len(unique(perm)), len(perm))
|
||||
|
||||
# Now make a symmetric, and test that the two permutation vectors are
|
||||
# the same
|
||||
# Note: a += a.T relies on undefined behavior.
|
||||
a = a + a.T
|
||||
a_ = csc_matrix(a)
|
||||
lu = splu(a_)
|
||||
assert_array_equal(lu.perm_r, lu.perm_c)
|
||||
|
||||
@pytest.mark.parametrize("splu_fun, rtol", [(splu, 1e-7), (spilu, 1e-1)])
|
||||
def test_natural_permc(self, splu_fun, rtol):
|
||||
# Test that the "NATURAL" permc_spec does not permute the matrix
|
||||
np.random.seed(42)
|
||||
n = 500
|
||||
p = 0.01
|
||||
A = scipy.sparse.random(n, n, p)
|
||||
x = np.random.rand(n)
|
||||
# Make A diagonal dominant to make sure it is not singular
|
||||
A += (n+1)*scipy.sparse.identity(n)
|
||||
A_ = csc_matrix(A)
|
||||
b = A_ @ x
|
||||
|
||||
# without permc_spec, permutation is not identity
|
||||
lu = splu_fun(A_)
|
||||
assert_(np.any(lu.perm_c != np.arange(n)))
|
||||
|
||||
# with permc_spec="NATURAL", permutation is identity
|
||||
lu = splu_fun(A_, permc_spec="NATURAL")
|
||||
assert_array_equal(lu.perm_c, np.arange(n))
|
||||
|
||||
# Also, lu decomposition is valid
|
||||
x2 = lu.solve(b)
|
||||
assert_allclose(x, x2, rtol=rtol)
|
||||
|
||||
@pytest.mark.skipif(not hasattr(sys, 'getrefcount'), reason="no sys.getrefcount")
|
||||
def test_lu_refcount(self):
|
||||
# Test that we are keeping track of the reference count with splu.
|
||||
n = 30
|
||||
a = random.random((n, n))
|
||||
a[a < 0.95] = 0
|
||||
# Make a diagonal dominant, to make sure it is not singular
|
||||
a += 4*eye(n)
|
||||
a_ = csc_matrix(a)
|
||||
lu = splu(a_)
|
||||
|
||||
# And now test that we don't have a refcount bug
|
||||
rc = sys.getrefcount(lu)
|
||||
for attr in ('perm_r', 'perm_c'):
|
||||
perm = getattr(lu, attr)
|
||||
assert_equal(sys.getrefcount(lu), rc + 1)
|
||||
del perm
|
||||
assert_equal(sys.getrefcount(lu), rc)
|
||||
|
||||
def test_bad_inputs(self):
|
||||
A = self.A.tocsc()
|
||||
|
||||
assert_raises(ValueError, splu, A[:,:4])
|
||||
assert_raises(ValueError, spilu, A[:,:4])
|
||||
|
||||
for lu in [splu(A), spilu(A)]:
|
||||
b = random.rand(42)
|
||||
B = random.rand(42, 3)
|
||||
BB = random.rand(self.n, 3, 9)
|
||||
assert_raises(ValueError, lu.solve, b)
|
||||
assert_raises(ValueError, lu.solve, B)
|
||||
assert_raises(ValueError, lu.solve, BB)
|
||||
assert_raises(TypeError, lu.solve,
|
||||
b.astype(np.complex64))
|
||||
assert_raises(TypeError, lu.solve,
|
||||
b.astype(np.complex128))
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_superlu_dlamch_i386_nan(self):
|
||||
# SuperLU 4.3 calls some functions returning floats without
|
||||
# declaring them. On i386@linux call convention, this fails to
|
||||
# clear floating point registers after call. As a result, NaN
|
||||
# can appear in the next floating point operation made.
|
||||
#
|
||||
# Here's a test case that triggered the issue.
|
||||
n = 8
|
||||
d = np.arange(n) + 1
|
||||
A = spdiags((d, 2*d, d[::-1]), (-3, 0, 5), n, n)
|
||||
A = A.astype(np.float32)
|
||||
spilu(A)
|
||||
A = A + 1j*A
|
||||
B = A.A
|
||||
assert_(not np.isnan(B).any())
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_lu_attr(self):
|
||||
|
||||
def check(dtype, complex_2=False):
|
||||
A = self.A.astype(dtype)
|
||||
|
||||
if complex_2:
|
||||
A = A + 1j*A.T
|
||||
|
||||
n = A.shape[0]
|
||||
lu = splu(A)
|
||||
|
||||
# Check that the decomposition is as advertized
|
||||
|
||||
Pc = np.zeros((n, n))
|
||||
Pc[np.arange(n), lu.perm_c] = 1
|
||||
|
||||
Pr = np.zeros((n, n))
|
||||
Pr[lu.perm_r, np.arange(n)] = 1
|
||||
|
||||
Ad = A.toarray()
|
||||
lhs = Pr.dot(Ad).dot(Pc)
|
||||
rhs = (lu.L * lu.U).toarray()
|
||||
|
||||
eps = np.finfo(dtype).eps
|
||||
|
||||
assert_allclose(lhs, rhs, atol=100*eps)
|
||||
|
||||
check(np.float32)
|
||||
check(np.float64)
|
||||
check(np.complex64)
|
||||
check(np.complex128)
|
||||
check(np.complex64, True)
|
||||
check(np.complex128, True)
|
||||
|
||||
@pytest.mark.slow
|
||||
@sup_sparse_efficiency
|
||||
def test_threads_parallel(self):
|
||||
oks = []
|
||||
|
||||
def worker():
|
||||
try:
|
||||
self.test_splu_basic()
|
||||
self._internal_test_splu_smoketest()
|
||||
self._internal_test_spilu_smoketest()
|
||||
oks.append(True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
threads = [threading.Thread(target=worker)
|
||||
for k in range(20)]
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
assert_equal(len(oks), 20)
|
||||
|
||||
|
||||
class TestSpsolveTriangular(object):
|
||||
def setup_method(self):
|
||||
use_solver(useUmfpack=False)
|
||||
|
||||
def test_singular(self):
|
||||
n = 5
|
||||
A = csr_matrix((n, n))
|
||||
b = np.arange(n)
|
||||
for lower in (True, False):
|
||||
assert_raises(scipy.linalg.LinAlgError, spsolve_triangular, A, b, lower=lower)
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_bad_shape(self):
|
||||
# A is not square.
|
||||
A = np.zeros((3, 4))
|
||||
b = ones((4, 1))
|
||||
assert_raises(ValueError, spsolve_triangular, A, b)
|
||||
# A2 and b2 have incompatible shapes.
|
||||
A2 = csr_matrix(eye(3))
|
||||
b2 = array([1.0, 2.0])
|
||||
assert_raises(ValueError, spsolve_triangular, A2, b2)
|
||||
|
||||
@sup_sparse_efficiency
|
||||
def test_input_types(self):
|
||||
A = array([[1., 0.], [1., 2.]])
|
||||
b = array([[2., 0.], [2., 2.]])
|
||||
for matrix_type in (array, csc_matrix, csr_matrix):
|
||||
x = spsolve_triangular(matrix_type(A), b, lower=True)
|
||||
assert_array_almost_equal(A.dot(x), b)
|
||||
|
||||
@pytest.mark.slow
|
||||
@sup_sparse_efficiency
|
||||
def test_random(self):
|
||||
def random_triangle_matrix(n, lower=True):
|
||||
A = scipy.sparse.random(n, n, density=0.1, format='coo')
|
||||
if lower:
|
||||
A = scipy.sparse.tril(A)
|
||||
else:
|
||||
A = scipy.sparse.triu(A)
|
||||
A = A.tocsr(copy=False)
|
||||
for i in range(n):
|
||||
A[i, i] = np.random.rand() + 1
|
||||
return A
|
||||
|
||||
np.random.seed(1234)
|
||||
for lower in (True, False):
|
||||
for n in (10, 10**2, 10**3):
|
||||
A = random_triangle_matrix(n, lower=lower)
|
||||
for m in (1, 10):
|
||||
for b in (np.random.rand(n, m),
|
||||
np.random.randint(-9, 9, (n, m)),
|
||||
np.random.randint(-9, 9, (n, m)) +
|
||||
np.random.randint(-9, 9, (n, m)) * 1j):
|
||||
x = spsolve_triangular(A, b, lower=lower)
|
||||
assert_array_almost_equal(A.dot(x), b)
|
||||
x = spsolve_triangular(A, b, lower=lower,
|
||||
unit_diagonal=True)
|
||||
A.setdiag(1)
|
||||
assert_array_almost_equal(A.dot(x), b)
|
Loading…
Add table
Add a link
Reference in a new issue