Skip to content

Commit b951b92

Browse files
authored
Merge branch 'master' into jishnub/lrmul_adjtrans
2 parents a462e5a + cdd135e commit b951b92

31 files changed

+735
-95
lines changed

docs/src/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ LinearAlgebra.BLAS.trsv
745745

746746
```@docs
747747
LinearAlgebra.BLAS.ger!
748-
# xGERU
748+
LinearAlgebra.BLAS.geru!
749749
# xGERC
750750
LinearAlgebra.BLAS.her!
751751
# xHPR

src/LinearAlgebra.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ public AbstractTriangular,
180180
symmetric_type,
181181
zeroslike,
182182
matprod_dest,
183-
fillstored!
183+
fillstored!,
184+
fillband!
184185

185186
const BlasFloat = Union{Float64,Float32,ComplexF64,ComplexF32}
186187
const BlasReal = Union{Float64,Float32}

src/adjtrans.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,3 +580,8 @@ diagview(A::Adjoint, k::Integer = 0) = _vecadjoint(diagview(parent(A), -k))
580580
# triu and tril
581581
triu!(A::AdjOrTransAbsMat, k::Integer = 0) = wrapperop(A)(tril!(parent(A), -k))
582582
tril!(A::AdjOrTransAbsMat, k::Integer = 0) = wrapperop(A)(triu!(parent(A), -k))
583+
584+
function fillband!(A::AdjOrTrans, v, k1, k2)
585+
fillband!(parent(A), wrapperop(A)(v), -k2, -k1)
586+
return A
587+
end

src/bidiag.jl

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,35 @@ function inv(B::Bidiagonal{T}) where T
14671467
return B.uplo == 'U' ? UpperTriangular(dest) : LowerTriangular(dest)
14681468
end
14691469

1470+
# cholesky-version for (sym)tridiagonal matrices
1471+
for (T, uplo) in ((:UpperTriangular, :(:U)), (:LowerTriangular, :(:L)))
1472+
@eval function _chol!(A::Bidiagonal, ::Type{$T})
1473+
dv = real(A.dv)
1474+
ev = A.ev
1475+
n = length(dv)
1476+
@inbounds for i in 1:n-1
1477+
iszero(dv[i]) && throw(ZeroPivotException(i))
1478+
ev[i] /= dv[i]
1479+
dv[i+1] -= abs2(ev[i])*dv[i]
1480+
Akk = dv[i]
1481+
Akk, info = _chol!(Akk, UpperTriangular)
1482+
if info != 0
1483+
return $T(A), convert(BlasInt, i)
1484+
end
1485+
dv[i] = Akk
1486+
ev[i] *= dv[i]
1487+
end
1488+
Akk = dv[n]
1489+
Akk, info = _chol!(Akk, $T)
1490+
if info != 0
1491+
return $T(A), convert(BlasInt, n)
1492+
end
1493+
dv[n] = Akk
1494+
B = Bidiagonal(dv, ev, $uplo)
1495+
return $T(B), convert(BlasInt, 0)
1496+
end
1497+
end
1498+
14701499
# Eigensystems
14711500
eigvals(M::Bidiagonal) = copy(M.dv)
14721501
function eigvecs(M::Bidiagonal{T}) where T
@@ -1543,3 +1572,30 @@ function Base._sum(A::Bidiagonal, dims::Integer)
15431572
end
15441573
res
15451574
end
1575+
1576+
function fillband!(B::Bidiagonal, x, l, u)
1577+
if l > u
1578+
return B
1579+
end
1580+
if ((B.uplo == 'U' && (l < 0 || u > 1)) ||
1581+
(B.uplo == 'L' && (l < -1 || u > 0))) && !iszero(x)
1582+
throw_fillband_error(l, u, x)
1583+
else
1584+
if B.uplo == 'U'
1585+
if l <= 1 <= u
1586+
fill!(B.ev, x)
1587+
end
1588+
if l <= 0 <= u
1589+
fill!(B.dv, x)
1590+
end
1591+
else # B.uplo == 'L'
1592+
if l <= 0 <= u
1593+
fill!(B.dv, x)
1594+
end
1595+
if l <= -1 <= u
1596+
fill!(B.ev, x)
1597+
end
1598+
end
1599+
end
1600+
return B
1601+
end

src/cholesky.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ end
413413
# cholesky!. Destructive methods for computing Cholesky factorization of real symmetric
414414
# or Hermitian matrix
415415
## No pivoting (default)
416-
function cholesky!(A::SelfAdjoint, ::NoPivot = NoPivot(); check::Bool = true)
416+
function cholesky!(A::RealSymHermitian, ::NoPivot = NoPivot(); check::Bool = true)
417417
C, info = _chol!(A.data, A.uplo == 'U' ? UpperTriangular : LowerTriangular)
418418
check && checkpositivedefinite(info)
419419
return Cholesky(C.data, A.uplo, info)
@@ -455,7 +455,7 @@ end
455455

456456
## With pivoting
457457
### Non BLAS/LAPACK element types (generic).
458-
function cholesky!(A::SelfAdjoint, ::RowMaximum; tol = 0.0, check::Bool = true)
458+
function cholesky!(A::RealSymHermitian, ::RowMaximum; tol = 0.0, check::Bool = true)
459459
AA, piv, rank, info = _cholpivoted!(A.data, A.uplo == 'U' ? UpperTriangular : LowerTriangular, tol, check)
460460
C = CholeskyPivoted(AA, A.uplo, piv, rank, tol, info)
461461
check && chkfullrank(C)

src/dense.jl

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,23 @@ tril(M::Matrix, k::Integer) = tril!(copy(M), k)
205205
fillband!(A::AbstractMatrix, x, l, u)
206206
207207
Fill the band between diagonals `l` and `u` with the value `x`.
208+
209+
# Examples
210+
```jldoctest
211+
julia> A = zeros(4,4)
212+
4×4 Matrix{Float64}:
213+
0.0 0.0 0.0 0.0
214+
0.0 0.0 0.0 0.0
215+
0.0 0.0 0.0 0.0
216+
0.0 0.0 0.0 0.0
217+
218+
julia> LinearAlgebra.fillband!(A, 2, 0, 1)
219+
4×4 Matrix{Float64}:
220+
2.0 2.0 0.0 0.0
221+
0.0 2.0 2.0 0.0
222+
0.0 0.0 2.0 2.0
223+
0.0 0.0 0.0 2.0
224+
```
208225
"""
209226
function fillband!(A::AbstractMatrix{T}, x, l, u) where T
210227
require_one_based_indexing(A)
@@ -1731,10 +1748,21 @@ both with the value of `M` and the intended application of the pseudoinverse.
17311748
The default relative tolerance is `n*ϵ`, where `n` is the size of the smallest
17321749
dimension of `M`, and `ϵ` is the [`eps`](@ref) of the element type of `M`.
17331750
1734-
For inverting dense ill-conditioned matrices in a least-squares sense,
1735-
`rtol = sqrt(eps(real(float(oneunit(eltype(M))))))` is recommended.
1751+
For solving dense, ill-conditioned equations in a least-square sense, it
1752+
is better to *not* explicitly form the pseudoinverse matrix, since this
1753+
can lead to numerical instability at low tolerances. The default `M \\ b`
1754+
algorithm instead uses pivoted QR factorization ([`qr`](@ref)). To use an
1755+
SVD-based algorithm, it is better to employ the SVD directly via `svd(M; rtol, atol) \\ b`
1756+
or `ldiv!(svd(M), b; rtol, atol)`.
1757+
1758+
One can also pass `M = svd(A)` as the argument to `pinv` in order to re-use
1759+
an existing [`SVD`](@ref) factorization. In this case, `pinv` will return
1760+
the SVD of the pseudo-inverse, which can be applied accurately, instead of an explicit matrix.
1761+
1762+
!!! compat "Julia 1.13"
1763+
Passing an `SVD` object to `pinv` requires Julia 1.13 or later.
17361764
1737-
For more information, see [^issue8859], [^B96], [^S84], [^KY88].
1765+
For more information, see [^pr1387], [^B96], [^S84], [^KY88].
17381766
17391767
# Examples
17401768
```jldoctest
@@ -1754,15 +1782,15 @@ julia> M * N
17541782
4.44089e-16 1.0
17551783
```
17561784
1757-
[^issue8859]: Issue 8859, "Fix least squares", [https://github.com/JuliaLang/julia/pull/8859](https://github.com/JuliaLang/julia/pull/8859)
1785+
[^pr1387]: PR 1387, "stable pinv least-squares", [LinearAlgebra.jl#1387](https://github.com/JuliaLang/LinearAlgebra.jl/pull/1387)
17581786
17591787
[^B96]: Åke Björck, "Numerical Methods for Least Squares Problems", SIAM Press, Philadelphia, 1996, "Other Titles in Applied Mathematics", Vol. 51. [doi:10.1137/1.9781611971484](http://epubs.siam.org/doi/book/10.1137/1.9781611971484)
17601788
17611789
[^S84]: G. W. Stewart, "Rank Degeneracy", SIAM Journal on Scientific and Statistical Computing, 5(2), 1984, 403-413. [doi:10.1137/0905030](http://epubs.siam.org/doi/abs/10.1137/0905030)
17621790
17631791
[^KY88]: Konstantinos Konstantinides and Kung Yao, "Statistical analysis of effective singular values in matrix rank determination", IEEE Transactions on Acoustics, Speech and Signal Processing, 36(5), 1988, 757-763. [doi:10.1109/29.1585](https://doi.org/10.1109/29.1585)
17641792
"""
1765-
function pinv(A::AbstractMatrix{T}; atol::Real = 0.0, rtol::Real = (eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T
1793+
function pinv(A::AbstractMatrix{T}; atol::Real=0, rtol::Real = (eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T
17661794
m, n = size(A)
17671795
Tout = typeof(zero(T)/sqrt(oneunit(T) + oneunit(T)))
17681796
if m == 0 || n == 0
@@ -1830,7 +1858,7 @@ julia> nullspace(M, atol=0.95)
18301858
1.0
18311859
```
18321860
"""
1833-
function nullspace(A::AbstractVecOrMat; atol::Real = 0.0, rtol::Real = (min(size(A, 1), size(A, 2))*eps(real(float(oneunit(eltype(A))))))*iszero(atol))
1861+
function nullspace(A::AbstractVecOrMat; atol::Real=0, rtol::Real = (min(size(A, 1), size(A, 2))*eps(real(float(oneunit(eltype(A))))))*iszero(atol))
18341862
m, n = size(A, 1), size(A, 2)
18351863
(m == 0 || n == 0) && return Matrix{eigtype(eltype(A))}(I, n, n)
18361864
SVD = svd(A; full=true)

src/diagonal.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,11 @@ end
806806

807807
kron(A::Diagonal, B::Diagonal) = Diagonal(kron(A.diag, B.diag))
808808

809+
function kron!(C::Diagonal, A::Diagonal, B::Diagonal)
810+
kron!(C.diag, A.diag, B.diag)
811+
return C
812+
end
813+
809814
function kron(A::Diagonal, B::SymTridiagonal)
810815
kdv = kron(A.diag, B.dv)
811816
# We don't need to drop the last element
@@ -1216,3 +1221,18 @@ end
12161221

12171222
uppertriangular(D::Diagonal) = D
12181223
lowertriangular(D::Diagonal) = D
1224+
1225+
throw_fillband_error(l, u, x) = throw(ArgumentError(lazy"cannot set bands $l:$u to a nonzero value ($x)"))
1226+
1227+
function fillband!(D::Diagonal, x, l, u)
1228+
if l > u
1229+
return D
1230+
end
1231+
if (l < 0 || u > 0) && !iszero(x)
1232+
throw_fillband_error(l, u, x)
1233+
end
1234+
if l <= 0 <= u
1235+
fill!(D.diag, x)
1236+
end
1237+
return D
1238+
end

src/factorization.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ Factorization{T}(A::AdjointFactorization) where {T} =
110110
adjoint(Factorization{T}(parent(A)))
111111
Factorization{T}(A::TransposeFactorization) where {T} =
112112
transpose(Factorization{T}(parent(A)))
113-
inv(F::Factorization{T}) where {T} = (n = size(F, 1); ldiv!(F, Matrix{T}(I, n, n)))
113+
inv(F::Factorization{T}) where {T} = (n = checksquare(F); ldiv!(F, Matrix{T}(I, n, n)))
114114

115115
Base.hash(F::Factorization, h::UInt) = mapreduce(f -> hash(getfield(F, f)), hash, 1:nfields(F); init=h)
116116
Base.:(==)( F::T, G::T) where {T<:Factorization} = all(f -> getfield(F, f) == getfield(G, f), 1:nfields(F))

src/generic.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1846,7 +1846,7 @@ julia> det(BigInt[1 0; 2 2]) # exact integer determinant
18461846
function det(A::AbstractMatrix{T}) where {T}
18471847
if istriu(A) || istril(A)
18481848
S = promote_type(T, typeof((one(T)*zero(T) + zero(T))/one(T)))
1849-
return convert(S, det(UpperTriangular(A)))
1849+
return prod(Base.Fix1(convert, S), @view A[diagind(A)]; init=one(S))
18501850
end
18511851
return det(lu(A; check = false))
18521852
end

src/hessenberg.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ lmul!(x::Number, H::UpperHessenberg) = (lmul!(x, H.data); H)
124124

125125
fillstored!(H::UpperHessenberg, x) = (fillband!(H.data, x, -1, size(H,2)-1); H)
126126

127+
function fillband!(H::UpperHessenberg, x, l, u)
128+
if l > u
129+
return H
130+
end
131+
if l < -1 && !iszero(x)
132+
throw_fillband_error(l, u, x)
133+
end
134+
fillband!(H.data, x, l, u)
135+
return H
136+
end
137+
127138
+(A::UpperHessenberg, B::UpperHessenberg) = UpperHessenberg(A.data+B.data)
128139
-(A::UpperHessenberg, B::UpperHessenberg) = UpperHessenberg(A.data-B.data)
129140

0 commit comments

Comments
 (0)