123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- import numpy as np
- from numpy.linalg import LinAlgError
- from .blas import get_blas_funcs
- from .lapack import get_lapack_funcs
- __all__ = ['LinAlgError', 'LinAlgWarning', 'norm']
- class LinAlgWarning(RuntimeWarning):
- """
- The warning emitted when a linear algebra related operation is close
- to fail conditions of the algorithm or loss of accuracy is expected.
- """
- pass
- def norm(a, ord=None, axis=None, keepdims=False, check_finite=True):
- """
- Matrix or vector norm.
- This function is able to return one of eight different matrix norms,
- or one of an infinite number of vector norms (described below), depending
- on the value of the ``ord`` parameter. For tensors with rank different from
- 1 or 2, only `ord=None` is supported.
- Parameters
- ----------
- a : array_like
- Input array. If `axis` is None, `a` must be 1-D or 2-D, unless `ord`
- is None. If both `axis` and `ord` are None, the 2-norm of
- ``a.ravel`` will be returned.
- ord : {int, inf, -inf, 'fro', 'nuc', None}, optional
- Order of the norm (see table under ``Notes``). inf means NumPy's
- `inf` object.
- axis : {int, 2-tuple of ints, None}, optional
- If `axis` is an integer, it specifies the axis of `a` along which to
- compute the vector norms. If `axis` is a 2-tuple, it specifies the
- axes that hold 2-D matrices, and the matrix norms of these matrices
- are computed. If `axis` is None then either a vector norm (when `a`
- is 1-D) or a matrix norm (when `a` is 2-D) is returned.
- keepdims : bool, optional
- If this is set to True, the axes which are normed over are left in the
- result as dimensions with size one. With this option the result will
- broadcast correctly against the original `a`.
- check_finite : bool, optional
- Whether to check that the input matrix contains only finite numbers.
- Disabling may give a performance gain, but may result in problems
- (crashes, non-termination) if the inputs do contain infinities or NaNs.
- Returns
- -------
- n : float or ndarray
- Norm of the matrix or vector(s).
- Notes
- -----
- For values of ``ord <= 0``, the result is, strictly speaking, not a
- mathematical 'norm', but it may still be useful for various numerical
- purposes.
- The following norms can be calculated:
- ===== ============================ ==========================
- ord norm for matrices norm for vectors
- ===== ============================ ==========================
- None Frobenius norm 2-norm
- 'fro' Frobenius norm --
- 'nuc' nuclear norm --
- inf max(sum(abs(a), axis=1)) max(abs(a))
- -inf min(sum(abs(a), axis=1)) min(abs(a))
- 0 -- sum(a != 0)
- 1 max(sum(abs(a), axis=0)) as below
- -1 min(sum(abs(a), axis=0)) as below
- 2 2-norm (largest sing. value) as below
- -2 smallest singular value as below
- other -- sum(abs(a)**ord)**(1./ord)
- ===== ============================ ==========================
- The Frobenius norm is given by [1]_:
- :math:`||A||_F = [\\sum_{i,j} abs(a_{i,j})^2]^{1/2}`
- The nuclear norm is the sum of the singular values.
- Both the Frobenius and nuclear norm orders are only defined for
- matrices.
- References
- ----------
- .. [1] G. H. Golub and C. F. Van Loan, *Matrix Computations*,
- Baltimore, MD, Johns Hopkins University Press, 1985, pg. 15
- Examples
- --------
- >>> import numpy as np
- >>> from scipy.linalg import norm
- >>> a = np.arange(9) - 4.0
- >>> a
- array([-4., -3., -2., -1., 0., 1., 2., 3., 4.])
- >>> b = a.reshape((3, 3))
- >>> b
- array([[-4., -3., -2.],
- [-1., 0., 1.],
- [ 2., 3., 4.]])
- >>> norm(a)
- 7.745966692414834
- >>> norm(b)
- 7.745966692414834
- >>> norm(b, 'fro')
- 7.745966692414834
- >>> norm(a, np.inf)
- 4
- >>> norm(b, np.inf)
- 9
- >>> norm(a, -np.inf)
- 0
- >>> norm(b, -np.inf)
- 2
- >>> norm(a, 1)
- 20
- >>> norm(b, 1)
- 7
- >>> norm(a, -1)
- -4.6566128774142013e-010
- >>> norm(b, -1)
- 6
- >>> norm(a, 2)
- 7.745966692414834
- >>> norm(b, 2)
- 7.3484692283495345
- >>> norm(a, -2)
- 0
- >>> norm(b, -2)
- 1.8570331885190563e-016
- >>> norm(a, 3)
- 5.8480354764257312
- >>> norm(a, -3)
- 0
- """
- # Differs from numpy only in non-finite handling and the use of blas.
- if check_finite:
- a = np.asarray_chkfinite(a)
- else:
- a = np.asarray(a)
- if a.size and a.dtype.char in 'fdFD' and axis is None and not keepdims:
- if ord in (None, 2) and (a.ndim == 1):
- # use blas for fast and stable euclidean norm
- nrm2 = get_blas_funcs('nrm2', dtype=a.dtype, ilp64='preferred')
- return nrm2(a)
- if a.ndim == 2:
- # Use lapack for a couple fast matrix norms.
- # For some reason the *lange frobenius norm is slow.
- lange_args = None
- # Make sure this works if the user uses the axis keywords
- # to apply the norm to the transpose.
- if ord == 1:
- if np.isfortran(a):
- lange_args = '1', a
- elif np.isfortran(a.T):
- lange_args = 'i', a.T
- elif ord == np.inf:
- if np.isfortran(a):
- lange_args = 'i', a
- elif np.isfortran(a.T):
- lange_args = '1', a.T
- if lange_args:
- lange = get_lapack_funcs('lange', dtype=a.dtype, ilp64='preferred')
- return lange(*lange_args)
- # fall back to numpy in every other case
- return np.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims)
- def _datacopied(arr, original):
- """
- Strict check for `arr` not sharing any data with `original`,
- under the assumption that arr = asarray(original)
- """
- if arr is original:
- return False
- if not isinstance(original, np.ndarray) and hasattr(original, '__array__'):
- return False
- return arr.base is None
|