19
19
import warnings
20
20
21
21
from numpy .core import (
22
- array , asarray , zeros , empty , empty_like , transpose , intc , single , double ,
22
+ array , asarray , zeros , empty , empty_like , intc , single , double ,
23
23
csingle , cdouble , inexact , complexfloating , newaxis , ravel , all , Inf , dot ,
24
24
add , multiply , sqrt , maximum , fastCopyAndTranspose , sum , isfinite , size ,
25
25
finfo , errstate , geterrobj , longdouble , moveaxis , amin , amax , product , abs ,
26
- broadcast , atleast_2d , intp , asanyarray , isscalar , object_ , ones
27
- )
26
+ broadcast , atleast_2d , intp , asanyarray , isscalar , object_ , ones , matmul ,
27
+ swapaxes , divide )
28
+
28
29
from numpy .core .multiarray import normalize_axis_index
29
30
from numpy .lib import triu , asfarray
30
31
from numpy .linalg import lapack_lite , _umath_linalg
@@ -223,6 +224,22 @@ def _assertNoEmpty2d(*arrays):
223
224
if _isEmpty2d (a ):
224
225
raise LinAlgError ("Arrays cannot be empty" )
225
226
227
+ def transpose (a ):
228
+ """
229
+ Transpose each matrix in a stack of matrices.
230
+
231
+ Unlike np.transpose, this only swaps the last two axes, rather than all of
232
+ them
233
+
234
+ Parameters
235
+ ----------
236
+ a : (...,M,N) array_like
237
+
238
+ Returns
239
+ -------
240
+ aT : (...,N,M) ndarray
241
+ """
242
+ return swapaxes (a , - 1 , - 2 )
226
243
227
244
# Linear equations
228
245
@@ -1279,7 +1296,7 @@ def eigh(a, UPLO='L'):
1279
1296
1280
1297
# Singular value decomposition
1281
1298
1282
- def svd (a , full_matrices = 1 , compute_uv = 1 ):
1299
+ def svd (a , full_matrices = True , compute_uv = True ):
1283
1300
"""
1284
1301
Singular Value Decomposition.
1285
1302
@@ -1494,15 +1511,21 @@ def matrix_rank(M, tol=None):
1494
1511
Rank of the array is the number of SVD singular values of the array that are
1495
1512
greater than `tol`.
1496
1513
1514
+ .. versionchanged:: 1.14
1515
+ Can now operate on stacks of matrices
1516
+
1497
1517
Parameters
1498
1518
----------
1499
1519
M : {(M,), (..., M, N)} array_like
1500
1520
input vector or stack of matrices
1501
- tol : {None, float}, optional
1502
- threshold below which SVD values are considered zero. If `tol` is
1503
- None, and ``S`` is an array with singular values for `M`, and
1504
- ``eps`` is the epsilon value for datatype of ``S``, then `tol` is
1505
- set to ``S.max() * max(M.shape) * eps``.
1521
+ tol : (...) array_like, float, optional
1522
+ threshold below which SVD values are considered zero. If `tol` is
1523
+ None, and ``S`` is an array with singular values for `M`, and
1524
+ ``eps`` is the epsilon value for datatype of ``S``, then `tol` is
1525
+ set to ``S.max() * max(M.shape) * eps``.
1526
+
1527
+ .. versionchanged:: 1.14
1528
+ Broadcasted against the stack of matrices
1506
1529
1507
1530
Notes
1508
1531
-----
@@ -1569,6 +1592,8 @@ def matrix_rank(M, tol=None):
1569
1592
S = svd (M , compute_uv = False )
1570
1593
if tol is None :
1571
1594
tol = S .max (axis = - 1 , keepdims = True ) * max (M .shape [- 2 :]) * finfo (S .dtype ).eps
1595
+ else :
1596
+ tol = asarray (tol )[...,newaxis ]
1572
1597
return (S > tol ).sum (axis = - 1 )
1573
1598
1574
1599
@@ -1582,26 +1607,29 @@ def pinv(a, rcond=1e-15 ):
1582
1607
singular-value decomposition (SVD) and including all
1583
1608
*large* singular values.
1584
1609
1610
+ .. versionchanged:: 1.14
1611
+ Can now operate on stacks of matrices
1612
+
1585
1613
Parameters
1586
1614
----------
1587
- a : (M, N) array_like
1588
- Matrix to be pseudo-inverted.
1589
- rcond : float
1590
- Cutoff for small singular values.
1591
- Singular values smaller (in modulus) than
1592
- `rcond` * largest_singular_value (again, in modulus)
1593
- are set to zero.
1615
+ a : (..., M, N) array_like
1616
+ Matrix or stack of matrices to be pseudo-inverted.
1617
+ rcond : (...) array_like of float
1618
+ Cutoff for small singular values.
1619
+ Singular values smaller (in modulus) than
1620
+ `rcond` * largest_singular_value (again, in modulus)
1621
+ are set to zero. Broadcasts against the stack of matrices
1594
1622
1595
1623
Returns
1596
1624
-------
1597
- B : (N, M) ndarray
1598
- The pseudo-inverse of `a`. If `a` is a `matrix` instance, then so
1599
- is `B`.
1625
+ B : (..., N, M) ndarray
1626
+ The pseudo-inverse of `a`. If `a` is a `matrix` instance, then so
1627
+ is `B`.
1600
1628
1601
1629
Raises
1602
1630
------
1603
1631
LinAlgError
1604
- If the SVD computation does not converge.
1632
+ If the SVD computation does not converge.
1605
1633
1606
1634
Notes
1607
1635
-----
@@ -1638,20 +1666,20 @@ def pinv(a, rcond=1e-15 ):
1638
1666
1639
1667
"""
1640
1668
a , wrap = _makearray (a )
1669
+ rcond = asarray (rcond )
1641
1670
if _isEmpty2d (a ):
1642
1671
res = empty (a .shape [:- 2 ] + (a .shape [- 1 ], a .shape [- 2 ]), dtype = a .dtype )
1643
1672
return wrap (res )
1644
1673
a = a .conjugate ()
1645
- u , s , vt = svd (a , 0 )
1646
- m = u .shape [0 ]
1647
- n = vt .shape [1 ]
1648
- cutoff = rcond * maximum .reduce (s )
1649
- for i in range (min (n , m )):
1650
- if s [i ] > cutoff :
1651
- s [i ] = 1. / s [i ]
1652
- else :
1653
- s [i ] = 0.
1654
- res = dot (transpose (vt ), multiply (s [:, newaxis ], transpose (u )))
1674
+ u , s , vt = svd (a , full_matrices = False )
1675
+
1676
+ # discard small singular values
1677
+ cutoff = rcond [..., newaxis ] * amax (s , axis = - 1 , keepdims = True )
1678
+ large = s > cutoff
1679
+ s = divide (1 , s , where = large , out = s )
1680
+ s [~ large ] = 0
1681
+
1682
+ res = matmul (transpose (vt ), multiply (s [..., newaxis ], transpose (u )))
1655
1683
return wrap (res )
1656
1684
1657
1685
# Determinant
@@ -1987,13 +2015,13 @@ def lstsq(a, b, rcond="warn"):
1987
2015
resids = array ([sum ((ravel (bstar )[n :])** 2 )],
1988
2016
dtype = result_real_t )
1989
2017
else :
1990
- x = array (transpose ( bstar ) [:n ,:], dtype = result_t , copy = True )
2018
+ x = array (bstar . T [:n ,:], dtype = result_t , copy = True )
1991
2019
if results ['rank' ] == n and m > n :
1992
2020
if isComplexType (t ):
1993
- resids = sum (abs (transpose ( bstar ) [n :,:])** 2 , axis = 0 ).astype (
2021
+ resids = sum (abs (bstar . T [n :,:])** 2 , axis = 0 ).astype (
1994
2022
result_real_t , copy = False )
1995
2023
else :
1996
- resids = sum ((transpose ( bstar ) [n :,:])** 2 , axis = 0 ).astype (
2024
+ resids = sum ((bstar . T [n :,:])** 2 , axis = 0 ).astype (
1997
2025
result_real_t , copy = False )
1998
2026
1999
2027
st = s [:min (n , m )].astype (result_real_t , copy = True )
0 commit comments