1"""Lite version of scipy.linalg.
2
3Notes
4-----
5This module is a lite version of the linalg.py module in SciPy which
6contains high-level Python interface to the LAPACK library. The lite
7version only accesses the following LAPACK functions: dgesv, zgesv,
8dgeev, zgeev, dgesdd, zgesdd, dgelsd, zgelsd, dsyevd, zheevd, dgetrf,
9zgetrf, dpotrf, zpotrf, dgeqrf, zgeqrf, zungqr, dorgqr.
10"""
11
12__all__ = ['matrix_power', 'solve', 'tensorsolve', 'tensorinv', 'inv',
13 'cholesky', 'eigvals', 'eigvalsh', 'pinv', 'slogdet', 'det',
14 'svd', 'eig', 'eigh', 'lstsq', 'norm', 'qr', 'cond', 'matrix_rank',
15 'LinAlgError', 'multi_dot']
16
17import functools
18import operator
19import warnings
20from typing import NamedTuple, Any
21
22from .._utils import set_module
23from numpy.core import (
24 array, asarray, zeros, empty, empty_like, intc, single, double,
25 csingle, cdouble, inexact, complexfloating, newaxis, all, Inf, dot,
26 add, multiply, sqrt, sum, isfinite,
27 finfo, errstate, geterrobj, moveaxis, amin, amax, prod, abs,
28 atleast_2d, intp, asanyarray, object_, matmul,
29 swapaxes, divide, count_nonzero, isnan, sign, argsort, sort,
30 reciprocal
31)
32from numpy.core.multiarray import normalize_axis_index
33from numpy.core import overrides
34from numpy.lib.twodim_base import triu, eye
35from numpy.linalg import _umath_linalg
36
37from numpy._typing import NDArray
38
39class EigResult(NamedTuple):
40 eigenvalues: NDArray[Any]
41 eigenvectors: NDArray[Any]
42
43class EighResult(NamedTuple):
44 eigenvalues: NDArray[Any]
45 eigenvectors: NDArray[Any]
46
47class QRResult(NamedTuple):
48 Q: NDArray[Any]
49 R: NDArray[Any]
50
51class SlogdetResult(NamedTuple):
52 sign: NDArray[Any]
53 logabsdet: NDArray[Any]
54
55class SVDResult(NamedTuple):
56 U: NDArray[Any]
57 S: NDArray[Any]
58 Vh: NDArray[Any]
59
60array_function_dispatch = functools.partial(
61 overrides.array_function_dispatch, module='numpy.linalg')
62
63
64fortran_int = intc
65
66
67@set_module('numpy.linalg')
68class LinAlgError(ValueError):
69 """
70 Generic Python-exception-derived object raised by linalg functions.
71
72 General purpose exception class, derived from Python's ValueError
73 class, programmatically raised in linalg functions when a Linear
74 Algebra-related condition would prevent further correct execution of the
75 function.
76
77 Parameters
78 ----------
79 None
80
81 Examples
82 --------
83 >>> from numpy import linalg as LA
84 >>> LA.inv(np.zeros((2,2)))
85 Traceback (most recent call last):
86 File "<stdin>", line 1, in <module>
87 File "...linalg.py", line 350,
88 in inv return wrap(solve(a, identity(a.shape[0], dtype=a.dtype)))
89 File "...linalg.py", line 249,
90 in solve
91 raise LinAlgError('Singular matrix')
92 numpy.linalg.LinAlgError: Singular matrix
93
94 """
95
96
97def _determine_error_states():
98 errobj = geterrobj()
99 bufsize = errobj[0]
100
101 with errstate(invalid='call', over='ignore',
102 divide='ignore', under='ignore'):
103 invalid_call_errmask = geterrobj()[1]
104
105 return [bufsize, invalid_call_errmask, None]
106
107# Dealing with errors in _umath_linalg
108_linalg_error_extobj = _determine_error_states()
109del _determine_error_states
110
111def _raise_linalgerror_singular(err, flag):
112 raise LinAlgError("Singular matrix")
113
114def _raise_linalgerror_nonposdef(err, flag):
115 raise LinAlgError("Matrix is not positive definite")
116
117def _raise_linalgerror_eigenvalues_nonconvergence(err, flag):
118 raise LinAlgError("Eigenvalues did not converge")
119
120def _raise_linalgerror_svd_nonconvergence(err, flag):
121 raise LinAlgError("SVD did not converge")
122
123def _raise_linalgerror_lstsq(err, flag):
124 raise LinAlgError("SVD did not converge in Linear Least Squares")
125
126def _raise_linalgerror_qr(err, flag):
127 raise LinAlgError("Incorrect argument found while performing "
128 "QR factorization")
129
130def get_linalg_error_extobj(callback):
131 extobj = list(_linalg_error_extobj) # make a copy
132 extobj[2] = callback
133 return extobj
134
135def _makearray(a):
136 new = asarray(a)
137 wrap = getattr(a, "__array_prepare__", new.__array_wrap__)
138 return new, wrap
139
140def isComplexType(t):
141 return issubclass(t, complexfloating)
142
143_real_types_map = {single : single,
144 double : double,
145 csingle : single,
146 cdouble : double}
147
148_complex_types_map = {single : csingle,
149 double : cdouble,
150 csingle : csingle,
151 cdouble : cdouble}
152
153def _realType(t, default=double):
154 return _real_types_map.get(t, default)
155
156def _complexType(t, default=cdouble):
157 return _complex_types_map.get(t, default)
158
159def _commonType(*arrays):
160 # in lite version, use higher precision (always double or cdouble)
161 result_type = single
162 is_complex = False
163 for a in arrays:
164 type_ = a.dtype.type
165 if issubclass(type_, inexact):
166 if isComplexType(type_):
167 is_complex = True
168 rt = _realType(type_, default=None)
169 if rt is double:
170 result_type = double
171 elif rt is None:
172 # unsupported inexact scalar
173 raise TypeError("array type %s is unsupported in linalg" %
174 (a.dtype.name,))
175 else:
176 result_type = double
177 if is_complex:
178 result_type = _complex_types_map[result_type]
179 return cdouble, result_type
180 else:
181 return double, result_type
182
183
184def _to_native_byte_order(*arrays):
185 ret = []
186 for arr in arrays:
187 if arr.dtype.byteorder not in ('=', '|'):
188 ret.append(asarray(arr, dtype=arr.dtype.newbyteorder('=')))
189 else:
190 ret.append(arr)
191 if len(ret) == 1:
192 return ret[0]
193 else:
194 return ret
195
196
197def _assert_2d(*arrays):
198 for a in arrays:
199 if a.ndim != 2:
200 raise LinAlgError('%d-dimensional array given. Array must be '
201 'two-dimensional' % a.ndim)
202
203def _assert_stacked_2d(*arrays):
204 for a in arrays:
205 if a.ndim < 2:
206 raise LinAlgError('%d-dimensional array given. Array must be '
207 'at least two-dimensional' % a.ndim)
208
209def _assert_stacked_square(*arrays):
210 for a in arrays:
211 m, n = a.shape[-2:]
212 if m != n:
213 raise LinAlgError('Last 2 dimensions of the array must be square')
214
215def _assert_finite(*arrays):
216 for a in arrays:
217 if not isfinite(a).all():
218 raise LinAlgError("Array must not contain infs or NaNs")
219
220def _is_empty_2d(arr):
221 # check size first for efficiency
222 return arr.size == 0 and prod(arr.shape[-2:]) == 0
223
224
225def transpose(a):
226 """
227 Transpose each matrix in a stack of matrices.
228
229 Unlike np.transpose, this only swaps the last two axes, rather than all of
230 them
231
232 Parameters
233 ----------
234 a : (...,M,N) array_like
235
236 Returns
237 -------
238 aT : (...,N,M) ndarray
239 """
240 return swapaxes(a, -1, -2)
241
242# Linear equations
243
244def _tensorsolve_dispatcher(a, b, axes=None):
245 return (a, b)
246
247
248@array_function_dispatch(_tensorsolve_dispatcher)
249def tensorsolve(a, b, axes=None):
250 """
251 Solve the tensor equation ``a x = b`` for x.
252
253 It is assumed that all indices of `x` are summed over in the product,
254 together with the rightmost indices of `a`, as is done in, for example,
255 ``tensordot(a, x, axes=x.ndim)``.
256
257 Parameters
258 ----------
259 a : array_like
260 Coefficient tensor, of shape ``b.shape + Q``. `Q`, a tuple, equals
261 the shape of that sub-tensor of `a` consisting of the appropriate
262 number of its rightmost indices, and must be such that
263 ``prod(Q) == prod(b.shape)`` (in which sense `a` is said to be
264 'square').
265 b : array_like
266 Right-hand tensor, which can be of any shape.
267 axes : tuple of ints, optional
268 Axes in `a` to reorder to the right, before inversion.
269 If None (default), no reordering is done.
270
271 Returns
272 -------
273 x : ndarray, shape Q
274
275 Raises
276 ------
277 LinAlgError
278 If `a` is singular or not 'square' (in the above sense).
279
280 See Also
281 --------
282 numpy.tensordot, tensorinv, numpy.einsum
283
284 Examples
285 --------
286 >>> a = np.eye(2*3*4)
287 >>> a.shape = (2*3, 4, 2, 3, 4)
288 >>> b = np.random.randn(2*3, 4)
289 >>> x = np.linalg.tensorsolve(a, b)
290 >>> x.shape
291 (2, 3, 4)
292 >>> np.allclose(np.tensordot(a, x, axes=3), b)
293 True
294
295 """
296 a, wrap = _makearray(a)
297 b = asarray(b)
298 an = a.ndim
299
300 if axes is not None:
301 allaxes = list(range(0, an))
302 for k in axes:
303 allaxes.remove(k)
304 allaxes.insert(an, k)
305 a = a.transpose(allaxes)
306
307 oldshape = a.shape[-(an-b.ndim):]
308 prod = 1
309 for k in oldshape:
310 prod *= k
311
312 if a.size != prod ** 2:
313 raise LinAlgError(
314 "Input arrays must satisfy the requirement \
315 prod(a.shape[b.ndim:]) == prod(a.shape[:b.ndim])"
316 )
317
318 a = a.reshape(prod, prod)
319 b = b.ravel()
320 res = wrap(solve(a, b))
321 res.shape = oldshape
322 return res
323
324
325def _solve_dispatcher(a, b):
326 return (a, b)
327
328
329@array_function_dispatch(_solve_dispatcher)
330def solve(a, b):
331 """
332 Solve a linear matrix equation, or system of linear scalar equations.
333
334 Computes the "exact" solution, `x`, of the well-determined, i.e., full
335 rank, linear matrix equation `ax = b`.
336
337 Parameters
338 ----------
339 a : (..., M, M) array_like
340 Coefficient matrix.
341 b : {(..., M,), (..., M, K)}, array_like
342 Ordinate or "dependent variable" values.
343
344 Returns
345 -------
346 x : {(..., M,), (..., M, K)} ndarray
347 Solution to the system a x = b. Returned shape is identical to `b`.
348
349 Raises
350 ------
351 LinAlgError
352 If `a` is singular or not square.
353
354 See Also
355 --------
356 scipy.linalg.solve : Similar function in SciPy.
357
358 Notes
359 -----
360
361 .. versionadded:: 1.8.0
362
363 Broadcasting rules apply, see the `numpy.linalg` documentation for
364 details.
365
366 The solutions are computed using LAPACK routine ``_gesv``.
367
368 `a` must be square and of full-rank, i.e., all rows (or, equivalently,
369 columns) must be linearly independent; if either is not true, use
370 `lstsq` for the least-squares best "solution" of the
371 system/equation.
372
373 References
374 ----------
375 .. [1] G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando,
376 FL, Academic Press, Inc., 1980, pg. 22.
377
378 Examples
379 --------
380 Solve the system of equations ``x0 + 2 * x1 = 1`` and ``3 * x0 + 5 * x1 = 2``:
381
382 >>> a = np.array([[1, 2], [3, 5]])
383 >>> b = np.array([1, 2])
384 >>> x = np.linalg.solve(a, b)
385 >>> x
386 array([-1., 1.])
387
388 Check that the solution is correct:
389
390 >>> np.allclose(np.dot(a, x), b)
391 True
392
393 """
394 a, _ = _makearray(a)
395 _assert_stacked_2d(a)
396 _assert_stacked_square(a)
397 b, wrap = _makearray(b)
398 t, result_t = _commonType(a, b)
399
400 # We use the b = (..., M,) logic, only if the number of extra dimensions
401 # match exactly
402 if b.ndim == a.ndim - 1:
403 gufunc = _umath_linalg.solve1
404 else:
405 gufunc = _umath_linalg.solve
406
407 signature = 'DD->D' if isComplexType(t) else 'dd->d'
408 extobj = get_linalg_error_extobj(_raise_linalgerror_singular)
409 r = gufunc(a, b, signature=signature, extobj=extobj)
410
411 return wrap(r.astype(result_t, copy=False))
412
413
414def _tensorinv_dispatcher(a, ind=None):
415 return (a,)
416
417
418@array_function_dispatch(_tensorinv_dispatcher)
419def tensorinv(a, ind=2):
420 """
421 Compute the 'inverse' of an N-dimensional array.
422
423 The result is an inverse for `a` relative to the tensordot operation
424 ``tensordot(a, b, ind)``, i. e., up to floating-point accuracy,
425 ``tensordot(tensorinv(a), a, ind)`` is the "identity" tensor for the
426 tensordot operation.
427
428 Parameters
429 ----------
430 a : array_like
431 Tensor to 'invert'. Its shape must be 'square', i. e.,
432 ``prod(a.shape[:ind]) == prod(a.shape[ind:])``.
433 ind : int, optional
434 Number of first indices that are involved in the inverse sum.
435 Must be a positive integer, default is 2.
436
437 Returns
438 -------
439 b : ndarray
440 `a`'s tensordot inverse, shape ``a.shape[ind:] + a.shape[:ind]``.
441
442 Raises
443 ------
444 LinAlgError
445 If `a` is singular or not 'square' (in the above sense).
446
447 See Also
448 --------
449 numpy.tensordot, tensorsolve
450
451 Examples
452 --------
453 >>> a = np.eye(4*6)
454 >>> a.shape = (4, 6, 8, 3)
455 >>> ainv = np.linalg.tensorinv(a, ind=2)
456 >>> ainv.shape
457 (8, 3, 4, 6)
458 >>> b = np.random.randn(4, 6)
459 >>> np.allclose(np.tensordot(ainv, b), np.linalg.tensorsolve(a, b))
460 True
461
462 >>> a = np.eye(4*6)
463 >>> a.shape = (24, 8, 3)
464 >>> ainv = np.linalg.tensorinv(a, ind=1)
465 >>> ainv.shape
466 (8, 3, 24)
467 >>> b = np.random.randn(24)
468 >>> np.allclose(np.tensordot(ainv, b, 1), np.linalg.tensorsolve(a, b))
469 True
470
471 """
472 a = asarray(a)
473 oldshape = a.shape
474 prod = 1
475 if ind > 0:
476 invshape = oldshape[ind:] + oldshape[:ind]
477 for k in oldshape[ind:]:
478 prod *= k
479 else:
480 raise ValueError("Invalid ind argument.")
481 a = a.reshape(prod, -1)
482 ia = inv(a)
483 return ia.reshape(*invshape)
484
485
486# Matrix inversion
487
488def _unary_dispatcher(a):
489 return (a,)
490
491
492@array_function_dispatch(_unary_dispatcher)
493def inv(a):
494 """
495 Compute the (multiplicative) inverse of a matrix.
496
497 Given a square matrix `a`, return the matrix `ainv` satisfying
498 ``dot(a, ainv) = dot(ainv, a) = eye(a.shape[0])``.
499
500 Parameters
501 ----------
502 a : (..., M, M) array_like
503 Matrix to be inverted.
504
505 Returns
506 -------
507 ainv : (..., M, M) ndarray or matrix
508 (Multiplicative) inverse of the matrix `a`.
509
510 Raises
511 ------
512 LinAlgError
513 If `a` is not square or inversion fails.
514
515 See Also
516 --------
517 scipy.linalg.inv : Similar function in SciPy.
518
519 Notes
520 -----
521
522 .. versionadded:: 1.8.0
523
524 Broadcasting rules apply, see the `numpy.linalg` documentation for
525 details.
526
527 Examples
528 --------
529 >>> from numpy.linalg import inv
530 >>> a = np.array([[1., 2.], [3., 4.]])
531 >>> ainv = inv(a)
532 >>> np.allclose(np.dot(a, ainv), np.eye(2))
533 True
534 >>> np.allclose(np.dot(ainv, a), np.eye(2))
535 True
536
537 If a is a matrix object, then the return value is a matrix as well:
538
539 >>> ainv = inv(np.matrix(a))
540 >>> ainv
541 matrix([[-2. , 1. ],
542 [ 1.5, -0.5]])
543
544 Inverses of several matrices can be computed at once:
545
546 >>> a = np.array([[[1., 2.], [3., 4.]], [[1, 3], [3, 5]]])
547 >>> inv(a)
548 array([[[-2. , 1. ],
549 [ 1.5 , -0.5 ]],
550 [[-1.25, 0.75],
551 [ 0.75, -0.25]]])
552
553 """
554 a, wrap = _makearray(a)
555 _assert_stacked_2d(a)
556 _assert_stacked_square(a)
557 t, result_t = _commonType(a)
558
559 signature = 'D->D' if isComplexType(t) else 'd->d'
560 extobj = get_linalg_error_extobj(_raise_linalgerror_singular)
561 ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
562 return wrap(ainv.astype(result_t, copy=False))
563
564
565def _matrix_power_dispatcher(a, n):
566 return (a,)
567
568
569@array_function_dispatch(_matrix_power_dispatcher)
570def matrix_power(a, n):
571 """
572 Raise a square matrix to the (integer) power `n`.
573
574 For positive integers `n`, the power is computed by repeated matrix
575 squarings and matrix multiplications. If ``n == 0``, the identity matrix
576 of the same shape as M is returned. If ``n < 0``, the inverse
577 is computed and then raised to the ``abs(n)``.
578
579 .. note:: Stacks of object matrices are not currently supported.
580
581 Parameters
582 ----------
583 a : (..., M, M) array_like
584 Matrix to be "powered".
585 n : int
586 The exponent can be any integer or long integer, positive,
587 negative, or zero.
588
589 Returns
590 -------
591 a**n : (..., M, M) ndarray or matrix object
592 The return value is the same shape and type as `M`;
593 if the exponent is positive or zero then the type of the
594 elements is the same as those of `M`. If the exponent is
595 negative the elements are floating-point.
596
597 Raises
598 ------
599 LinAlgError
600 For matrices that are not square or that (for negative powers) cannot
601 be inverted numerically.
602
603 Examples
604 --------
605 >>> from numpy.linalg import matrix_power
606 >>> i = np.array([[0, 1], [-1, 0]]) # matrix equiv. of the imaginary unit
607 >>> matrix_power(i, 3) # should = -i
608 array([[ 0, -1],
609 [ 1, 0]])
610 >>> matrix_power(i, 0)
611 array([[1, 0],
612 [0, 1]])
613 >>> matrix_power(i, -3) # should = 1/(-i) = i, but w/ f.p. elements
614 array([[ 0., 1.],
615 [-1., 0.]])
616
617 Somewhat more sophisticated example
618
619 >>> q = np.zeros((4, 4))
620 >>> q[0:2, 0:2] = -i
621 >>> q[2:4, 2:4] = i
622 >>> q # one of the three quaternion units not equal to 1
623 array([[ 0., -1., 0., 0.],
624 [ 1., 0., 0., 0.],
625 [ 0., 0., 0., 1.],
626 [ 0., 0., -1., 0.]])
627 >>> matrix_power(q, 2) # = -np.eye(4)
628 array([[-1., 0., 0., 0.],
629 [ 0., -1., 0., 0.],
630 [ 0., 0., -1., 0.],
631 [ 0., 0., 0., -1.]])
632
633 """
634 a = asanyarray(a)
635 _assert_stacked_2d(a)
636 _assert_stacked_square(a)
637
638 try:
639 n = operator.index(n)
640 except TypeError as e:
641 raise TypeError("exponent must be an integer") from e
642
643 # Fall back on dot for object arrays. Object arrays are not supported by
644 # the current implementation of matmul using einsum
645 if a.dtype != object:
646 fmatmul = matmul
647 elif a.ndim == 2:
648 fmatmul = dot
649 else:
650 raise NotImplementedError(
651 "matrix_power not supported for stacks of object arrays")
652
653 if n == 0:
654 a = empty_like(a)
655 a[...] = eye(a.shape[-2], dtype=a.dtype)
656 return a
657
658 elif n < 0:
659 a = inv(a)
660 n = abs(n)
661
662 # short-cuts.
663 if n == 1:
664 return a
665
666 elif n == 2:
667 return fmatmul(a, a)
668
669 elif n == 3:
670 return fmatmul(fmatmul(a, a), a)
671
672 # Use binary decomposition to reduce the number of matrix multiplications.
673 # Here, we iterate over the bits of n, from LSB to MSB, raise `a` to
674 # increasing powers of 2, and multiply into the result as needed.
675 z = result = None
676 while n > 0:
677 z = a if z is None else fmatmul(z, z)
678 n, bit = divmod(n, 2)
679 if bit:
680 result = z if result is None else fmatmul(result, z)
681
682 return result
683
684
685# Cholesky decomposition
686
687
688@array_function_dispatch(_unary_dispatcher)
689def cholesky(a):
690 """
691 Cholesky decomposition.
692
693 Return the Cholesky decomposition, `L * L.H`, of the square matrix `a`,
694 where `L` is lower-triangular and .H is the conjugate transpose operator
695 (which is the ordinary transpose if `a` is real-valued). `a` must be
696 Hermitian (symmetric if real-valued) and positive-definite. No
697 checking is performed to verify whether `a` is Hermitian or not.
698 In addition, only the lower-triangular and diagonal elements of `a`
699 are used. Only `L` is actually returned.
700
701 Parameters
702 ----------
703 a : (..., M, M) array_like
704 Hermitian (symmetric if all elements are real), positive-definite
705 input matrix.
706
707 Returns
708 -------
709 L : (..., M, M) array_like
710 Lower-triangular Cholesky factor of `a`. Returns a matrix object if
711 `a` is a matrix object.
712
713 Raises
714 ------
715 LinAlgError
716 If the decomposition fails, for example, if `a` is not
717 positive-definite.
718
719 See Also
720 --------
721 scipy.linalg.cholesky : Similar function in SciPy.
722 scipy.linalg.cholesky_banded : Cholesky decompose a banded Hermitian
723 positive-definite matrix.
724 scipy.linalg.cho_factor : Cholesky decomposition of a matrix, to use in
725 `scipy.linalg.cho_solve`.
726
727 Notes
728 -----
729
730 .. versionadded:: 1.8.0
731
732 Broadcasting rules apply, see the `numpy.linalg` documentation for
733 details.
734
735 The Cholesky decomposition is often used as a fast way of solving
736
737 .. math:: A \\mathbf{x} = \\mathbf{b}
738
739 (when `A` is both Hermitian/symmetric and positive-definite).
740
741 First, we solve for :math:`\\mathbf{y}` in
742
743 .. math:: L \\mathbf{y} = \\mathbf{b},
744
745 and then for :math:`\\mathbf{x}` in
746
747 .. math:: L.H \\mathbf{x} = \\mathbf{y}.
748
749 Examples
750 --------
751 >>> A = np.array([[1,-2j],[2j,5]])
752 >>> A
753 array([[ 1.+0.j, -0.-2.j],
754 [ 0.+2.j, 5.+0.j]])
755 >>> L = np.linalg.cholesky(A)
756 >>> L
757 array([[1.+0.j, 0.+0.j],
758 [0.+2.j, 1.+0.j]])
759 >>> np.dot(L, L.T.conj()) # verify that L * L.H = A
760 array([[1.+0.j, 0.-2.j],
761 [0.+2.j, 5.+0.j]])
762 >>> A = [[1,-2j],[2j,5]] # what happens if A is only array_like?
763 >>> np.linalg.cholesky(A) # an ndarray object is returned
764 array([[1.+0.j, 0.+0.j],
765 [0.+2.j, 1.+0.j]])
766 >>> # But a matrix object is returned if A is a matrix object
767 >>> np.linalg.cholesky(np.matrix(A))
768 matrix([[ 1.+0.j, 0.+0.j],
769 [ 0.+2.j, 1.+0.j]])
770
771 """
772 extobj = get_linalg_error_extobj(_raise_linalgerror_nonposdef)
773 gufunc = _umath_linalg.cholesky_lo
774 a, wrap = _makearray(a)
775 _assert_stacked_2d(a)
776 _assert_stacked_square(a)
777 t, result_t = _commonType(a)
778 signature = 'D->D' if isComplexType(t) else 'd->d'
779 r = gufunc(a, signature=signature, extobj=extobj)
780 return wrap(r.astype(result_t, copy=False))
781
782
783# QR decomposition
784
785def _qr_dispatcher(a, mode=None):
786 return (a,)
787
788
789@array_function_dispatch(_qr_dispatcher)
790def qr(a, mode='reduced'):
791 """
792 Compute the qr factorization of a matrix.
793
794 Factor the matrix `a` as *qr*, where `q` is orthonormal and `r` is
795 upper-triangular.
796
797 Parameters
798 ----------
799 a : array_like, shape (..., M, N)
800 An array-like object with the dimensionality of at least 2.
801 mode : {'reduced', 'complete', 'r', 'raw'}, optional
802 If K = min(M, N), then
803
804 * 'reduced' : returns Q, R with dimensions (..., M, K), (..., K, N) (default)
805 * 'complete' : returns Q, R with dimensions (..., M, M), (..., M, N)
806 * 'r' : returns R only with dimensions (..., K, N)
807 * 'raw' : returns h, tau with dimensions (..., N, M), (..., K,)
808
809 The options 'reduced', 'complete, and 'raw' are new in numpy 1.8,
810 see the notes for more information. The default is 'reduced', and to
811 maintain backward compatibility with earlier versions of numpy both
812 it and the old default 'full' can be omitted. Note that array h
813 returned in 'raw' mode is transposed for calling Fortran. The
814 'economic' mode is deprecated. The modes 'full' and 'economic' may
815 be passed using only the first letter for backwards compatibility,
816 but all others must be spelled out. See the Notes for more
817 explanation.
818
819
820 Returns
821 -------
822 When mode is 'reduced' or 'complete', the result will be a namedtuple with
823 the attributes `Q` and `R`.
824
825 Q : ndarray of float or complex, optional
826 A matrix with orthonormal columns. When mode = 'complete' the
827 result is an orthogonal/unitary matrix depending on whether or not
828 a is real/complex. The determinant may be either +/- 1 in that
829 case. In case the number of dimensions in the input array is
830 greater than 2 then a stack of the matrices with above properties
831 is returned.
832 R : ndarray of float or complex, optional
833 The upper-triangular matrix or a stack of upper-triangular
834 matrices if the number of dimensions in the input array is greater
835 than 2.
836 (h, tau) : ndarrays of np.double or np.cdouble, optional
837 The array h contains the Householder reflectors that generate q
838 along with r. The tau array contains scaling factors for the
839 reflectors. In the deprecated 'economic' mode only h is returned.
840
841 Raises
842 ------
843 LinAlgError
844 If factoring fails.
845
846 See Also
847 --------
848 scipy.linalg.qr : Similar function in SciPy.
849 scipy.linalg.rq : Compute RQ decomposition of a matrix.
850
851 Notes
852 -----
853 This is an interface to the LAPACK routines ``dgeqrf``, ``zgeqrf``,
854 ``dorgqr``, and ``zungqr``.
855
856 For more information on the qr factorization, see for example:
857 https://en.wikipedia.org/wiki/QR_factorization
858
859 Subclasses of `ndarray` are preserved except for the 'raw' mode. So if
860 `a` is of type `matrix`, all the return values will be matrices too.
861
862 New 'reduced', 'complete', and 'raw' options for mode were added in
863 NumPy 1.8.0 and the old option 'full' was made an alias of 'reduced'. In
864 addition the options 'full' and 'economic' were deprecated. Because
865 'full' was the previous default and 'reduced' is the new default,
866 backward compatibility can be maintained by letting `mode` default.
867 The 'raw' option was added so that LAPACK routines that can multiply
868 arrays by q using the Householder reflectors can be used. Note that in
869 this case the returned arrays are of type np.double or np.cdouble and
870 the h array is transposed to be FORTRAN compatible. No routines using
871 the 'raw' return are currently exposed by numpy, but some are available
872 in lapack_lite and just await the necessary work.
873
874 Examples
875 --------
876 >>> a = np.random.randn(9, 6)
877 >>> Q, R = np.linalg.qr(a)
878 >>> np.allclose(a, np.dot(Q, R)) # a does equal QR
879 True
880 >>> R2 = np.linalg.qr(a, mode='r')
881 >>> np.allclose(R, R2) # mode='r' returns the same R as mode='full'
882 True
883 >>> a = np.random.normal(size=(3, 2, 2)) # Stack of 2 x 2 matrices as input
884 >>> Q, R = np.linalg.qr(a)
885 >>> Q.shape
886 (3, 2, 2)
887 >>> R.shape
888 (3, 2, 2)
889 >>> np.allclose(a, np.matmul(Q, R))
890 True
891
892 Example illustrating a common use of `qr`: solving of least squares
893 problems
894
895 What are the least-squares-best `m` and `y0` in ``y = y0 + mx`` for
896 the following data: {(0,1), (1,0), (1,2), (2,1)}. (Graph the points
897 and you'll see that it should be y0 = 0, m = 1.) The answer is provided
898 by solving the over-determined matrix equation ``Ax = b``, where::
899
900 A = array([[0, 1], [1, 1], [1, 1], [2, 1]])
901 x = array([[y0], [m]])
902 b = array([[1], [0], [2], [1]])
903
904 If A = QR such that Q is orthonormal (which is always possible via
905 Gram-Schmidt), then ``x = inv(R) * (Q.T) * b``. (In numpy practice,
906 however, we simply use `lstsq`.)
907
908 >>> A = np.array([[0, 1], [1, 1], [1, 1], [2, 1]])
909 >>> A
910 array([[0, 1],
911 [1, 1],
912 [1, 1],
913 [2, 1]])
914 >>> b = np.array([1, 2, 2, 3])
915 >>> Q, R = np.linalg.qr(A)
916 >>> p = np.dot(Q.T, b)
917 >>> np.dot(np.linalg.inv(R), p)
918 array([ 1., 1.])
919
920 """
921 if mode not in ('reduced', 'complete', 'r', 'raw'):
922 if mode in ('f', 'full'):
923 # 2013-04-01, 1.8
924 msg = "".join((
925 "The 'full' option is deprecated in favor of 'reduced'.\n",
926 "For backward compatibility let mode default."))
927 warnings.warn(msg, DeprecationWarning, stacklevel=2)
928 mode = 'reduced'
929 elif mode in ('e', 'economic'):
930 # 2013-04-01, 1.8
931 msg = "The 'economic' option is deprecated."
932 warnings.warn(msg, DeprecationWarning, stacklevel=2)
933 mode = 'economic'
934 else:
935 raise ValueError(f"Unrecognized mode '{mode}'")
936
937 a, wrap = _makearray(a)
938 _assert_stacked_2d(a)
939 m, n = a.shape[-2:]
940 t, result_t = _commonType(a)
941 a = a.astype(t, copy=True)
942 a = _to_native_byte_order(a)
943 mn = min(m, n)
944
945 if m <= n:
946 gufunc = _umath_linalg.qr_r_raw_m
947 else:
948 gufunc = _umath_linalg.qr_r_raw_n
949
950 signature = 'D->D' if isComplexType(t) else 'd->d'
951 extobj = get_linalg_error_extobj(_raise_linalgerror_qr)
952 tau = gufunc(a, signature=signature, extobj=extobj)
953
954 # handle modes that don't return q
955 if mode == 'r':
956 r = triu(a[..., :mn, :])
957 r = r.astype(result_t, copy=False)
958 return wrap(r)
959
960 if mode == 'raw':
961 q = transpose(a)
962 q = q.astype(result_t, copy=False)
963 tau = tau.astype(result_t, copy=False)
964 return wrap(q), tau
965
966 if mode == 'economic':
967 a = a.astype(result_t, copy=False)
968 return wrap(a)
969
970 # mc is the number of columns in the resulting q
971 # matrix. If the mode is complete then it is
972 # same as number of rows, and if the mode is reduced,
973 # then it is the minimum of number of rows and columns.
974 if mode == 'complete' and m > n:
975 mc = m
976 gufunc = _umath_linalg.qr_complete
977 else:
978 mc = mn
979 gufunc = _umath_linalg.qr_reduced
980
981 signature = 'DD->D' if isComplexType(t) else 'dd->d'
982 extobj = get_linalg_error_extobj(_raise_linalgerror_qr)
983 q = gufunc(a, tau, signature=signature, extobj=extobj)
984 r = triu(a[..., :mc, :])
985
986 q = q.astype(result_t, copy=False)
987 r = r.astype(result_t, copy=False)
988
989 return QRResult(wrap(q), wrap(r))
990
991# Eigenvalues
992
993
994@array_function_dispatch(_unary_dispatcher)
995def eigvals(a):
996 """
997 Compute the eigenvalues of a general matrix.
998
999 Main difference between `eigvals` and `eig`: the eigenvectors aren't
1000 returned.
1001
1002 Parameters
1003 ----------
1004 a : (..., M, M) array_like
1005 A complex- or real-valued matrix whose eigenvalues will be computed.
1006
1007 Returns
1008 -------
1009 w : (..., M,) ndarray
1010 The eigenvalues, each repeated according to its multiplicity.
1011 They are not necessarily ordered, nor are they necessarily
1012 real for real matrices.
1013
1014 Raises
1015 ------
1016 LinAlgError
1017 If the eigenvalue computation does not converge.
1018
1019 See Also
1020 --------
1021 eig : eigenvalues and right eigenvectors of general arrays
1022 eigvalsh : eigenvalues of real symmetric or complex Hermitian
1023 (conjugate symmetric) arrays.
1024 eigh : eigenvalues and eigenvectors of real symmetric or complex
1025 Hermitian (conjugate symmetric) arrays.
1026 scipy.linalg.eigvals : Similar function in SciPy.
1027
1028 Notes
1029 -----
1030
1031 .. versionadded:: 1.8.0
1032
1033 Broadcasting rules apply, see the `numpy.linalg` documentation for
1034 details.
1035
1036 This is implemented using the ``_geev`` LAPACK routines which compute
1037 the eigenvalues and eigenvectors of general square arrays.
1038
1039 Examples
1040 --------
1041 Illustration, using the fact that the eigenvalues of a diagonal matrix
1042 are its diagonal elements, that multiplying a matrix on the left
1043 by an orthogonal matrix, `Q`, and on the right by `Q.T` (the transpose
1044 of `Q`), preserves the eigenvalues of the "middle" matrix. In other words,
1045 if `Q` is orthogonal, then ``Q * A * Q.T`` has the same eigenvalues as
1046 ``A``:
1047
1048 >>> from numpy import linalg as LA
1049 >>> x = np.random.random()
1050 >>> Q = np.array([[np.cos(x), -np.sin(x)], [np.sin(x), np.cos(x)]])
1051 >>> LA.norm(Q[0, :]), LA.norm(Q[1, :]), np.dot(Q[0, :],Q[1, :])
1052 (1.0, 1.0, 0.0)
1053
1054 Now multiply a diagonal matrix by ``Q`` on one side and by ``Q.T`` on the other:
1055
1056 >>> D = np.diag((-1,1))
1057 >>> LA.eigvals(D)
1058 array([-1., 1.])
1059 >>> A = np.dot(Q, D)
1060 >>> A = np.dot(A, Q.T)
1061 >>> LA.eigvals(A)
1062 array([ 1., -1.]) # random
1063
1064 """
1065 a, wrap = _makearray(a)
1066 _assert_stacked_2d(a)
1067 _assert_stacked_square(a)
1068 _assert_finite(a)
1069 t, result_t = _commonType(a)
1070
1071 extobj = get_linalg_error_extobj(
1072 _raise_linalgerror_eigenvalues_nonconvergence)
1073 signature = 'D->D' if isComplexType(t) else 'd->D'
1074 w = _umath_linalg.eigvals(a, signature=signature, extobj=extobj)
1075
1076 if not isComplexType(t):
1077 if all(w.imag == 0):
1078 w = w.real
1079 result_t = _realType(result_t)
1080 else:
1081 result_t = _complexType(result_t)
1082
1083 return w.astype(result_t, copy=False)
1084
1085
1086def _eigvalsh_dispatcher(a, UPLO=None):
1087 return (a,)
1088
1089
1090@array_function_dispatch(_eigvalsh_dispatcher)
1091def eigvalsh(a, UPLO='L'):
1092 """
1093 Compute the eigenvalues of a complex Hermitian or real symmetric matrix.
1094
1095 Main difference from eigh: the eigenvectors are not computed.
1096
1097 Parameters
1098 ----------
1099 a : (..., M, M) array_like
1100 A complex- or real-valued matrix whose eigenvalues are to be
1101 computed.
1102 UPLO : {'L', 'U'}, optional
1103 Specifies whether the calculation is done with the lower triangular
1104 part of `a` ('L', default) or the upper triangular part ('U').
1105 Irrespective of this value only the real parts of the diagonal will
1106 be considered in the computation to preserve the notion of a Hermitian
1107 matrix. It therefore follows that the imaginary part of the diagonal
1108 will always be treated as zero.
1109
1110 Returns
1111 -------
1112 w : (..., M,) ndarray
1113 The eigenvalues in ascending order, each repeated according to
1114 its multiplicity.
1115
1116 Raises
1117 ------
1118 LinAlgError
1119 If the eigenvalue computation does not converge.
1120
1121 See Also
1122 --------
1123 eigh : eigenvalues and eigenvectors of real symmetric or complex Hermitian
1124 (conjugate symmetric) arrays.
1125 eigvals : eigenvalues of general real or complex arrays.
1126 eig : eigenvalues and right eigenvectors of general real or complex
1127 arrays.
1128 scipy.linalg.eigvalsh : Similar function in SciPy.
1129
1130 Notes
1131 -----
1132
1133 .. versionadded:: 1.8.0
1134
1135 Broadcasting rules apply, see the `numpy.linalg` documentation for
1136 details.
1137
1138 The eigenvalues are computed using LAPACK routines ``_syevd``, ``_heevd``.
1139
1140 Examples
1141 --------
1142 >>> from numpy import linalg as LA
1143 >>> a = np.array([[1, -2j], [2j, 5]])
1144 >>> LA.eigvalsh(a)
1145 array([ 0.17157288, 5.82842712]) # may vary
1146
1147 >>> # demonstrate the treatment of the imaginary part of the diagonal
1148 >>> a = np.array([[5+2j, 9-2j], [0+2j, 2-1j]])
1149 >>> a
1150 array([[5.+2.j, 9.-2.j],
1151 [0.+2.j, 2.-1.j]])
1152 >>> # with UPLO='L' this is numerically equivalent to using LA.eigvals()
1153 >>> # with:
1154 >>> b = np.array([[5.+0.j, 0.-2.j], [0.+2.j, 2.-0.j]])
1155 >>> b
1156 array([[5.+0.j, 0.-2.j],
1157 [0.+2.j, 2.+0.j]])
1158 >>> wa = LA.eigvalsh(a)
1159 >>> wb = LA.eigvals(b)
1160 >>> wa; wb
1161 array([1., 6.])
1162 array([6.+0.j, 1.+0.j])
1163
1164 """
1165 UPLO = UPLO.upper()
1166 if UPLO not in ('L', 'U'):
1167 raise ValueError("UPLO argument must be 'L' or 'U'")
1168
1169 extobj = get_linalg_error_extobj(
1170 _raise_linalgerror_eigenvalues_nonconvergence)
1171 if UPLO == 'L':
1172 gufunc = _umath_linalg.eigvalsh_lo
1173 else:
1174 gufunc = _umath_linalg.eigvalsh_up
1175
1176 a, wrap = _makearray(a)
1177 _assert_stacked_2d(a)
1178 _assert_stacked_square(a)
1179 t, result_t = _commonType(a)
1180 signature = 'D->d' if isComplexType(t) else 'd->d'
1181 w = gufunc(a, signature=signature, extobj=extobj)
1182 return w.astype(_realType(result_t), copy=False)
1183
1184def _convertarray(a):
1185 t, result_t = _commonType(a)
1186 a = a.astype(t).T.copy()
1187 return a, t, result_t
1188
1189
1190# Eigenvectors
1191
1192
1193@array_function_dispatch(_unary_dispatcher)
1194def eig(a):
1195 """
1196 Compute the eigenvalues and right eigenvectors of a square array.
1197
1198 Parameters
1199 ----------
1200 a : (..., M, M) array
1201 Matrices for which the eigenvalues and right eigenvectors will
1202 be computed
1203
1204 Returns
1205 -------
1206 A namedtuple with the following attributes:
1207
1208 eigenvalues : (..., M) array
1209 The eigenvalues, each repeated according to its multiplicity.
1210 The eigenvalues are not necessarily ordered. The resulting
1211 array will be of complex type, unless the imaginary part is
1212 zero in which case it will be cast to a real type. When `a`
1213 is real the resulting eigenvalues will be real (0 imaginary
1214 part) or occur in conjugate pairs
1215
1216 eigenvectors : (..., M, M) array
1217 The normalized (unit "length") eigenvectors, such that the
1218 column ``eigenvectors[:,i]`` is the eigenvector corresponding to the
1219 eigenvalue ``eigenvalues[i]``.
1220
1221 Raises
1222 ------
1223 LinAlgError
1224 If the eigenvalue computation does not converge.
1225
1226 See Also
1227 --------
1228 eigvals : eigenvalues of a non-symmetric array.
1229 eigh : eigenvalues and eigenvectors of a real symmetric or complex
1230 Hermitian (conjugate symmetric) array.
1231 eigvalsh : eigenvalues of a real symmetric or complex Hermitian
1232 (conjugate symmetric) array.
1233 scipy.linalg.eig : Similar function in SciPy that also solves the
1234 generalized eigenvalue problem.
1235 scipy.linalg.schur : Best choice for unitary and other non-Hermitian
1236 normal matrices.
1237
1238 Notes
1239 -----
1240
1241 .. versionadded:: 1.8.0
1242
1243 Broadcasting rules apply, see the `numpy.linalg` documentation for
1244 details.
1245
1246 This is implemented using the ``_geev`` LAPACK routines which compute
1247 the eigenvalues and eigenvectors of general square arrays.
1248
1249 The number `w` is an eigenvalue of `a` if there exists a vector `v` such
1250 that ``a @ v = w * v``. Thus, the arrays `a`, `eigenvalues`, and
1251 `eigenvectors` satisfy the equations ``a @ eigenvectors[:,i] =
1252 eigenvalues[i] * eigenvalues[:,i]`` for :math:`i \\in \\{0,...,M-1\\}`.
1253
1254 The array `eigenvectors` may not be of maximum rank, that is, some of the
1255 columns may be linearly dependent, although round-off error may obscure
1256 that fact. If the eigenvalues are all different, then theoretically the
1257 eigenvectors are linearly independent and `a` can be diagonalized by a
1258 similarity transformation using `eigenvectors`, i.e, ``inv(eigenvectors) @
1259 a @ eigenvectors`` is diagonal.
1260
1261 For non-Hermitian normal matrices the SciPy function `scipy.linalg.schur`
1262 is preferred because the matrix `eigenvectors` is guaranteed to be
1263 unitary, which is not the case when using `eig`. The Schur factorization
1264 produces an upper triangular matrix rather than a diagonal matrix, but for
1265 normal matrices only the diagonal of the upper triangular matrix is
1266 needed, the rest is roundoff error.
1267
1268 Finally, it is emphasized that `eigenvectors` consists of the *right* (as
1269 in right-hand side) eigenvectors of `a`. A vector `y` satisfying ``y.T @ a
1270 = z * y.T`` for some number `z` is called a *left* eigenvector of `a`,
1271 and, in general, the left and right eigenvectors of a matrix are not
1272 necessarily the (perhaps conjugate) transposes of each other.
1273
1274 References
1275 ----------
1276 G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando, FL,
1277 Academic Press, Inc., 1980, Various pp.
1278
1279 Examples
1280 --------
1281 >>> from numpy import linalg as LA
1282
1283 (Almost) trivial example with real eigenvalues and eigenvectors.
1284
1285 >>> eigenvalues, eigenvectors = LA.eig(np.diag((1, 2, 3)))
1286 >>> eigenvalues
1287 array([1., 2., 3.])
1288 >>> eigenvectors
1289 array([[1., 0., 0.],
1290 [0., 1., 0.],
1291 [0., 0., 1.]])
1292
1293 Real matrix possessing complex eigenvalues and eigenvectors; note that the
1294 eigenvalues are complex conjugates of each other.
1295
1296 >>> eigenvalues, eigenvectors = LA.eig(np.array([[1, -1], [1, 1]]))
1297 >>> eigenvalues
1298 array([1.+1.j, 1.-1.j])
1299 >>> eigenvectors
1300 array([[0.70710678+0.j , 0.70710678-0.j ],
1301 [0. -0.70710678j, 0. +0.70710678j]])
1302
1303 Complex-valued matrix with real eigenvalues (but complex-valued eigenvectors);
1304 note that ``a.conj().T == a``, i.e., `a` is Hermitian.
1305
1306 >>> a = np.array([[1, 1j], [-1j, 1]])
1307 >>> eigenvalues, eigenvectors = LA.eig(a)
1308 >>> eigenvalues
1309 array([2.+0.j, 0.+0.j])
1310 >>> eigenvectors
1311 array([[ 0. +0.70710678j, 0.70710678+0.j ], # may vary
1312 [ 0.70710678+0.j , -0. +0.70710678j]])
1313
1314 Be careful about round-off error!
1315
1316 >>> a = np.array([[1 + 1e-9, 0], [0, 1 - 1e-9]])
1317 >>> # Theor. eigenvalues are 1 +/- 1e-9
1318 >>> eigenvalues, eigenvectors = LA.eig(a)
1319 >>> eigenvalues
1320 array([1., 1.])
1321 >>> eigenvectors
1322 array([[1., 0.],
1323 [0., 1.]])
1324
1325 """
1326 a, wrap = _makearray(a)
1327 _assert_stacked_2d(a)
1328 _assert_stacked_square(a)
1329 _assert_finite(a)
1330 t, result_t = _commonType(a)
1331
1332 extobj = get_linalg_error_extobj(
1333 _raise_linalgerror_eigenvalues_nonconvergence)
1334 signature = 'D->DD' if isComplexType(t) else 'd->DD'
1335 w, vt = _umath_linalg.eig(a, signature=signature, extobj=extobj)
1336
1337 if not isComplexType(t) and all(w.imag == 0.0):
1338 w = w.real
1339 vt = vt.real
1340 result_t = _realType(result_t)
1341 else:
1342 result_t = _complexType(result_t)
1343
1344 vt = vt.astype(result_t, copy=False)
1345 return EigResult(w.astype(result_t, copy=False), wrap(vt))
1346
1347
1348@array_function_dispatch(_eigvalsh_dispatcher)
1349def eigh(a, UPLO='L'):
1350 """
1351 Return the eigenvalues and eigenvectors of a complex Hermitian
1352 (conjugate symmetric) or a real symmetric matrix.
1353
1354 Returns two objects, a 1-D array containing the eigenvalues of `a`, and
1355 a 2-D square array or matrix (depending on the input type) of the
1356 corresponding eigenvectors (in columns).
1357
1358 Parameters
1359 ----------
1360 a : (..., M, M) array
1361 Hermitian or real symmetric matrices whose eigenvalues and
1362 eigenvectors are to be computed.
1363 UPLO : {'L', 'U'}, optional
1364 Specifies whether the calculation is done with the lower triangular
1365 part of `a` ('L', default) or the upper triangular part ('U').
1366 Irrespective of this value only the real parts of the diagonal will
1367 be considered in the computation to preserve the notion of a Hermitian
1368 matrix. It therefore follows that the imaginary part of the diagonal
1369 will always be treated as zero.
1370
1371 Returns
1372 -------
1373 A namedtuple with the following attributes:
1374
1375 eigenvalues : (..., M) ndarray
1376 The eigenvalues in ascending order, each repeated according to
1377 its multiplicity.
1378 eigenvectors : {(..., M, M) ndarray, (..., M, M) matrix}
1379 The column ``eigenvectors[:, i]`` is the normalized eigenvector
1380 corresponding to the eigenvalue ``eigenvalues[i]``. Will return a
1381 matrix object if `a` is a matrix object.
1382
1383 Raises
1384 ------
1385 LinAlgError
1386 If the eigenvalue computation does not converge.
1387
1388 See Also
1389 --------
1390 eigvalsh : eigenvalues of real symmetric or complex Hermitian
1391 (conjugate symmetric) arrays.
1392 eig : eigenvalues and right eigenvectors for non-symmetric arrays.
1393 eigvals : eigenvalues of non-symmetric arrays.
1394 scipy.linalg.eigh : Similar function in SciPy (but also solves the
1395 generalized eigenvalue problem).
1396
1397 Notes
1398 -----
1399
1400 .. versionadded:: 1.8.0
1401
1402 Broadcasting rules apply, see the `numpy.linalg` documentation for
1403 details.
1404
1405 The eigenvalues/eigenvectors are computed using LAPACK routines ``_syevd``,
1406 ``_heevd``.
1407
1408 The eigenvalues of real symmetric or complex Hermitian matrices are always
1409 real. [1]_ The array `eigenvalues` of (column) eigenvectors is unitary and
1410 `a`, `eigenvalues`, and `eigenvectors` satisfy the equations ``dot(a,
1411 eigenvectors[:, i]) = eigenvalues[i] * eigenvectors[:, i]``.
1412
1413 References
1414 ----------
1415 .. [1] G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando,
1416 FL, Academic Press, Inc., 1980, pg. 222.
1417
1418 Examples
1419 --------
1420 >>> from numpy import linalg as LA
1421 >>> a = np.array([[1, -2j], [2j, 5]])
1422 >>> a
1423 array([[ 1.+0.j, -0.-2.j],
1424 [ 0.+2.j, 5.+0.j]])
1425 >>> eigenvalues, eigenvectors = LA.eigh(a)
1426 >>> eigenvalues
1427 array([0.17157288, 5.82842712])
1428 >>> eigenvectors
1429 array([[-0.92387953+0.j , -0.38268343+0.j ], # may vary
1430 [ 0. +0.38268343j, 0. -0.92387953j]])
1431
1432 >>> np.dot(a, eigenvectors[:, 0]) - eigenvalues[0] * eigenvectors[:, 0] # verify 1st eigenval/vec pair
1433 array([5.55111512e-17+0.0000000e+00j, 0.00000000e+00+1.2490009e-16j])
1434 >>> np.dot(a, eigenvectors[:, 1]) - eigenvalues[1] * eigenvectors[:, 1] # verify 2nd eigenval/vec pair
1435 array([0.+0.j, 0.+0.j])
1436
1437 >>> A = np.matrix(a) # what happens if input is a matrix object
1438 >>> A
1439 matrix([[ 1.+0.j, -0.-2.j],
1440 [ 0.+2.j, 5.+0.j]])
1441 >>> eigenvalues, eigenvectors = LA.eigh(A)
1442 >>> eigenvalues
1443 array([0.17157288, 5.82842712])
1444 >>> eigenvectors
1445 matrix([[-0.92387953+0.j , -0.38268343+0.j ], # may vary
1446 [ 0. +0.38268343j, 0. -0.92387953j]])
1447
1448 >>> # demonstrate the treatment of the imaginary part of the diagonal
1449 >>> a = np.array([[5+2j, 9-2j], [0+2j, 2-1j]])
1450 >>> a
1451 array([[5.+2.j, 9.-2.j],
1452 [0.+2.j, 2.-1.j]])
1453 >>> # with UPLO='L' this is numerically equivalent to using LA.eig() with:
1454 >>> b = np.array([[5.+0.j, 0.-2.j], [0.+2.j, 2.-0.j]])
1455 >>> b
1456 array([[5.+0.j, 0.-2.j],
1457 [0.+2.j, 2.+0.j]])
1458 >>> wa, va = LA.eigh(a)
1459 >>> wb, vb = LA.eig(b)
1460 >>> wa; wb
1461 array([1., 6.])
1462 array([6.+0.j, 1.+0.j])
1463 >>> va; vb
1464 array([[-0.4472136 +0.j , -0.89442719+0.j ], # may vary
1465 [ 0. +0.89442719j, 0. -0.4472136j ]])
1466 array([[ 0.89442719+0.j , -0. +0.4472136j],
1467 [-0. +0.4472136j, 0.89442719+0.j ]])
1468
1469 """
1470 UPLO = UPLO.upper()
1471 if UPLO not in ('L', 'U'):
1472 raise ValueError("UPLO argument must be 'L' or 'U'")
1473
1474 a, wrap = _makearray(a)
1475 _assert_stacked_2d(a)
1476 _assert_stacked_square(a)
1477 t, result_t = _commonType(a)
1478
1479 extobj = get_linalg_error_extobj(
1480 _raise_linalgerror_eigenvalues_nonconvergence)
1481 if UPLO == 'L':
1482 gufunc = _umath_linalg.eigh_lo
1483 else:
1484 gufunc = _umath_linalg.eigh_up
1485
1486 signature = 'D->dD' if isComplexType(t) else 'd->dd'
1487 w, vt = gufunc(a, signature=signature, extobj=extobj)
1488 w = w.astype(_realType(result_t), copy=False)
1489 vt = vt.astype(result_t, copy=False)
1490 return EighResult(w, wrap(vt))
1491
1492
1493# Singular value decomposition
1494
1495def _svd_dispatcher(a, full_matrices=None, compute_uv=None, hermitian=None):
1496 return (a,)
1497
1498
1499@array_function_dispatch(_svd_dispatcher)
1500def svd(a, full_matrices=True, compute_uv=True, hermitian=False):
1501 """
1502 Singular Value Decomposition.
1503
1504 When `a` is a 2D array, and ``full_matrices=False``, then it is
1505 factorized as ``u @ np.diag(s) @ vh = (u * s) @ vh``, where
1506 `u` and the Hermitian transpose of `vh` are 2D arrays with
1507 orthonormal columns and `s` is a 1D array of `a`'s singular
1508 values. When `a` is higher-dimensional, SVD is applied in
1509 stacked mode as explained below.
1510
1511 Parameters
1512 ----------
1513 a : (..., M, N) array_like
1514 A real or complex array with ``a.ndim >= 2``.
1515 full_matrices : bool, optional
1516 If True (default), `u` and `vh` have the shapes ``(..., M, M)`` and
1517 ``(..., N, N)``, respectively. Otherwise, the shapes are
1518 ``(..., M, K)`` and ``(..., K, N)``, respectively, where
1519 ``K = min(M, N)``.
1520 compute_uv : bool, optional
1521 Whether or not to compute `u` and `vh` in addition to `s`. True
1522 by default.
1523 hermitian : bool, optional
1524 If True, `a` is assumed to be Hermitian (symmetric if real-valued),
1525 enabling a more efficient method for finding singular values.
1526 Defaults to False.
1527
1528 .. versionadded:: 1.17.0
1529
1530 Returns
1531 -------
1532 When `compute_uv` is True, the result is a namedtuple with the following
1533 attribute names:
1534
1535 U : { (..., M, M), (..., M, K) } array
1536 Unitary array(s). The first ``a.ndim - 2`` dimensions have the same
1537 size as those of the input `a`. The size of the last two dimensions
1538 depends on the value of `full_matrices`. Only returned when
1539 `compute_uv` is True.
1540 S : (..., K) array
1541 Vector(s) with the singular values, within each vector sorted in
1542 descending order. The first ``a.ndim - 2`` dimensions have the same
1543 size as those of the input `a`.
1544 Vh : { (..., N, N), (..., K, N) } array
1545 Unitary array(s). The first ``a.ndim - 2`` dimensions have the same
1546 size as those of the input `a`. The size of the last two dimensions
1547 depends on the value of `full_matrices`. Only returned when
1548 `compute_uv` is True.
1549
1550 Raises
1551 ------
1552 LinAlgError
1553 If SVD computation does not converge.
1554
1555 See Also
1556 --------
1557 scipy.linalg.svd : Similar function in SciPy.
1558 scipy.linalg.svdvals : Compute singular values of a matrix.
1559
1560 Notes
1561 -----
1562
1563 .. versionchanged:: 1.8.0
1564 Broadcasting rules apply, see the `numpy.linalg` documentation for
1565 details.
1566
1567 The decomposition is performed using LAPACK routine ``_gesdd``.
1568
1569 SVD is usually described for the factorization of a 2D matrix :math:`A`.
1570 The higher-dimensional case will be discussed below. In the 2D case, SVD is
1571 written as :math:`A = U S V^H`, where :math:`A = a`, :math:`U= u`,
1572 :math:`S= \\mathtt{np.diag}(s)` and :math:`V^H = vh`. The 1D array `s`
1573 contains the singular values of `a` and `u` and `vh` are unitary. The rows
1574 of `vh` are the eigenvectors of :math:`A^H A` and the columns of `u` are
1575 the eigenvectors of :math:`A A^H`. In both cases the corresponding
1576 (possibly non-zero) eigenvalues are given by ``s**2``.
1577
1578 If `a` has more than two dimensions, then broadcasting rules apply, as
1579 explained in :ref:`routines.linalg-broadcasting`. This means that SVD is
1580 working in "stacked" mode: it iterates over all indices of the first
1581 ``a.ndim - 2`` dimensions and for each combination SVD is applied to the
1582 last two indices. The matrix `a` can be reconstructed from the
1583 decomposition with either ``(u * s[..., None, :]) @ vh`` or
1584 ``u @ (s[..., None] * vh)``. (The ``@`` operator can be replaced by the
1585 function ``np.matmul`` for python versions below 3.5.)
1586
1587 If `a` is a ``matrix`` object (as opposed to an ``ndarray``), then so are
1588 all the return values.
1589
1590 Examples
1591 --------
1592 >>> a = np.random.randn(9, 6) + 1j*np.random.randn(9, 6)
1593 >>> b = np.random.randn(2, 7, 8, 3) + 1j*np.random.randn(2, 7, 8, 3)
1594
1595 Reconstruction based on full SVD, 2D case:
1596
1597 >>> U, S, Vh = np.linalg.svd(a, full_matrices=True)
1598 >>> U.shape, S.shape, Vh.shape
1599 ((9, 9), (6,), (6, 6))
1600 >>> np.allclose(a, np.dot(U[:, :6] * S, Vh))
1601 True
1602 >>> smat = np.zeros((9, 6), dtype=complex)
1603 >>> smat[:6, :6] = np.diag(S)
1604 >>> np.allclose(a, np.dot(U, np.dot(smat, Vh)))
1605 True
1606
1607 Reconstruction based on reduced SVD, 2D case:
1608
1609 >>> U, S, Vh = np.linalg.svd(a, full_matrices=False)
1610 >>> U.shape, S.shape, Vh.shape
1611 ((9, 6), (6,), (6, 6))
1612 >>> np.allclose(a, np.dot(U * S, Vh))
1613 True
1614 >>> smat = np.diag(S)
1615 >>> np.allclose(a, np.dot(U, np.dot(smat, Vh)))
1616 True
1617
1618 Reconstruction based on full SVD, 4D case:
1619
1620 >>> U, S, Vh = np.linalg.svd(b, full_matrices=True)
1621 >>> U.shape, S.shape, Vh.shape
1622 ((2, 7, 8, 8), (2, 7, 3), (2, 7, 3, 3))
1623 >>> np.allclose(b, np.matmul(U[..., :3] * S[..., None, :], Vh))
1624 True
1625 >>> np.allclose(b, np.matmul(U[..., :3], S[..., None] * Vh))
1626 True
1627
1628 Reconstruction based on reduced SVD, 4D case:
1629
1630 >>> U, S, Vh = np.linalg.svd(b, full_matrices=False)
1631 >>> U.shape, S.shape, Vh.shape
1632 ((2, 7, 8, 3), (2, 7, 3), (2, 7, 3, 3))
1633 >>> np.allclose(b, np.matmul(U * S[..., None, :], Vh))
1634 True
1635 >>> np.allclose(b, np.matmul(U, S[..., None] * Vh))
1636 True
1637
1638 """
1639 import numpy as _nx
1640 a, wrap = _makearray(a)
1641
1642 if hermitian:
1643 # note: lapack svd returns eigenvalues with s ** 2 sorted descending,
1644 # but eig returns s sorted ascending, so we re-order the eigenvalues
1645 # and related arrays to have the correct order
1646 if compute_uv:
1647 s, u = eigh(a)
1648 sgn = sign(s)
1649 s = abs(s)
1650 sidx = argsort(s)[..., ::-1]
1651 sgn = _nx.take_along_axis(sgn, sidx, axis=-1)
1652 s = _nx.take_along_axis(s, sidx, axis=-1)
1653 u = _nx.take_along_axis(u, sidx[..., None, :], axis=-1)
1654 # singular values are unsigned, move the sign into v
1655 vt = transpose(u * sgn[..., None, :]).conjugate()
1656 return SVDResult(wrap(u), s, wrap(vt))
1657 else:
1658 s = eigvalsh(a)
1659 s = abs(s)
1660 return sort(s)[..., ::-1]
1661
1662 _assert_stacked_2d(a)
1663 t, result_t = _commonType(a)
1664
1665 extobj = get_linalg_error_extobj(_raise_linalgerror_svd_nonconvergence)
1666
1667 m, n = a.shape[-2:]
1668 if compute_uv:
1669 if full_matrices:
1670 if m < n:
1671 gufunc = _umath_linalg.svd_m_f
1672 else:
1673 gufunc = _umath_linalg.svd_n_f
1674 else:
1675 if m < n:
1676 gufunc = _umath_linalg.svd_m_s
1677 else:
1678 gufunc = _umath_linalg.svd_n_s
1679
1680 signature = 'D->DdD' if isComplexType(t) else 'd->ddd'
1681 u, s, vh = gufunc(a, signature=signature, extobj=extobj)
1682 u = u.astype(result_t, copy=False)
1683 s = s.astype(_realType(result_t), copy=False)
1684 vh = vh.astype(result_t, copy=False)
1685 return SVDResult(wrap(u), s, wrap(vh))
1686 else:
1687 if m < n:
1688 gufunc = _umath_linalg.svd_m
1689 else:
1690 gufunc = _umath_linalg.svd_n
1691
1692 signature = 'D->d' if isComplexType(t) else 'd->d'
1693 s = gufunc(a, signature=signature, extobj=extobj)
1694 s = s.astype(_realType(result_t), copy=False)
1695 return s
1696
1697
1698def _cond_dispatcher(x, p=None):
1699 return (x,)
1700
1701
1702@array_function_dispatch(_cond_dispatcher)
1703def cond(x, p=None):
1704 """
1705 Compute the condition number of a matrix.
1706
1707 This function is capable of returning the condition number using
1708 one of seven different norms, depending on the value of `p` (see
1709 Parameters below).
1710
1711 Parameters
1712 ----------
1713 x : (..., M, N) array_like
1714 The matrix whose condition number is sought.
1715 p : {None, 1, -1, 2, -2, inf, -inf, 'fro'}, optional
1716 Order of the norm used in the condition number computation:
1717
1718 ===== ============================
1719 p norm for matrices
1720 ===== ============================
1721 None 2-norm, computed directly using the ``SVD``
1722 'fro' Frobenius norm
1723 inf max(sum(abs(x), axis=1))
1724 -inf min(sum(abs(x), axis=1))
1725 1 max(sum(abs(x), axis=0))
1726 -1 min(sum(abs(x), axis=0))
1727 2 2-norm (largest sing. value)
1728 -2 smallest singular value
1729 ===== ============================
1730
1731 inf means the `numpy.inf` object, and the Frobenius norm is
1732 the root-of-sum-of-squares norm.
1733
1734 Returns
1735 -------
1736 c : {float, inf}
1737 The condition number of the matrix. May be infinite.
1738
1739 See Also
1740 --------
1741 numpy.linalg.norm
1742
1743 Notes
1744 -----
1745 The condition number of `x` is defined as the norm of `x` times the
1746 norm of the inverse of `x` [1]_; the norm can be the usual L2-norm
1747 (root-of-sum-of-squares) or one of a number of other matrix norms.
1748
1749 References
1750 ----------
1751 .. [1] G. Strang, *Linear Algebra and Its Applications*, Orlando, FL,
1752 Academic Press, Inc., 1980, pg. 285.
1753
1754 Examples
1755 --------
1756 >>> from numpy import linalg as LA
1757 >>> a = np.array([[1, 0, -1], [0, 1, 0], [1, 0, 1]])
1758 >>> a
1759 array([[ 1, 0, -1],
1760 [ 0, 1, 0],
1761 [ 1, 0, 1]])
1762 >>> LA.cond(a)
1763 1.4142135623730951
1764 >>> LA.cond(a, 'fro')
1765 3.1622776601683795
1766 >>> LA.cond(a, np.inf)
1767 2.0
1768 >>> LA.cond(a, -np.inf)
1769 1.0
1770 >>> LA.cond(a, 1)
1771 2.0
1772 >>> LA.cond(a, -1)
1773 1.0
1774 >>> LA.cond(a, 2)
1775 1.4142135623730951
1776 >>> LA.cond(a, -2)
1777 0.70710678118654746 # may vary
1778 >>> min(LA.svd(a, compute_uv=False))*min(LA.svd(LA.inv(a), compute_uv=False))
1779 0.70710678118654746 # may vary
1780
1781 """
1782 x = asarray(x) # in case we have a matrix
1783 if _is_empty_2d(x):
1784 raise LinAlgError("cond is not defined on empty arrays")
1785 if p is None or p == 2 or p == -2:
1786 s = svd(x, compute_uv=False)
1787 with errstate(all='ignore'):
1788 if p == -2:
1789 r = s[..., -1] / s[..., 0]
1790 else:
1791 r = s[..., 0] / s[..., -1]
1792 else:
1793 # Call inv(x) ignoring errors. The result array will
1794 # contain nans in the entries where inversion failed.
1795 _assert_stacked_2d(x)
1796 _assert_stacked_square(x)
1797 t, result_t = _commonType(x)
1798 signature = 'D->D' if isComplexType(t) else 'd->d'
1799 with errstate(all='ignore'):
1800 invx = _umath_linalg.inv(x, signature=signature)
1801 r = norm(x, p, axis=(-2, -1)) * norm(invx, p, axis=(-2, -1))
1802 r = r.astype(result_t, copy=False)
1803
1804 # Convert nans to infs unless the original array had nan entries
1805 r = asarray(r)
1806 nan_mask = isnan(r)
1807 if nan_mask.any():
1808 nan_mask &= ~isnan(x).any(axis=(-2, -1))
1809 if r.ndim > 0:
1810 r[nan_mask] = Inf
1811 elif nan_mask:
1812 r[()] = Inf
1813
1814 # Convention is to return scalars instead of 0d arrays
1815 if r.ndim == 0:
1816 r = r[()]
1817
1818 return r
1819
1820
1821def _matrix_rank_dispatcher(A, tol=None, hermitian=None):
1822 return (A,)
1823
1824
1825@array_function_dispatch(_matrix_rank_dispatcher)
1826def matrix_rank(A, tol=None, hermitian=False):
1827 """
1828 Return matrix rank of array using SVD method
1829
1830 Rank of the array is the number of singular values of the array that are
1831 greater than `tol`.
1832
1833 .. versionchanged:: 1.14
1834 Can now operate on stacks of matrices
1835
1836 Parameters
1837 ----------
1838 A : {(M,), (..., M, N)} array_like
1839 Input vector or stack of matrices.
1840 tol : (...) array_like, float, optional
1841 Threshold below which SVD values are considered zero. If `tol` is
1842 None, and ``S`` is an array with singular values for `M`, and
1843 ``eps`` is the epsilon value for datatype of ``S``, then `tol` is
1844 set to ``S.max() * max(M, N) * eps``.
1845
1846 .. versionchanged:: 1.14
1847 Broadcasted against the stack of matrices
1848 hermitian : bool, optional
1849 If True, `A` is assumed to be Hermitian (symmetric if real-valued),
1850 enabling a more efficient method for finding singular values.
1851 Defaults to False.
1852
1853 .. versionadded:: 1.14
1854
1855 Returns
1856 -------
1857 rank : (...) array_like
1858 Rank of A.
1859
1860 Notes
1861 -----
1862 The default threshold to detect rank deficiency is a test on the magnitude
1863 of the singular values of `A`. By default, we identify singular values less
1864 than ``S.max() * max(M, N) * eps`` as indicating rank deficiency (with
1865 the symbols defined above). This is the algorithm MATLAB uses [1]. It also
1866 appears in *Numerical recipes* in the discussion of SVD solutions for linear
1867 least squares [2].
1868
1869 This default threshold is designed to detect rank deficiency accounting for
1870 the numerical errors of the SVD computation. Imagine that there is a column
1871 in `A` that is an exact (in floating point) linear combination of other
1872 columns in `A`. Computing the SVD on `A` will not produce a singular value
1873 exactly equal to 0 in general: any difference of the smallest SVD value from
1874 0 will be caused by numerical imprecision in the calculation of the SVD.
1875 Our threshold for small SVD values takes this numerical imprecision into
1876 account, and the default threshold will detect such numerical rank
1877 deficiency. The threshold may declare a matrix `A` rank deficient even if
1878 the linear combination of some columns of `A` is not exactly equal to
1879 another column of `A` but only numerically very close to another column of
1880 `A`.
1881
1882 We chose our default threshold because it is in wide use. Other thresholds
1883 are possible. For example, elsewhere in the 2007 edition of *Numerical
1884 recipes* there is an alternative threshold of ``S.max() *
1885 np.finfo(A.dtype).eps / 2. * np.sqrt(m + n + 1.)``. The authors describe
1886 this threshold as being based on "expected roundoff error" (p 71).
1887
1888 The thresholds above deal with floating point roundoff error in the
1889 calculation of the SVD. However, you may have more information about the
1890 sources of error in `A` that would make you consider other tolerance values
1891 to detect *effective* rank deficiency. The most useful measure of the
1892 tolerance depends on the operations you intend to use on your matrix. For
1893 example, if your data come from uncertain measurements with uncertainties
1894 greater than floating point epsilon, choosing a tolerance near that
1895 uncertainty may be preferable. The tolerance may be absolute if the
1896 uncertainties are absolute rather than relative.
1897
1898 References
1899 ----------
1900 .. [1] MATLAB reference documentation, "Rank"
1901 https://www.mathworks.com/help/techdoc/ref/rank.html
1902 .. [2] W. H. Press, S. A. Teukolsky, W. T. Vetterling and B. P. Flannery,
1903 "Numerical Recipes (3rd edition)", Cambridge University Press, 2007,
1904 page 795.
1905
1906 Examples
1907 --------
1908 >>> from numpy.linalg import matrix_rank
1909 >>> matrix_rank(np.eye(4)) # Full rank matrix
1910 4
1911 >>> I=np.eye(4); I[-1,-1] = 0. # rank deficient matrix
1912 >>> matrix_rank(I)
1913 3
1914 >>> matrix_rank(np.ones((4,))) # 1 dimension - rank 1 unless all 0
1915 1
1916 >>> matrix_rank(np.zeros((4,)))
1917 0
1918 """
1919 A = asarray(A)
1920 if A.ndim < 2:
1921 return int(not all(A==0))
1922 S = svd(A, compute_uv=False, hermitian=hermitian)
1923 if tol is None:
1924 tol = S.max(axis=-1, keepdims=True) * max(A.shape[-2:]) * finfo(S.dtype).eps
1925 else:
1926 tol = asarray(tol)[..., newaxis]
1927 return count_nonzero(S > tol, axis=-1)
1928
1929
1930# Generalized inverse
1931
1932def _pinv_dispatcher(a, rcond=None, hermitian=None):
1933 return (a,)
1934
1935
1936@array_function_dispatch(_pinv_dispatcher)
1937def pinv(a, rcond=1e-15, hermitian=False):
1938 """
1939 Compute the (Moore-Penrose) pseudo-inverse of a matrix.
1940
1941 Calculate the generalized inverse of a matrix using its
1942 singular-value decomposition (SVD) and including all
1943 *large* singular values.
1944
1945 .. versionchanged:: 1.14
1946 Can now operate on stacks of matrices
1947
1948 Parameters
1949 ----------
1950 a : (..., M, N) array_like
1951 Matrix or stack of matrices to be pseudo-inverted.
1952 rcond : (...) array_like of float
1953 Cutoff for small singular values.
1954 Singular values less than or equal to
1955 ``rcond * largest_singular_value`` are set to zero.
1956 Broadcasts against the stack of matrices.
1957 hermitian : bool, optional
1958 If True, `a` is assumed to be Hermitian (symmetric if real-valued),
1959 enabling a more efficient method for finding singular values.
1960 Defaults to False.
1961
1962 .. versionadded:: 1.17.0
1963
1964 Returns
1965 -------
1966 B : (..., N, M) ndarray
1967 The pseudo-inverse of `a`. If `a` is a `matrix` instance, then so
1968 is `B`.
1969
1970 Raises
1971 ------
1972 LinAlgError
1973 If the SVD computation does not converge.
1974
1975 See Also
1976 --------
1977 scipy.linalg.pinv : Similar function in SciPy.
1978 scipy.linalg.pinvh : Compute the (Moore-Penrose) pseudo-inverse of a
1979 Hermitian matrix.
1980
1981 Notes
1982 -----
1983 The pseudo-inverse of a matrix A, denoted :math:`A^+`, is
1984 defined as: "the matrix that 'solves' [the least-squares problem]
1985 :math:`Ax = b`," i.e., if :math:`\\bar{x}` is said solution, then
1986 :math:`A^+` is that matrix such that :math:`\\bar{x} = A^+b`.
1987
1988 It can be shown that if :math:`Q_1 \\Sigma Q_2^T = A` is the singular
1989 value decomposition of A, then
1990 :math:`A^+ = Q_2 \\Sigma^+ Q_1^T`, where :math:`Q_{1,2}` are
1991 orthogonal matrices, :math:`\\Sigma` is a diagonal matrix consisting
1992 of A's so-called singular values, (followed, typically, by
1993 zeros), and then :math:`\\Sigma^+` is simply the diagonal matrix
1994 consisting of the reciprocals of A's singular values
1995 (again, followed by zeros). [1]_
1996
1997 References
1998 ----------
1999 .. [1] G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando,
2000 FL, Academic Press, Inc., 1980, pp. 139-142.
2001
2002 Examples
2003 --------
2004 The following example checks that ``a * a+ * a == a`` and
2005 ``a+ * a * a+ == a+``:
2006
2007 >>> a = np.random.randn(9, 6)
2008 >>> B = np.linalg.pinv(a)
2009 >>> np.allclose(a, np.dot(a, np.dot(B, a)))
2010 True
2011 >>> np.allclose(B, np.dot(B, np.dot(a, B)))
2012 True
2013
2014 """
2015 a, wrap = _makearray(a)
2016 rcond = asarray(rcond)
2017 if _is_empty_2d(a):
2018 m, n = a.shape[-2:]
2019 res = empty(a.shape[:-2] + (n, m), dtype=a.dtype)
2020 return wrap(res)
2021 a = a.conjugate()
2022 u, s, vt = svd(a, full_matrices=False, hermitian=hermitian)
2023
2024 # discard small singular values
2025 cutoff = rcond[..., newaxis] * amax(s, axis=-1, keepdims=True)
2026 large = s > cutoff
2027 s = divide(1, s, where=large, out=s)
2028 s[~large] = 0
2029
2030 res = matmul(transpose(vt), multiply(s[..., newaxis], transpose(u)))
2031 return wrap(res)
2032
2033
2034# Determinant
2035
2036
2037@array_function_dispatch(_unary_dispatcher)
2038def slogdet(a):
2039 """
2040 Compute the sign and (natural) logarithm of the determinant of an array.
2041
2042 If an array has a very small or very large determinant, then a call to
2043 `det` may overflow or underflow. This routine is more robust against such
2044 issues, because it computes the logarithm of the determinant rather than
2045 the determinant itself.
2046
2047 Parameters
2048 ----------
2049 a : (..., M, M) array_like
2050 Input array, has to be a square 2-D array.
2051
2052 Returns
2053 -------
2054 A namedtuple with the following attributes:
2055
2056 sign : (...) array_like
2057 A number representing the sign of the determinant. For a real matrix,
2058 this is 1, 0, or -1. For a complex matrix, this is a complex number
2059 with absolute value 1 (i.e., it is on the unit circle), or else 0.
2060 logabsdet : (...) array_like
2061 The natural log of the absolute value of the determinant.
2062
2063 If the determinant is zero, then `sign` will be 0 and `logabsdet` will be
2064 -Inf. In all cases, the determinant is equal to ``sign * np.exp(logabsdet)``.
2065
2066 See Also
2067 --------
2068 det
2069
2070 Notes
2071 -----
2072
2073 .. versionadded:: 1.8.0
2074
2075 Broadcasting rules apply, see the `numpy.linalg` documentation for
2076 details.
2077
2078 .. versionadded:: 1.6.0
2079
2080 The determinant is computed via LU factorization using the LAPACK
2081 routine ``z/dgetrf``.
2082
2083
2084 Examples
2085 --------
2086 The determinant of a 2-D array ``[[a, b], [c, d]]`` is ``ad - bc``:
2087
2088 >>> a = np.array([[1, 2], [3, 4]])
2089 >>> (sign, logabsdet) = np.linalg.slogdet(a)
2090 >>> (sign, logabsdet)
2091 (-1, 0.69314718055994529) # may vary
2092 >>> sign * np.exp(logabsdet)
2093 -2.0
2094
2095 Computing log-determinants for a stack of matrices:
2096
2097 >>> a = np.array([ [[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]] ])
2098 >>> a.shape
2099 (3, 2, 2)
2100 >>> sign, logabsdet = np.linalg.slogdet(a)
2101 >>> (sign, logabsdet)
2102 (array([-1., -1., -1.]), array([ 0.69314718, 1.09861229, 2.07944154]))
2103 >>> sign * np.exp(logabsdet)
2104 array([-2., -3., -8.])
2105
2106 This routine succeeds where ordinary `det` does not:
2107
2108 >>> np.linalg.det(np.eye(500) * 0.1)
2109 0.0
2110 >>> np.linalg.slogdet(np.eye(500) * 0.1)
2111 (1, -1151.2925464970228)
2112
2113 """
2114 a = asarray(a)
2115 _assert_stacked_2d(a)
2116 _assert_stacked_square(a)
2117 t, result_t = _commonType(a)
2118 real_t = _realType(result_t)
2119 signature = 'D->Dd' if isComplexType(t) else 'd->dd'
2120 sign, logdet = _umath_linalg.slogdet(a, signature=signature)
2121 sign = sign.astype(result_t, copy=False)
2122 logdet = logdet.astype(real_t, copy=False)
2123 return SlogdetResult(sign, logdet)
2124
2125
2126@array_function_dispatch(_unary_dispatcher)
2127def det(a):
2128 """
2129 Compute the determinant of an array.
2130
2131 Parameters
2132 ----------
2133 a : (..., M, M) array_like
2134 Input array to compute determinants for.
2135
2136 Returns
2137 -------
2138 det : (...) array_like
2139 Determinant of `a`.
2140
2141 See Also
2142 --------
2143 slogdet : Another way to represent the determinant, more suitable
2144 for large matrices where underflow/overflow may occur.
2145 scipy.linalg.det : Similar function in SciPy.
2146
2147 Notes
2148 -----
2149
2150 .. versionadded:: 1.8.0
2151
2152 Broadcasting rules apply, see the `numpy.linalg` documentation for
2153 details.
2154
2155 The determinant is computed via LU factorization using the LAPACK
2156 routine ``z/dgetrf``.
2157
2158 Examples
2159 --------
2160 The determinant of a 2-D array [[a, b], [c, d]] is ad - bc:
2161
2162 >>> a = np.array([[1, 2], [3, 4]])
2163 >>> np.linalg.det(a)
2164 -2.0 # may vary
2165
2166 Computing determinants for a stack of matrices:
2167
2168 >>> a = np.array([ [[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]] ])
2169 >>> a.shape
2170 (3, 2, 2)
2171 >>> np.linalg.det(a)
2172 array([-2., -3., -8.])
2173
2174 """
2175 a = asarray(a)
2176 _assert_stacked_2d(a)
2177 _assert_stacked_square(a)
2178 t, result_t = _commonType(a)
2179 signature = 'D->D' if isComplexType(t) else 'd->d'
2180 r = _umath_linalg.det(a, signature=signature)
2181 r = r.astype(result_t, copy=False)
2182 return r
2183
2184
2185# Linear Least Squares
2186
2187def _lstsq_dispatcher(a, b, rcond=None):
2188 return (a, b)
2189
2190
2191@array_function_dispatch(_lstsq_dispatcher)
2192def lstsq(a, b, rcond="warn"):
2193 r"""
2194 Return the least-squares solution to a linear matrix equation.
2195
2196 Computes the vector `x` that approximately solves the equation
2197 ``a @ x = b``. The equation may be under-, well-, or over-determined
2198 (i.e., the number of linearly independent rows of `a` can be less than,
2199 equal to, or greater than its number of linearly independent columns).
2200 If `a` is square and of full rank, then `x` (but for round-off error)
2201 is the "exact" solution of the equation. Else, `x` minimizes the
2202 Euclidean 2-norm :math:`||b - ax||`. If there are multiple minimizing
2203 solutions, the one with the smallest 2-norm :math:`||x||` is returned.
2204
2205 Parameters
2206 ----------
2207 a : (M, N) array_like
2208 "Coefficient" matrix.
2209 b : {(M,), (M, K)} array_like
2210 Ordinate or "dependent variable" values. If `b` is two-dimensional,
2211 the least-squares solution is calculated for each of the `K` columns
2212 of `b`.
2213 rcond : float, optional
2214 Cut-off ratio for small singular values of `a`.
2215 For the purposes of rank determination, singular values are treated
2216 as zero if they are smaller than `rcond` times the largest singular
2217 value of `a`.
2218
2219 .. versionchanged:: 1.14.0
2220 If not set, a FutureWarning is given. The previous default
2221 of ``-1`` will use the machine precision as `rcond` parameter,
2222 the new default will use the machine precision times `max(M, N)`.
2223 To silence the warning and use the new default, use ``rcond=None``,
2224 to keep using the old behavior, use ``rcond=-1``.
2225
2226 Returns
2227 -------
2228 x : {(N,), (N, K)} ndarray
2229 Least-squares solution. If `b` is two-dimensional,
2230 the solutions are in the `K` columns of `x`.
2231 residuals : {(1,), (K,), (0,)} ndarray
2232 Sums of squared residuals: Squared Euclidean 2-norm for each column in
2233 ``b - a @ x``.
2234 If the rank of `a` is < N or M <= N, this is an empty array.
2235 If `b` is 1-dimensional, this is a (1,) shape array.
2236 Otherwise the shape is (K,).
2237 rank : int
2238 Rank of matrix `a`.
2239 s : (min(M, N),) ndarray
2240 Singular values of `a`.
2241
2242 Raises
2243 ------
2244 LinAlgError
2245 If computation does not converge.
2246
2247 See Also
2248 --------
2249 scipy.linalg.lstsq : Similar function in SciPy.
2250
2251 Notes
2252 -----
2253 If `b` is a matrix, then all array results are returned as matrices.
2254
2255 Examples
2256 --------
2257 Fit a line, ``y = mx + c``, through some noisy data-points:
2258
2259 >>> x = np.array([0, 1, 2, 3])
2260 >>> y = np.array([-1, 0.2, 0.9, 2.1])
2261
2262 By examining the coefficients, we see that the line should have a
2263 gradient of roughly 1 and cut the y-axis at, more or less, -1.
2264
2265 We can rewrite the line equation as ``y = Ap``, where ``A = [[x 1]]``
2266 and ``p = [[m], [c]]``. Now use `lstsq` to solve for `p`:
2267
2268 >>> A = np.vstack([x, np.ones(len(x))]).T
2269 >>> A
2270 array([[ 0., 1.],
2271 [ 1., 1.],
2272 [ 2., 1.],
2273 [ 3., 1.]])
2274
2275 >>> m, c = np.linalg.lstsq(A, y, rcond=None)[0]
2276 >>> m, c
2277 (1.0 -0.95) # may vary
2278
2279 Plot the data along with the fitted line:
2280
2281 >>> import matplotlib.pyplot as plt
2282 >>> _ = plt.plot(x, y, 'o', label='Original data', markersize=10)
2283 >>> _ = plt.plot(x, m*x + c, 'r', label='Fitted line')
2284 >>> _ = plt.legend()
2285 >>> plt.show()
2286
2287 """
2288 a, _ = _makearray(a)
2289 b, wrap = _makearray(b)
2290 is_1d = b.ndim == 1
2291 if is_1d:
2292 b = b[:, newaxis]
2293 _assert_2d(a, b)
2294 m, n = a.shape[-2:]
2295 m2, n_rhs = b.shape[-2:]
2296 if m != m2:
2297 raise LinAlgError('Incompatible dimensions')
2298
2299 t, result_t = _commonType(a, b)
2300 result_real_t = _realType(result_t)
2301
2302 # Determine default rcond value
2303 if rcond == "warn":
2304 # 2017-08-19, 1.14.0
2305 warnings.warn("`rcond` parameter will change to the default of "
2306 "machine precision times ``max(M, N)`` where M and N "
2307 "are the input matrix dimensions.\n"
2308 "To use the future default and silence this warning "
2309 "we advise to pass `rcond=None`, to keep using the old, "
2310 "explicitly pass `rcond=-1`.",
2311 FutureWarning, stacklevel=2)
2312 rcond = -1
2313 if rcond is None:
2314 rcond = finfo(t).eps * max(n, m)
2315
2316 if m <= n:
2317 gufunc = _umath_linalg.lstsq_m
2318 else:
2319 gufunc = _umath_linalg.lstsq_n
2320
2321 signature = 'DDd->Ddid' if isComplexType(t) else 'ddd->ddid'
2322 extobj = get_linalg_error_extobj(_raise_linalgerror_lstsq)
2323 if n_rhs == 0:
2324 # lapack can't handle n_rhs = 0 - so allocate the array one larger in that axis
2325 b = zeros(b.shape[:-2] + (m, n_rhs + 1), dtype=b.dtype)
2326 x, resids, rank, s = gufunc(a, b, rcond, signature=signature, extobj=extobj)
2327 if m == 0:
2328 x[...] = 0
2329 if n_rhs == 0:
2330 # remove the item we added
2331 x = x[..., :n_rhs]
2332 resids = resids[..., :n_rhs]
2333
2334 # remove the axis we added
2335 if is_1d:
2336 x = x.squeeze(axis=-1)
2337 # we probably should squeeze resids too, but we can't
2338 # without breaking compatibility.
2339
2340 # as documented
2341 if rank != n or m <= n:
2342 resids = array([], result_real_t)
2343
2344 # coerce output arrays
2345 s = s.astype(result_real_t, copy=False)
2346 resids = resids.astype(result_real_t, copy=False)
2347 x = x.astype(result_t, copy=True) # Copying lets the memory in r_parts be freed
2348 return wrap(x), wrap(resids), rank, s
2349
2350
2351def _multi_svd_norm(x, row_axis, col_axis, op):
2352 """Compute a function of the singular values of the 2-D matrices in `x`.
2353
2354 This is a private utility function used by `numpy.linalg.norm()`.
2355
2356 Parameters
2357 ----------
2358 x : ndarray
2359 row_axis, col_axis : int
2360 The axes of `x` that hold the 2-D matrices.
2361 op : callable
2362 This should be either numpy.amin or `numpy.amax` or `numpy.sum`.
2363
2364 Returns
2365 -------
2366 result : float or ndarray
2367 If `x` is 2-D, the return values is a float.
2368 Otherwise, it is an array with ``x.ndim - 2`` dimensions.
2369 The return values are either the minimum or maximum or sum of the
2370 singular values of the matrices, depending on whether `op`
2371 is `numpy.amin` or `numpy.amax` or `numpy.sum`.
2372
2373 """
2374 y = moveaxis(x, (row_axis, col_axis), (-2, -1))
2375 result = op(svd(y, compute_uv=False), axis=-1)
2376 return result
2377
2378
2379def _norm_dispatcher(x, ord=None, axis=None, keepdims=None):
2380 return (x,)
2381
2382
2383@array_function_dispatch(_norm_dispatcher)
2384def norm(x, ord=None, axis=None, keepdims=False):
2385 """
2386 Matrix or vector norm.
2387
2388 This function is able to return one of eight different matrix norms,
2389 or one of an infinite number of vector norms (described below), depending
2390 on the value of the ``ord`` parameter.
2391
2392 Parameters
2393 ----------
2394 x : array_like
2395 Input array. If `axis` is None, `x` must be 1-D or 2-D, unless `ord`
2396 is None. If both `axis` and `ord` are None, the 2-norm of
2397 ``x.ravel`` will be returned.
2398 ord : {non-zero int, inf, -inf, 'fro', 'nuc'}, optional
2399 Order of the norm (see table under ``Notes``). inf means numpy's
2400 `inf` object. The default is None.
2401 axis : {None, int, 2-tuple of ints}, optional.
2402 If `axis` is an integer, it specifies the axis of `x` along which to
2403 compute the vector norms. If `axis` is a 2-tuple, it specifies the
2404 axes that hold 2-D matrices, and the matrix norms of these matrices
2405 are computed. If `axis` is None then either a vector norm (when `x`
2406 is 1-D) or a matrix norm (when `x` is 2-D) is returned. The default
2407 is None.
2408
2409 .. versionadded:: 1.8.0
2410
2411 keepdims : bool, optional
2412 If this is set to True, the axes which are normed over are left in the
2413 result as dimensions with size one. With this option the result will
2414 broadcast correctly against the original `x`.
2415
2416 .. versionadded:: 1.10.0
2417
2418 Returns
2419 -------
2420 n : float or ndarray
2421 Norm of the matrix or vector(s).
2422
2423 See Also
2424 --------
2425 scipy.linalg.norm : Similar function in SciPy.
2426
2427 Notes
2428 -----
2429 For values of ``ord < 1``, the result is, strictly speaking, not a
2430 mathematical 'norm', but it may still be useful for various numerical
2431 purposes.
2432
2433 The following norms can be calculated:
2434
2435 ===== ============================ ==========================
2436 ord norm for matrices norm for vectors
2437 ===== ============================ ==========================
2438 None Frobenius norm 2-norm
2439 'fro' Frobenius norm --
2440 'nuc' nuclear norm --
2441 inf max(sum(abs(x), axis=1)) max(abs(x))
2442 -inf min(sum(abs(x), axis=1)) min(abs(x))
2443 0 -- sum(x != 0)
2444 1 max(sum(abs(x), axis=0)) as below
2445 -1 min(sum(abs(x), axis=0)) as below
2446 2 2-norm (largest sing. value) as below
2447 -2 smallest singular value as below
2448 other -- sum(abs(x)**ord)**(1./ord)
2449 ===== ============================ ==========================
2450
2451 The Frobenius norm is given by [1]_:
2452
2453 :math:`||A||_F = [\\sum_{i,j} abs(a_{i,j})^2]^{1/2}`
2454
2455 The nuclear norm is the sum of the singular values.
2456
2457 Both the Frobenius and nuclear norm orders are only defined for
2458 matrices and raise a ValueError when ``x.ndim != 2``.
2459
2460 References
2461 ----------
2462 .. [1] G. H. Golub and C. F. Van Loan, *Matrix Computations*,
2463 Baltimore, MD, Johns Hopkins University Press, 1985, pg. 15
2464
2465 Examples
2466 --------
2467 >>> from numpy import linalg as LA
2468 >>> a = np.arange(9) - 4
2469 >>> a
2470 array([-4, -3, -2, ..., 2, 3, 4])
2471 >>> b = a.reshape((3, 3))
2472 >>> b
2473 array([[-4, -3, -2],
2474 [-1, 0, 1],
2475 [ 2, 3, 4]])
2476
2477 >>> LA.norm(a)
2478 7.745966692414834
2479 >>> LA.norm(b)
2480 7.745966692414834
2481 >>> LA.norm(b, 'fro')
2482 7.745966692414834
2483 >>> LA.norm(a, np.inf)
2484 4.0
2485 >>> LA.norm(b, np.inf)
2486 9.0
2487 >>> LA.norm(a, -np.inf)
2488 0.0
2489 >>> LA.norm(b, -np.inf)
2490 2.0
2491
2492 >>> LA.norm(a, 1)
2493 20.0
2494 >>> LA.norm(b, 1)
2495 7.0
2496 >>> LA.norm(a, -1)
2497 -4.6566128774142013e-010
2498 >>> LA.norm(b, -1)
2499 6.0
2500 >>> LA.norm(a, 2)
2501 7.745966692414834
2502 >>> LA.norm(b, 2)
2503 7.3484692283495345
2504
2505 >>> LA.norm(a, -2)
2506 0.0
2507 >>> LA.norm(b, -2)
2508 1.8570331885190563e-016 # may vary
2509 >>> LA.norm(a, 3)
2510 5.8480354764257312 # may vary
2511 >>> LA.norm(a, -3)
2512 0.0
2513
2514 Using the `axis` argument to compute vector norms:
2515
2516 >>> c = np.array([[ 1, 2, 3],
2517 ... [-1, 1, 4]])
2518 >>> LA.norm(c, axis=0)
2519 array([ 1.41421356, 2.23606798, 5. ])
2520 >>> LA.norm(c, axis=1)
2521 array([ 3.74165739, 4.24264069])
2522 >>> LA.norm(c, ord=1, axis=1)
2523 array([ 6., 6.])
2524
2525 Using the `axis` argument to compute matrix norms:
2526
2527 >>> m = np.arange(8).reshape(2,2,2)
2528 >>> LA.norm(m, axis=(1,2))
2529 array([ 3.74165739, 11.22497216])
2530 >>> LA.norm(m[0, :, :]), LA.norm(m[1, :, :])
2531 (3.7416573867739413, 11.224972160321824)
2532
2533 """
2534 x = asarray(x)
2535
2536 if not issubclass(x.dtype.type, (inexact, object_)):
2537 x = x.astype(float)
2538
2539 # Immediately handle some default, simple, fast, and common cases.
2540 if axis is None:
2541 ndim = x.ndim
2542 if ((ord is None) or
2543 (ord in ('f', 'fro') and ndim == 2) or
2544 (ord == 2 and ndim == 1)):
2545
2546 x = x.ravel(order='K')
2547 if isComplexType(x.dtype.type):
2548 x_real = x.real
2549 x_imag = x.imag
2550 sqnorm = x_real.dot(x_real) + x_imag.dot(x_imag)
2551 else:
2552 sqnorm = x.dot(x)
2553 ret = sqrt(sqnorm)
2554 if keepdims:
2555 ret = ret.reshape(ndim*[1])
2556 return ret
2557
2558 # Normalize the `axis` argument to a tuple.
2559 nd = x.ndim
2560 if axis is None:
2561 axis = tuple(range(nd))
2562 elif not isinstance(axis, tuple):
2563 try:
2564 axis = int(axis)
2565 except Exception as e:
2566 raise TypeError("'axis' must be None, an integer or a tuple of integers") from e
2567 axis = (axis,)
2568
2569 if len(axis) == 1:
2570 if ord == Inf:
2571 return abs(x).max(axis=axis, keepdims=keepdims)
2572 elif ord == -Inf:
2573 return abs(x).min(axis=axis, keepdims=keepdims)
2574 elif ord == 0:
2575 # Zero norm
2576 return (x != 0).astype(x.real.dtype).sum(axis=axis, keepdims=keepdims)
2577 elif ord == 1:
2578 # special case for speedup
2579 return add.reduce(abs(x), axis=axis, keepdims=keepdims)
2580 elif ord is None or ord == 2:
2581 # special case for speedup
2582 s = (x.conj() * x).real
2583 return sqrt(add.reduce(s, axis=axis, keepdims=keepdims))
2584 # None of the str-type keywords for ord ('fro', 'nuc')
2585 # are valid for vectors
2586 elif isinstance(ord, str):
2587 raise ValueError(f"Invalid norm order '{ord}' for vectors")
2588 else:
2589 absx = abs(x)
2590 absx **= ord
2591 ret = add.reduce(absx, axis=axis, keepdims=keepdims)
2592 ret **= reciprocal(ord, dtype=ret.dtype)
2593 return ret
2594 elif len(axis) == 2:
2595 row_axis, col_axis = axis
2596 row_axis = normalize_axis_index(row_axis, nd)
2597 col_axis = normalize_axis_index(col_axis, nd)
2598 if row_axis == col_axis:
2599 raise ValueError('Duplicate axes given.')
2600 if ord == 2:
2601 ret = _multi_svd_norm(x, row_axis, col_axis, amax)
2602 elif ord == -2:
2603 ret = _multi_svd_norm(x, row_axis, col_axis, amin)
2604 elif ord == 1:
2605 if col_axis > row_axis:
2606 col_axis -= 1
2607 ret = add.reduce(abs(x), axis=row_axis).max(axis=col_axis)
2608 elif ord == Inf:
2609 if row_axis > col_axis:
2610 row_axis -= 1
2611 ret = add.reduce(abs(x), axis=col_axis).max(axis=row_axis)
2612 elif ord == -1:
2613 if col_axis > row_axis:
2614 col_axis -= 1
2615 ret = add.reduce(abs(x), axis=row_axis).min(axis=col_axis)
2616 elif ord == -Inf:
2617 if row_axis > col_axis:
2618 row_axis -= 1
2619 ret = add.reduce(abs(x), axis=col_axis).min(axis=row_axis)
2620 elif ord in [None, 'fro', 'f']:
2621 ret = sqrt(add.reduce((x.conj() * x).real, axis=axis))
2622 elif ord == 'nuc':
2623 ret = _multi_svd_norm(x, row_axis, col_axis, sum)
2624 else:
2625 raise ValueError("Invalid norm order for matrices.")
2626 if keepdims:
2627 ret_shape = list(x.shape)
2628 ret_shape[axis[0]] = 1
2629 ret_shape[axis[1]] = 1
2630 ret = ret.reshape(ret_shape)
2631 return ret
2632 else:
2633 raise ValueError("Improper number of dimensions to norm.")
2634
2635
2636# multi_dot
2637
2638def _multidot_dispatcher(arrays, *, out=None):
2639 yield from arrays
2640 yield out
2641
2642
2643@array_function_dispatch(_multidot_dispatcher)
2644def multi_dot(arrays, *, out=None):
2645 """
2646 Compute the dot product of two or more arrays in a single function call,
2647 while automatically selecting the fastest evaluation order.
2648
2649 `multi_dot` chains `numpy.dot` and uses optimal parenthesization
2650 of the matrices [1]_ [2]_. Depending on the shapes of the matrices,
2651 this can speed up the multiplication a lot.
2652
2653 If the first argument is 1-D it is treated as a row vector.
2654 If the last argument is 1-D it is treated as a column vector.
2655 The other arguments must be 2-D.
2656
2657 Think of `multi_dot` as::
2658
2659 def multi_dot(arrays): return functools.reduce(np.dot, arrays)
2660
2661
2662 Parameters
2663 ----------
2664 arrays : sequence of array_like
2665 If the first argument is 1-D it is treated as row vector.
2666 If the last argument is 1-D it is treated as column vector.
2667 The other arguments must be 2-D.
2668 out : ndarray, optional
2669 Output argument. This must have the exact kind that would be returned
2670 if it was not used. In particular, it must have the right type, must be
2671 C-contiguous, and its dtype must be the dtype that would be returned
2672 for `dot(a, b)`. This is a performance feature. Therefore, if these
2673 conditions are not met, an exception is raised, instead of attempting
2674 to be flexible.
2675
2676 .. versionadded:: 1.19.0
2677
2678 Returns
2679 -------
2680 output : ndarray
2681 Returns the dot product of the supplied arrays.
2682
2683 See Also
2684 --------
2685 numpy.dot : dot multiplication with two arguments.
2686
2687 References
2688 ----------
2689
2690 .. [1] Cormen, "Introduction to Algorithms", Chapter 15.2, p. 370-378
2691 .. [2] https://en.wikipedia.org/wiki/Matrix_chain_multiplication
2692
2693 Examples
2694 --------
2695 `multi_dot` allows you to write::
2696
2697 >>> from numpy.linalg import multi_dot
2698 >>> # Prepare some data
2699 >>> A = np.random.random((10000, 100))
2700 >>> B = np.random.random((100, 1000))
2701 >>> C = np.random.random((1000, 5))
2702 >>> D = np.random.random((5, 333))
2703 >>> # the actual dot multiplication
2704 >>> _ = multi_dot([A, B, C, D])
2705
2706 instead of::
2707
2708 >>> _ = np.dot(np.dot(np.dot(A, B), C), D)
2709 >>> # or
2710 >>> _ = A.dot(B).dot(C).dot(D)
2711
2712 Notes
2713 -----
2714 The cost for a matrix multiplication can be calculated with the
2715 following function::
2716
2717 def cost(A, B):
2718 return A.shape[0] * A.shape[1] * B.shape[1]
2719
2720 Assume we have three matrices
2721 :math:`A_{10x100}, B_{100x5}, C_{5x50}`.
2722
2723 The costs for the two different parenthesizations are as follows::
2724
2725 cost((AB)C) = 10*100*5 + 10*5*50 = 5000 + 2500 = 7500
2726 cost(A(BC)) = 10*100*50 + 100*5*50 = 50000 + 25000 = 75000
2727
2728 """
2729 n = len(arrays)
2730 # optimization only makes sense for len(arrays) > 2
2731 if n < 2:
2732 raise ValueError("Expecting at least two arrays.")
2733 elif n == 2:
2734 return dot(arrays[0], arrays[1], out=out)
2735
2736 arrays = [asanyarray(a) for a in arrays]
2737
2738 # save original ndim to reshape the result array into the proper form later
2739 ndim_first, ndim_last = arrays[0].ndim, arrays[-1].ndim
2740 # Explicitly convert vectors to 2D arrays to keep the logic of the internal
2741 # _multi_dot_* functions as simple as possible.
2742 if arrays[0].ndim == 1:
2743 arrays[0] = atleast_2d(arrays[0])
2744 if arrays[-1].ndim == 1:
2745 arrays[-1] = atleast_2d(arrays[-1]).T
2746 _assert_2d(*arrays)
2747
2748 # _multi_dot_three is much faster than _multi_dot_matrix_chain_order
2749 if n == 3:
2750 result = _multi_dot_three(arrays[0], arrays[1], arrays[2], out=out)
2751 else:
2752 order = _multi_dot_matrix_chain_order(arrays)
2753 result = _multi_dot(arrays, order, 0, n - 1, out=out)
2754
2755 # return proper shape
2756 if ndim_first == 1 and ndim_last == 1:
2757 return result[0, 0] # scalar
2758 elif ndim_first == 1 or ndim_last == 1:
2759 return result.ravel() # 1-D
2760 else:
2761 return result
2762
2763
2764def _multi_dot_three(A, B, C, out=None):
2765 """
2766 Find the best order for three arrays and do the multiplication.
2767
2768 For three arguments `_multi_dot_three` is approximately 15 times faster
2769 than `_multi_dot_matrix_chain_order`
2770
2771 """
2772 a0, a1b0 = A.shape
2773 b1c0, c1 = C.shape
2774 # cost1 = cost((AB)C) = a0*a1b0*b1c0 + a0*b1c0*c1
2775 cost1 = a0 * b1c0 * (a1b0 + c1)
2776 # cost2 = cost(A(BC)) = a1b0*b1c0*c1 + a0*a1b0*c1
2777 cost2 = a1b0 * c1 * (a0 + b1c0)
2778
2779 if cost1 < cost2:
2780 return dot(dot(A, B), C, out=out)
2781 else:
2782 return dot(A, dot(B, C), out=out)
2783
2784
2785def _multi_dot_matrix_chain_order(arrays, return_costs=False):
2786 """
2787 Return a np.array that encodes the optimal order of mutiplications.
2788
2789 The optimal order array is then used by `_multi_dot()` to do the
2790 multiplication.
2791
2792 Also return the cost matrix if `return_costs` is `True`
2793
2794 The implementation CLOSELY follows Cormen, "Introduction to Algorithms",
2795 Chapter 15.2, p. 370-378. Note that Cormen uses 1-based indices.
2796
2797 cost[i, j] = min([
2798 cost[prefix] + cost[suffix] + cost_mult(prefix, suffix)
2799 for k in range(i, j)])
2800
2801 """
2802 n = len(arrays)
2803 # p stores the dimensions of the matrices
2804 # Example for p: A_{10x100}, B_{100x5}, C_{5x50} --> p = [10, 100, 5, 50]
2805 p = [a.shape[0] for a in arrays] + [arrays[-1].shape[1]]
2806 # m is a matrix of costs of the subproblems
2807 # m[i,j]: min number of scalar multiplications needed to compute A_{i..j}
2808 m = zeros((n, n), dtype=double)
2809 # s is the actual ordering
2810 # s[i, j] is the value of k at which we split the product A_i..A_j
2811 s = empty((n, n), dtype=intp)
2812
2813 for l in range(1, n):
2814 for i in range(n - l):
2815 j = i + l
2816 m[i, j] = Inf
2817 for k in range(i, j):
2818 q = m[i, k] + m[k+1, j] + p[i]*p[k+1]*p[j+1]
2819 if q < m[i, j]:
2820 m[i, j] = q
2821 s[i, j] = k # Note that Cormen uses 1-based index
2822
2823 return (s, m) if return_costs else s
2824
2825
2826def _multi_dot(arrays, order, i, j, out=None):
2827 """Actually do the multiplication with the given order."""
2828 if i == j:
2829 # the initial call with non-None out should never get here
2830 assert out is None
2831
2832 return arrays[i]
2833 else:
2834 return dot(_multi_dot(arrays, order, i, order[i, j]),
2835 _multi_dot(arrays, order, order[i, j] + 1, j),
2836 out=out)