1import numpy as np
2from numpy.linalg import LinAlgError
3from .blas import get_blas_funcs
4from .lapack import get_lapack_funcs
5
6__all__ = ['LinAlgError', 'LinAlgWarning', 'norm']
7
8
9class LinAlgWarning(RuntimeWarning):
10    """
11    The warning emitted when a linear algebra related operation is close
12    to fail conditions of the algorithm or loss of accuracy is expected.
13    """
14    pass
15
16
17def norm(a, ord=None, axis=None, keepdims=False, check_finite=True):
18    """
19    Matrix or vector norm.
20
21    This function is able to return one of eight different matrix norms,
22    or one of an infinite number of vector norms (described below), depending
23    on the value of the ``ord`` parameter. For tensors with rank different from
24    1 or 2, only `ord=None` is supported.
25
26    Parameters
27    ----------
28    a : array_like
29        Input array. If `axis` is None, `a` must be 1-D or 2-D, unless `ord`
30        is None. If both `axis` and `ord` are None, the 2-norm of
31        ``a.ravel`` will be returned.
32    ord : {int, inf, -inf, 'fro', 'nuc', None}, optional
33        Order of the norm (see table under ``Notes``). inf means NumPy's
34        `inf` object.
35    axis : {int, 2-tuple of ints, None}, optional
36        If `axis` is an integer, it specifies the axis of `a` along which to
37        compute the vector norms. If `axis` is a 2-tuple, it specifies the
38        axes that hold 2-D matrices, and the matrix norms of these matrices
39        are computed. If `axis` is None then either a vector norm (when `a`
40        is 1-D) or a matrix norm (when `a` is 2-D) is returned.
41    keepdims : bool, optional
42        If this is set to True, the axes which are normed over are left in the
43        result as dimensions with size one. With this option the result will
44        broadcast correctly against the original `a`.
45    check_finite : bool, optional
46        Whether to check that the input matrix contains only finite numbers.
47        Disabling may give a performance gain, but may result in problems
48        (crashes, non-termination) if the inputs do contain infinities or NaNs.
49
50    Returns
51    -------
52    n : float or ndarray
53        Norm of the matrix or vector(s).
54
55    Notes
56    -----
57    For values of ``ord <= 0``, the result is, strictly speaking, not a
58    mathematical 'norm', but it may still be useful for various numerical
59    purposes.
60
61    The following norms can be calculated:
62
63    =====  ============================  ==========================
64    ord    norm for matrices             norm for vectors
65    =====  ============================  ==========================
66    None   Frobenius norm                2-norm
67    'fro'  Frobenius norm                --
68    'nuc'  nuclear norm                  --
69    inf    max(sum(abs(a), axis=1))      max(abs(a))
70    -inf   min(sum(abs(a), axis=1))      min(abs(a))
71    0      --                            sum(a != 0)
72    1      max(sum(abs(a), axis=0))      as below
73    -1     min(sum(abs(a), axis=0))      as below
74    2      2-norm (largest sing. value)  as below
75    -2     smallest singular value       as below
76    other  --                            sum(abs(a)**ord)**(1./ord)
77    =====  ============================  ==========================
78
79    The Frobenius norm is given by [1]_:
80
81        :math:`||A||_F = [\\sum_{i,j} abs(a_{i,j})^2]^{1/2}`
82
83    The nuclear norm is the sum of the singular values.
84
85    Both the Frobenius and nuclear norm orders are only defined for
86    matrices.
87
88    References
89    ----------
90    .. [1] G. H. Golub and C. F. Van Loan, *Matrix Computations*,
91           Baltimore, MD, Johns Hopkins University Press, 1985, pg. 15
92
93    Examples
94    --------
95    >>> from scipy.linalg import norm
96    >>> a = np.arange(9) - 4.0
97    >>> a
98    array([-4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.])
99    >>> b = a.reshape((3, 3))
100    >>> b
101    array([[-4., -3., -2.],
102           [-1.,  0.,  1.],
103           [ 2.,  3.,  4.]])
104
105    >>> norm(a)
106    7.745966692414834
107    >>> norm(b)
108    7.745966692414834
109    >>> norm(b, 'fro')
110    7.745966692414834
111    >>> norm(a, np.inf)
112    4
113    >>> norm(b, np.inf)
114    9
115    >>> norm(a, -np.inf)
116    0
117    >>> norm(b, -np.inf)
118    2
119
120    >>> norm(a, 1)
121    20
122    >>> norm(b, 1)
123    7
124    >>> norm(a, -1)
125    -4.6566128774142013e-010
126    >>> norm(b, -1)
127    6
128    >>> norm(a, 2)
129    7.745966692414834
130    >>> norm(b, 2)
131    7.3484692283495345
132
133    >>> norm(a, -2)
134    0
135    >>> norm(b, -2)
136    1.8570331885190563e-016
137    >>> norm(a, 3)
138    5.8480354764257312
139    >>> norm(a, -3)
140    0
141
142    """
143    # Differs from numpy only in non-finite handling and the use of blas.
144    if check_finite:
145        a = np.asarray_chkfinite(a)
146    else:
147        a = np.asarray(a)
148
149    if a.size and a.dtype.char in 'fdFD' and axis is None and not keepdims:
150
151        if ord in (None, 2) and (a.ndim == 1):
152            # use blas for fast and stable euclidean norm
153            nrm2 = get_blas_funcs('nrm2', dtype=a.dtype, ilp64='preferred')
154            return nrm2(a)
155
156        if a.ndim == 2:
157            # Use lapack for a couple fast matrix norms.
158            # For some reason the *lange frobenius norm is slow.
159            lange_args = None
160            # Make sure this works if the user uses the axis keywords
161            # to apply the norm to the transpose.
162            if ord == 1:
163                if np.isfortran(a):
164                    lange_args = '1', a
165                elif np.isfortran(a.T):
166                    lange_args = 'i', a.T
167            elif ord == np.inf:
168                if np.isfortran(a):
169                    lange_args = 'i', a
170                elif np.isfortran(a.T):
171                    lange_args = '1', a.T
172            if lange_args:
173                lange = get_lapack_funcs('lange', dtype=a.dtype, ilp64='preferred')
174                return lange(*lange_args)
175
176    # fall back to numpy in every other case
177    return np.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims)
178
179
180def _datacopied(arr, original):
181    """
182    Strict check for `arr` not sharing any data with `original`,
183    under the assumption that arr = asarray(original)
184
185    """
186    if arr is original:
187        return False
188    if not isinstance(original, np.ndarray) and hasattr(original, '__array__'):
189        return False
190    return arr.base is None
191