Skip to content

Commit 8bd17c8

Browse files
authored
Merge branch 'master' into jishnub/issymmetric_number
2 parents ca9a31c + 1c0b673 commit 8bd17c8

30 files changed

+570
-190
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
docs:
1616
runs-on: ubuntu-latest
1717
steps:
18-
- uses: actions/checkout@v4
18+
- uses: actions/checkout@v5
1919
- uses: julia-actions/setup-julia@v2
2020
with:
2121
version: 'nightly'

docs/src/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,7 @@ LinearAlgebra.hermitianpart
604604
LinearAlgebra.hermitianpart!
605605
LinearAlgebra.copy_adjoint!
606606
LinearAlgebra.copy_transpose!
607+
LinearAlgebra.uplo
607608
```
608609

609610
## Low-level matrix operations

src/LinearAlgebra.jl

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ public AbstractTriangular,
181181
zeroslike,
182182
matprod_dest,
183183
fillstored!,
184-
fillband!
184+
fillband!,
185+
uplo
185186

186187
const BlasFloat = Union{Float64,Float32,ComplexF64,ComplexF32}
187188
const BlasReal = Union{Float64,Float32}
@@ -325,7 +326,7 @@ StridedMatrixStride1{T} = StridedArrayStride1{T,2}
325326
"""
326327
LinearAlgebra.checksquare(A)
327328
328-
Check that a matrix is square, then return its common dimension.
329+
Checks whether a matrix is square, returning its common dimension if it is the case, or throwing a DimensionMismatch error otherwise.
329330
For multiple arguments, return a vector.
330331
331332
# Examples
@@ -339,19 +340,13 @@ julia> LinearAlgebra.checksquare(A, B)
339340
```
340341
"""
341342
function checksquare(A)
342-
m,n = size(A)
343-
m == n || throw(DimensionMismatch(lazy"matrix is not square: dimensions are $(size(A))"))
344-
m
343+
sizeA = size(A)
344+
length(sizeA) == 2 || throw(DimensionMismatch(lazy"input is not a matrix: dimensions are $sizeA"))
345+
sizeA[1] == sizeA[2] || throw(DimensionMismatch(lazy"matrix is not square: dimensions are $sizeA"))
346+
return sizeA[1]
345347
end
346348

347-
function checksquare(A...)
348-
sizes = Int[]
349-
for a in A
350-
size(a,1)==size(a,2) || throw(DimensionMismatch(lazy"matrix is not square: dimensions are $(size(a))"))
351-
push!(sizes, size(a,1))
352-
end
353-
return sizes
354-
end
349+
checksquare(A...) = [checksquare(a) for a in A]
355350

356351
function char_uplo(uplo::Symbol)
357352
if uplo === :U
@@ -363,7 +358,14 @@ function char_uplo(uplo::Symbol)
363358
end
364359
end
365360

361+
"""
362+
sym_uplo(uplo::Char)
363+
364+
Return the `Symbol` corresponding the `uplo` by checking for validity.
365+
"""
366366
function sym_uplo(uplo::Char)
367+
# This method is called by other packages, and isn't used within LinearAlgebra
368+
# It's retained here for backward compatibility.
367369
if uplo == 'U'
368370
return :U
369371
elseif uplo == 'L'
@@ -372,6 +374,13 @@ function sym_uplo(uplo::Char)
372374
throw_uplo()
373375
end
374376
end
377+
"""
378+
_sym_uplo(uplo::Char)
379+
380+
Return the `Symbol` corresponding to `uplo` without checking for validity.
381+
See also `sym_uplo`, which checks for validity.
382+
"""
383+
_sym_uplo(uplo::Char) = uplo == 'U' ? (:U) : (:L)
375384

376385
@noinline throw_uplo() = throw(ArgumentError("uplo argument must be either :U (upper) or :L (lower)"))
377386

src/abstractq.jl

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,13 @@ convert(::Type{AbstractQ{T}}, adjQ::AdjointQ) where {T} = convert(AbstractQ{T},
4242

4343
# ... to matrix
4444
Matrix{T}(Q::AbstractQ) where {T} = convert(Matrix{T}, Q*I) # generic fallback, yields square matrix
45-
Matrix{T}(adjQ::AdjointQ{S}) where {T,S} = convert(Matrix{T}, lmul!(adjQ, Matrix{S}(I, size(adjQ))))
4645
Matrix(Q::AbstractQ{T}) where {T} = Matrix{T}(Q)
4746
Array{T}(Q::AbstractQ) where {T} = Matrix{T}(Q)
4847
Array(Q::AbstractQ) = Matrix(Q)
48+
AbstractMatrix(Q::AbstractQ) = Q*I
49+
AbstractArray(Q::AbstractQ) = AbstractMatrix(Q)
50+
AbstractMatrix{T}(Q::AbstractQ) where {T} = Matrix{T}(Q)
51+
AbstractArray{T}(Q::AbstractQ) where {T} = AbstractMatrix{T}(Q)
4952
convert(::Type{T}, Q::AbstractQ) where {T<:AbstractArray} = T(Q)
5053
# legacy
5154
@deprecate(convert(::Type{AbstractMatrix{T}}, Q::AbstractQ) where {T},
@@ -172,10 +175,10 @@ qsize_check(Q::AbstractQ, P::AbstractQ) =
172175
# mimic the AbstractArray fallback
173176
*(Q::AbstractQ{<:Number}) = Q
174177

175-
(*)(Q::AbstractQ, J::UniformScaling) = Q*J.λ
176-
function (*)(Q::AbstractQ, b::Number)
177-
T = promote_type(eltype(Q), typeof(b))
178-
lmul!(convert(AbstractQ{T}, Q), Matrix{T}(b*I, size(Q)))
178+
(*)(Q::AbstractQ, b::Number) = Q*(b*I)
179+
function (*)(Q::AbstractQ, J::UniformScaling)
180+
T = promote_type(eltype(Q), eltype(J))
181+
lmul!(convert(AbstractQ{T}, Q), Matrix{T}(J, size(Q)))
179182
end
180183
function (*)(Q::AbstractQ, B::AbstractVector)
181184
T = promote_type(eltype(Q), eltype(B))
@@ -188,10 +191,10 @@ function (*)(Q::AbstractQ, B::AbstractMatrix)
188191
mul!(similar(B, T, (size(Q, 1), size(B, 2))), convert(AbstractQ{T}, Q), B)
189192
end
190193

191-
(*)(J::UniformScaling, Q::AbstractQ) = J.λ*Q
192-
function (*)(a::Number, Q::AbstractQ)
193-
T = promote_type(typeof(a), eltype(Q))
194-
rmul!(Matrix{T}(a*I, size(Q)), convert(AbstractQ{T}, Q))
194+
(*)(a::Number, Q::AbstractQ) = (a*I)*Q
195+
function (*)(J::UniformScaling, Q::AbstractQ)
196+
T = promote_type(eltype(J), eltype(Q))
197+
rmul!(Matrix{T}(J, size(Q)), convert(AbstractQ{T}, Q))
195198
end
196199
function (*)(A::AbstractVector, Q::AbstractQ)
197200
T = promote_type(eltype(A), eltype(Q))

src/bidiag.jl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ Bidiagonal(A::Bidiagonal) = A
115115
Bidiagonal{T}(A::Bidiagonal{T}) where {T} = A
116116
Bidiagonal{T}(A::Bidiagonal) where {T} = Bidiagonal{T}(A.dv, A.ev, A.uplo)
117117

118+
"""
119+
LinearAlgebra.uplo(S::Bidiagonal)::Symbol
120+
121+
Return a `Symbol` corresponding to whether the upper (`:U`) or lower (`:L`) off-diagonal band is stored.
122+
"""
123+
uplo(B::Bidiagonal) = sym_uplo(B.uplo)
124+
118125
_offdiagind(uplo) = uplo == 'U' ? 1 : -1
119126

120127
@inline function Base.isassigned(A::Bidiagonal, i::Int, j::Int)
@@ -295,7 +302,7 @@ function show(io::IO, M::Bidiagonal)
295302
print(io, ", ")
296303
show(io, M.ev)
297304
print(io, ", ")
298-
show(io, sym_uplo(M.uplo))
305+
show(io, _sym_uplo(M.uplo))
299306
print(io, ")")
300307
end
301308

@@ -910,12 +917,12 @@ function _bidimul!(C::AbstractMatrix, A::BiTriSym, B::Diagonal, _add::MulAddMul)
910917
@inbounds begin
911918
# first row of C
912919
for j in 1:min(2, n)
913-
C[1,j] += _add(A[1,j]*B[j,j])
920+
C[1,j] += _add(A[1,j]*Bd[j])
914921
end
915922
# second row of C
916923
if n > 1
917924
for j in 1:min(3, n)
918-
C[2,j] += _add(A[2,j]*B[j,j])
925+
C[2,j] += _add(A[2,j]*Bd[j])
919926
end
920927
end
921928
for j in 3:n-2
@@ -926,13 +933,13 @@ function _bidimul!(C::AbstractMatrix, A::BiTriSym, B::Diagonal, _add::MulAddMul)
926933
if n > 3
927934
# row before last of C
928935
for j in n-2:n
929-
C[n-1,j] += _add(A[n-1,j]*B[j,j])
936+
C[n-1,j] += _add(A[n-1,j]*Bd[j])
930937
end
931938
end
932939
# last row of C
933940
if n > 2
934941
for j in n-1:n
935-
C[n,j] += _add(A[n,j]*B[j,j])
942+
C[n,j] += _add(A[n,j]*Bd[j])
936943
end
937944
end
938945
end # inbounds
@@ -1285,7 +1292,7 @@ function dot(x::AbstractVector, B::Bidiagonal, y::AbstractVector)
12851292
nx, ny = length(x), length(y)
12861293
(nx == size(B, 1) == ny) || throw(DimensionMismatch())
12871294
if nx 1
1288-
nx == 0 && return dot(zero(eltype(x)), zero(eltype(B)), zero(eltype(y)))
1295+
nx == 0 && return zero(dot(zero(eltype(x)), zero(eltype(B)), zero(eltype(y))))
12891296
return dot(x[1], B.dv[1], y[1])
12901297
end
12911298
ev, dv = B.ev, B.dv

src/blas.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,7 +2102,7 @@ end
21022102
her2k!(uplo, trans, alpha, A, B, beta, C)
21032103
21042104
Rank-2k update of the Hermitian matrix `C` as
2105-
`alpha*A*B' + alpha*B*A' + beta*C` or `alpha*A'*B + alpha*B'*A + beta*C`
2105+
`alpha*A*B' + alpha'*B*A' + beta*C` or `alpha*A'*B + alpha'*B'*A + beta*C`
21062106
according to [`trans`](@ref stdlib-blas-trans). The scalar `beta` has to be real.
21072107
Only the [`uplo`](@ref stdlib-blas-uplo) triangle of `C` is used. Return `C`.
21082108
"""
@@ -2111,8 +2111,8 @@ function her2k! end
21112111
"""
21122112
her2k(uplo, trans, alpha, A, B)
21132113
2114-
Return the [`uplo`](@ref stdlib-blas-uplo) triangle of `alpha*A*B' + alpha*B*A'`
2115-
or `alpha*A'*B + alpha*B'*A`, according to [`trans`](@ref stdlib-blas-trans).
2114+
Return the [`uplo`](@ref stdlib-blas-uplo) triangle of `alpha*A*B' + alpha'*B*A'`
2115+
or `alpha*A'*B + alpha'*B'*A`, according to [`trans`](@ref stdlib-blas-trans).
21162116
"""
21172117
her2k(uplo, trans, alpha, A, B)
21182118

