Inzynierka/Lib/site-packages/scipy/sparse/linalg/_isolve/utils.py
2023-06-02 12:51:02 +02:00

128 lines
3.5 KiB
Python

__docformat__ = "restructuredtext en"
__all__ = []
from numpy import asanyarray, asarray, array, zeros
from scipy.sparse.linalg._interface import aslinearoperator, LinearOperator, \
IdentityOperator
_coerce_rules = {('f','f'):'f', ('f','d'):'d', ('f','F'):'F',
('f','D'):'D', ('d','f'):'d', ('d','d'):'d',
('d','F'):'D', ('d','D'):'D', ('F','f'):'F',
('F','d'):'D', ('F','F'):'F', ('F','D'):'D',
('D','f'):'D', ('D','d'):'D', ('D','F'):'D',
('D','D'):'D'}
def coerce(x,y):
if x not in 'fdFD':
x = 'd'
if y not in 'fdFD':
y = 'd'
return _coerce_rules[x,y]
def id(x):
return x
def make_system(A, M, x0, b):
"""Make a linear system Ax=b
Parameters
----------
A : LinearOperator
sparse or dense matrix (or any valid input to aslinearoperator)
M : {LinearOperator, Nones}
preconditioner
sparse or dense matrix (or any valid input to aslinearoperator)
x0 : {array_like, str, None}
initial guess to iterative method.
``x0 = 'Mb'`` means using the nonzero initial guess ``M @ b``.
Default is `None`, which means using the zero initial guess.
b : array_like
right hand side
Returns
-------
(A, M, x, b, postprocess)
A : LinearOperator
matrix of the linear system
M : LinearOperator
preconditioner
x : rank 1 ndarray
initial guess
b : rank 1 ndarray
right hand side
postprocess : function
converts the solution vector to the appropriate
type and dimensions (e.g. (N,1) matrix)
"""
A_ = A
A = aslinearoperator(A)
if A.shape[0] != A.shape[1]:
raise ValueError(f'expected square matrix, but got shape={(A.shape,)}')
N = A.shape[0]
b = asanyarray(b)
if not (b.shape == (N,1) or b.shape == (N,)):
raise ValueError(f'shapes of A {A.shape} and b {b.shape} are '
'incompatible')
if b.dtype.char not in 'fdFD':
b = b.astype('d') # upcast non-FP types to double
def postprocess(x):
return x
if hasattr(A,'dtype'):
xtype = A.dtype.char
else:
xtype = A.matvec(b).dtype.char
xtype = coerce(xtype, b.dtype.char)
b = asarray(b,dtype=xtype) # make b the same type as x
b = b.ravel()
# process preconditioner
if M is None:
if hasattr(A_,'psolve'):
psolve = A_.psolve
else:
psolve = id
if hasattr(A_,'rpsolve'):
rpsolve = A_.rpsolve
else:
rpsolve = id
if psolve is id and rpsolve is id:
M = IdentityOperator(shape=A.shape, dtype=A.dtype)
else:
M = LinearOperator(A.shape, matvec=psolve, rmatvec=rpsolve,
dtype=A.dtype)
else:
M = aslinearoperator(M)
if A.shape != M.shape:
raise ValueError('matrix and preconditioner have different shapes')
# set initial guess
if x0 is None:
x = zeros(N, dtype=xtype)
elif isinstance(x0, str):
if x0 == 'Mb': # use nonzero initial guess ``M @ b``
bCopy = b.copy()
x = M.matvec(bCopy)
else:
x = array(x0, dtype=xtype)
if not (x.shape == (N, 1) or x.shape == (N,)):
raise ValueError(f'shapes of A {A.shape} and '
f'x0 {x.shape} are incompatible')
x = x.ravel()
return A, M, x, b, postprocess