src/bunchkaufman.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ function bunchkaufman!(A::StridedMatrix{<:BlasFloat}, rook::Bool = false; check:
130130
end
131131

132132
bkcopy_oftype(A, S) = eigencopy_oftype(A, S)
133-
bkcopy_oftype(A::Symmetric{<:Complex}, S) = Symmetric(copytrito!(similar(parent(A), S, size(A)), A.data, A.uplo), sym_uplo(A.uplo))
133+
function bkcopy_oftype(A::Symmetric{<:Complex}, S)
134+
Symmetric(copytrito!(similar(parent(A), S, size(A)), A.data, A.uplo), _sym_uplo(A.uplo))
135+
end
134136

135137
"""
136138
bunchkaufman(A, rook::Bool=false; check = true) -> S::BunchKaufman
@@ -215,6 +217,12 @@ BunchKaufman{T}(B::BunchKaufman) where {T} =
215217
BunchKaufman(convert(Matrix{T}, B.LD), B.ipiv, B.uplo, B.symmetric, B.rook, B.info)
216218
Factorization{T}(B::BunchKaufman) where {T} = BunchKaufman{T}(B)
217219

220+
AbstractMatrix(B::BunchKaufman) = B.uplo == 'U' ? B.P'B.U*B.D*B.U'B.P : B.P'B.L*B.D*B.L'B.P
221+
AbstractArray(B::BunchKaufman) = AbstractMatrix(B)
222+
Matrix(B::BunchKaufman) = convert(Array, AbstractArray(B))
223+
Array(B::BunchKaufman) = Matrix(B)
224+
225+
218226
size(B::BunchKaufman) = size(getfield(B, :LD))
219227
size(B::BunchKaufman, d::Integer) = size(getfield(B, :LD), d)
220228
issymmetric(B::BunchKaufman) = B.symmetric

src/cholesky.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ Factorization{T}(C::CholeskyPivoted) where {T} = CholeskyPivoted{T}(C)
646646

647647
AbstractMatrix(C::Cholesky) = C.uplo == 'U' ? C.U'C.U : C.L*C.L'
648648
AbstractArray(C::Cholesky) = AbstractMatrix(C)
649-
Matrix(C::Cholesky) = Array(AbstractArray(C))
649+
Matrix(C::Cholesky) = convert(Array, AbstractArray(C))
650650
Array(C::Cholesky) = Matrix(C)
651651

652652
function AbstractMatrix(F::CholeskyPivoted)
@@ -655,7 +655,7 @@ function AbstractMatrix(F::CholeskyPivoted)
655655
U'U
656656
end
657657
AbstractArray(F::CholeskyPivoted) = AbstractMatrix(F)
658-
Matrix(F::CholeskyPivoted) = Array(AbstractArray(F))
658+
Matrix(F::CholeskyPivoted) = convert(Array, AbstractArray(F))
659659
Array(F::CholeskyPivoted) = Matrix(F)
660660

661661
copy(C::Cholesky) = Cholesky(copy(C.factors), C.uplo, C.info)

src/dense.jl

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -237,22 +237,14 @@ end
237237

238238
fillstored!(A::AbstractMatrix, v) = fill!(A, v)
239239

240-
diagind(m::Integer, n::Integer, k::Integer=0) = diagind(IndexLinear(), m, n, k)
241-
diagind(::IndexLinear, m::Integer, n::Integer, k::Integer=0) =
242-
k <= 0 ? range(1-k, step=m+1, length=min(m+k, n)) : range(k*m+1, step=m+1, length=min(m, n-k))
243-
244-
function diagind(::IndexCartesian, m::Integer, n::Integer, k::Integer=0)
245-
Cstart = CartesianIndex(1 + max(0,-k), 1 + max(0,k))
246-
Cstep = CartesianIndex(1, 1)
247-
length = max(0, k <= 0 ? min(m+k, n) : min(m, n-k))
248-
StepRangeLen(Cstart, Cstep, length)
249-
end
250-
251240
"""
252241
diagind(M::AbstractMatrix, k::Integer = 0, indstyle::IndexStyle = IndexLinear())
253242
diagind(M::AbstractMatrix, indstyle::IndexStyle = IndexLinear())
243+
diagind(::IndexStyle, m::Integer, n::Integer, k::Integer = 0)
244+
diagind(m::Integer, n::Integer, k::Integer = 0)
254245
255-
An `AbstractRange` giving the indices of the `k`th diagonal of the matrix `M`.
246+
An `AbstractRange` giving the indices of the `k`th diagonal of a matrix,
247+
specified either by the matrix `M` itself or by its dimensions `m` and `n`.
256248
Optionally, an index style may be specified which determines the type of the range returned.
257249
If `indstyle isa IndexLinear` (default), this returns an `AbstractRange{Integer}`.
258250
On the other hand, if `indstyle isa IndexCartesian`, this returns an `AbstractRange{CartesianIndex{2}}`.
@@ -262,6 +254,7 @@ If `k` is not provided, it is assumed to be `0` (corresponding to the main diago
262254
See also: [`diag`](@ref), [`diagm`](@ref), [`Diagonal`](@ref).
263255
264256
# Examples
257+
The matrix itself may be passed to `diagind`:
265258
```jldoctest
266259
julia> A = [1 2 3; 4 5 6; 7 8 9]
267260
3×3 Matrix{Int64}:
@@ -276,6 +269,18 @@ julia> diagind(A, IndexCartesian())
276269
StepRangeLen(CartesianIndex(1, 1), CartesianIndex(1, 1), 3)
277270
```
278271
272+
Alternatively, dimensions `m` and `n` may be passed to get the diagonal of an `m×n` matrix:
273+
```jldoctest
274+
julia> m, n = 5, 7
275+
(5, 7)
276+
277+
julia> diagind(m, n, 2)
278+
11:6:35
279+
280+
julia> diagind(IndexCartesian(), m, n)
281+
StepRangeLen(CartesianIndex(1, 1), CartesianIndex(1, 1), 5)
282+
```
283+
279284
!!! compat "Julia 1.11"
280285
Specifying an `IndexStyle` requires at least Julia 1.11.
281286
"""
@@ -286,6 +291,17 @@ end
286291

287292
diagind(A::AbstractMatrix, indexstyle::IndexStyle) = diagind(A, 0, indexstyle)
288293

294+
function diagind(::IndexCartesian, m::Integer, n::Integer, k::Integer=0)
295+
Cstart = CartesianIndex(1 + max(0,-k), 1 + max(0,k))
296+
Cstep = CartesianIndex(1, 1)
297+
length = max(0, k <= 0 ? min(m+k, n) : min(m, n-k))
298+
StepRangeLen(Cstart, Cstep, length)
299+
end
300+
301+
diagind(::IndexLinear, m::Integer, n::Integer, k::Integer=0) =
302+
k <= 0 ? range(1-k, step=m+1, length=min(m+k, n)) : range(k*m+1, step=m+1, length=min(m, n-k))
303+
diagind(m::Integer, n::Integer, k::Integer=0) = diagind(IndexLinear(), m, n, k)
304+
289305
"""
290306
diag(M, k::Integer=0)
291307

src/diagonal.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,10 @@ function inv(D::Diagonal{T}) where T
970970
Diagonal(Di)
971971
end
972972

973+
# Ensure doubly wrapped matrices use efficient diagonal methods and return a Symmetric/Hermitian type
974+
inv(A::Symmetric{<:Number,<:Diagonal}) = Symmetric(inv(A.data), sym_uplo(A.uplo))
975+
inv(A::Hermitian{<:Number,<:Diagonal}) = Hermitian(inv(real(A.data)), sym_uplo(A.uplo))
976+
973977
function pinv(D::Diagonal{T}) where T
974978
Di = similar(D.diag, typeof(inv(oneunit(T))))
975979
for i = 1:length(D.diag)
@@ -1111,6 +1115,23 @@ end
11111115
/(u::AdjointAbsVec, D::Diagonal) = (D' \ u')'
11121116
/(u::TransposeAbsVec, D::Diagonal) = transpose(transpose(D) \ transpose(u))
11131117

1118+
# norm
1119+
function generic_normMinusInf(D::Diagonal)
1120+
norm_diag = norm(D.diag, -Inf)
1121+
return size(D,1) > 1 ? min(norm_diag, zero(norm_diag)) : norm_diag
1122+
end
1123+
generic_normInf(D::Diagonal) = norm(D.diag, Inf)
1124+
generic_norm1(D::Diagonal) = norm(D.diag, 1)
1125+
generic_norm2(D::Diagonal) = norm(D.diag)
1126+
function generic_normp(D::Diagonal, p)
1127+
v = norm(D.diag, p)
1128+
if size(D,1) > 1 && p < 0
1129+
v = norm(zero(v), p)
1130+
end
1131+
return v
1132+
end
1133+
norm_x_minus_y(D1::Diagonal, D2::Diagonal) = norm_x_minus_y(D1.diag, D2.diag)
1134+
11141135
_opnorm1(A::Diagonal) = maximum(norm(x) for x in A.diag)
11151136
_opnormInf(A::Diagonal) = maximum(norm(x) for x in A.diag)
11161137
_opnorm12Inf(A::Diagonal, p) = maximum(opnorm(x, p) for x in A.diag)

0 commit comments

Comments
 (0)