From c32bfdc85be68fe65353003f6a4cf5278308e4d3 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Tue, 27 Apr 2021 11:05:41 +0200 Subject: [PATCH 1/8] Use constant propagation instead of Val-types in `lu` and `qr` Co-authored-by: Andreas Noack --- stdlib/LinearAlgebra/src/dense.jl | 2 +- stdlib/LinearAlgebra/src/factorization.jl | 11 ++-- stdlib/LinearAlgebra/src/generic.jl | 2 +- stdlib/LinearAlgebra/src/lu.jl | 63 ++++++++++++++++------- stdlib/LinearAlgebra/src/qr.jl | 40 ++++++++++---- stdlib/LinearAlgebra/test/lu.jl | 10 ++-- stdlib/LinearAlgebra/test/qr.jl | 1 - 7 files changed, 87 insertions(+), 42 deletions(-) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index ff789a9fd11b2..b1256ec45abde 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -1371,7 +1371,7 @@ function factorize(A::StridedMatrix{T}) where T end return lu(A) end - qr(A, Val(true)) + qr(A, :colnorm) end factorize(A::Adjoint) = adjoint(factorize(parent(A))) factorize(A::Transpose) = transpose(factorize(parent(A))) diff --git a/stdlib/LinearAlgebra/src/factorization.jl b/stdlib/LinearAlgebra/src/factorization.jl index 3e335ed391ad6..c45adfa76406e 100644 --- a/stdlib/LinearAlgebra/src/factorization.jl +++ b/stdlib/LinearAlgebra/src/factorization.jl @@ -16,9 +16,14 @@ size(F::Adjoint{<:Any,<:Factorization}) = reverse(size(parent(F))) size(F::Transpose{<:Any,<:Factorization}) = reverse(size(parent(F))) checkpositivedefinite(info) = info == 0 || throw(PosDefException(info)) -checknonsingular(info, pivoted::Val{true}) = info == 0 || throw(SingularException(info)) -checknonsingular(info, pivoted::Val{false}) = info == 0 || throw(ZeroPivotException(info)) -checknonsingular(info) = checknonsingular(info, Val{true}()) +function checknonsingular(info, pivoted = :rowmax) + if info != 0 + pivoted === :rowmax && throw(SingularException(info)) + pivoted === :none && throw(ZeroPivotException(info)) + else + return nothing + end +end """ issuccess(F::Factorization) diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index ec8e9df654c46..2fed6e44baa89 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -1141,7 +1141,7 @@ function (\)(A::AbstractMatrix, B::AbstractVecOrMat) end return lu(A) \ B end - return qr(A,Val(true)) \ B + return qr(A, :colnorm) \ B end (\)(a::AbstractVector, b::AbstractArray) = pinv(a) * b diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index 2d915680d5381..a0e9789a26b06 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -76,22 +76,28 @@ adjoint(F::LU) = Adjoint(F) transpose(F::LU) = Transpose(F) # StridedMatrix -function lu!(A::StridedMatrix{T}, pivot::Union{Val{false}, Val{true}} = Val(true); - check::Bool = true) where T<:BlasFloat - if pivot === Val(false) +function lu!(A::StridedMatrix{T}, pivot::Symbol = :rowmax; check::Bool = true) where {T<:BlasFloat} + if pivot === :none return generic_lufact!(A, pivot; check = check) + elseif pivot === :rowmax + lpt = LAPACK.getrf!(A) + check && checknonsingular(lpt[3]) + return LU{T,typeof(A)}(lpt[1], lpt[2], lpt[3]) + else + throw(ArgumentError("only `:rowmax` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) end - lpt = LAPACK.getrf!(A) - check && checknonsingular(lpt[3]) - return LU{T,typeof(A)}(lpt[1], lpt[2], lpt[3]) end -function lu!(A::HermOrSym, pivot::Union{Val{false}, Val{true}} = Val(true); check::Bool = true) +function lu!(A::HermOrSym, pivot::Symbol = :rowmax; check::Bool = true) copytri!(A.data, A.uplo, isa(A, Hermitian)) lu!(A.data, pivot; check = check) end +# for backward compatibility +# TODO: remove/deprecate towards Julia v2 +lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = true) = lu!(A, :rowmax; check=check) +lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{false}; check::Bool = true) = lu!(A, :none; check=check) """ - lu!(A, pivot=Val(true); check = true) -> LU + lu!(A; pivot= :rowmax, check = true) -> LU `lu!` is the same as [`lu`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. An [`InexactError`](@ref) @@ -127,19 +133,26 @@ Stacktrace: [...] ``` """ -lu!(A::StridedMatrix, pivot::Union{Val{false}, Val{true}} = Val(true); check::Bool = true) = +lu!(A::StridedMatrix, pivot::Symbol = :rowmax; check::Bool = true) = generic_lufact!(A, pivot; check = check) -function generic_lufact!(A::StridedMatrix{T}, ::Val{Pivot} = Val(true); - check::Bool = true) where {T,Pivot} +function generic_lufact!(A::StridedMatrix{T}, pivot = :rowmax; check::Bool = true) where T + # Check arguments + if pivot !== :rowmax && pivot !== :none + throw(ArgumentError("only `rowmax` and `none` are supported as `pivot` argument but you supplied `$pivot`")) + end + + # Extract values m, n = size(A) minmn = min(m,n) + + # Initialize variables info = 0 ipiv = Vector{BlasInt}(undef, minmn) @inbounds begin for k = 1:minmn # find index max kp = k - if Pivot && k < m + if pivot === :rowmax && k < m amax = abs(A[k, k]) for i = k+1:m absi = abs(A[i,k]) @@ -175,7 +188,7 @@ function generic_lufact!(A::StridedMatrix{T}, ::Val{Pivot} = Val(true); end end end - check && checknonsingular(info, Val{Pivot}()) + check && checknonsingular(info, pivot) return LU{T,typeof(A)}(A, ipiv, convert(BlasInt, info)) end @@ -200,7 +213,7 @@ end # for all other types we must promote to a type which is stable under division """ - lu(A, pivot=Val(true); check = true) -> F::LU + lu(A, pivot = :rowmax; check = true) -> F::LU Compute the LU factorization of `A`. @@ -267,11 +280,14 @@ julia> l == F.L && u == F.U && p == F.p true ``` """ -function lu(A::AbstractMatrix{T}, pivot::Union{Val{false}, Val{true}}=Val(true); - check::Bool = true) where T +function lu(A::AbstractMatrix{T}, pivot::Symbol = :rowmax; check::Bool = true) where {T} S = lutype(T) lu!(copy_oftype(A, S), pivot; check = check) end +# TODO: remove/deprecate for Julia v2.0 +lu(A::AbstractMatrix, ::Val{true}; check::Bool = true) = lu(A, :rowmax; check=check) +lu(A::AbstractMatrix, ::Val{false}; check::Bool = true) = lu(A, :none; check=check) + lu(S::LU) = S function lu(x::Number; check::Bool=true) @@ -481,9 +497,16 @@ inv(A::LU{<:BlasFloat,<:StridedMatrix}) = inv!(copy(A)) # Tridiagonal # See dgttrf.f -function lu!(A::Tridiagonal{T,V}, pivot::Union{Val{false}, Val{true}} = Val(true); - check::Bool = true) where {T,V} +function lu!(A::Tridiagonal{T,V}, pivot::Symbol = :rowmax; check::Bool = true) where {T,V} + # Extract values n = size(A, 1) + + # Check arguments + if pivot !== :rowmax && pivot !== :none + throw(ArgumentError("only `:row` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) + end + + # Initialize variables info = 0 ipiv = Vector{BlasInt}(undef, n) dl = A.dl @@ -500,7 +523,7 @@ function lu!(A::Tridiagonal{T,V}, pivot::Union{Val{false}, Val{true}} = Val(true end for i = 1:n-2 # pivot or not? - if pivot === Val(false) || abs(d[i]) >= abs(dl[i]) + if pivot === :none || abs(d[i]) >= abs(dl[i]) # No interchange if d[i] != 0 fact = dl[i]/d[i] @@ -523,7 +546,7 @@ function lu!(A::Tridiagonal{T,V}, pivot::Union{Val{false}, Val{true}} = Val(true end if n > 1 i = n-1 - if pivot === Val(false) || abs(d[i]) >= abs(dl[i]) + if pivot === :none || abs(d[i]) >= abs(dl[i]) if d[i] != 0 fact = dl[i]/d[i] dl[i] = fact diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index cd5d17565fa3f..382fd0634f36f 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -246,14 +246,20 @@ function qrfactPivotedUnblocked!(A::AbstractMatrix) end # LAPACK version -qr!(A::StridedMatrix{<:BlasFloat}, ::Val{false} = Val(false); blocksize=36) = - QRCompactWY(LAPACK.geqrt!(A, min(min(size(A)...), blocksize))...) -qr!(A::StridedMatrix{<:BlasFloat}, ::Val{true}) = QRPivoted(LAPACK.geqp3!(A)...) +@inline function qr!(A::StridedMatrix{<:BlasFloat}, pivot::Symbol = :none; blocksize=36) + if pivot === :none + return QRCompactWY(LAPACK.geqrt!(A, min(min(size(A)...), blocksize))...) + elseif pivot === :colnorm + return QRPivoted(LAPACK.geqp3!(A)...) + else + throw(ArgumentError("only `:colnorm` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) + end +end # Generic fallbacks """ - qr!(A, pivot=Val(false); blocksize) + qr!(A, pivot = :none; blocksize) `qr!` is the same as [`qr`](@ref) when `A` is a subtype of [`StridedMatrix`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. @@ -292,14 +298,23 @@ Stacktrace: [...] ``` """ -qr!(A::AbstractMatrix, ::Val{false}) = qrfactUnblocked!(A) -qr!(A::AbstractMatrix, ::Val{true}) = qrfactPivotedUnblocked!(A) -qr!(A::AbstractMatrix) = qr!(A, Val(false)) +@inline function qr!(A::AbstractMatrix, pivot::Symbol = :none) + if pivot === :none + return qrfactUnblocked!(A) + elseif pivot === :colnorm + return qrfactPivotedUnblocked!(A) + else + throw(ArgumentError("only `:colnorm` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) + end +end +# TODO: Remove/deprecate towards Julia v2.0 +@inline qr!(A::AbstractMatrix, ::Val{true}) = qr!(A, :colnorm) +@inline qr!(A::AbstractMatrix, ::Val{false}) = qr!(A, :none) _qreltype(::Type{T}) where T = typeof(zero(T)/sqrt(abs2(one(T)))) """ - qr(A, pivot=Val(false); blocksize) -> F + qr(A, pivot = :none; blocksize) -> F Compute the QR factorization of the matrix `A`: an orthogonal (or unitary if `A` is complex-valued) matrix `Q`, and an upper triangular matrix `R` such that @@ -310,7 +325,7 @@ A = Q R The returned object `F` stores the factorization in a packed format: - - if `pivot == Val(true)` then `F` is a [`QRPivoted`](@ref) object, + - if `pivot == :colnorm` then `F` is a [`QRPivoted`](@ref) object, - otherwise if the element type of `A` is a BLAS type ([`Float32`](@ref), [`Float64`](@ref), `ComplexF32` or `ComplexF64`), then `F` is a [`QRCompactWY`](@ref) object, @@ -340,7 +355,7 @@ and `F.Q*A` are supported. A `Q` matrix can be converted into a regular matrix w orthogonal matrix. The block size for QR decomposition can be specified by keyword argument -`blocksize :: Integer` when `pivot == Val(false)` and `A isa StridedMatrix{<:BlasFloat}`. +`blocksize :: Integer` when `pivot == :none` and `A isa StridedMatrix{<:BlasFloat}`. It is ignored when `blocksize > minimum(size(A))`. See [`QRCompactWY`](@ref). !!! compat "Julia 1.4" @@ -376,12 +391,15 @@ true elementary reflectors, so that the `Q` and `R` matrices can be stored compactly rather as two separate dense matrices. """ -function qr(A::AbstractMatrix{T}, arg...; kwargs...) where T +@inline function qr(A::AbstractMatrix{T}, arg...; kwargs...) where T require_one_based_indexing(A) AA = similar(A, _qreltype(T), size(A)) copyto!(AA, A) return qr!(AA, arg...; kwargs...) end +@inline qr(A::AbstractMatrix, ::Val{false}; kwargs...) = qr(A, :none; kwargs...) +@inline qr(A::AbstractMatrix, ::Val{true}; kwargs...) = qr(A, :colnorm; kwargs...) + qr(x::Number) = qr(fill(x,1,1)) function qr(v::AbstractVector) require_one_based_indexing(v) diff --git a/stdlib/LinearAlgebra/test/lu.jl b/stdlib/LinearAlgebra/test/lu.jl index 8e6c06cdbd12e..c8366deafccdc 100644 --- a/stdlib/LinearAlgebra/test/lu.jl +++ b/stdlib/LinearAlgebra/test/lu.jl @@ -61,7 +61,7 @@ dimg = randn(n)/2 lua = factorize(a) @test_throws ErrorException lua.Z l,u,p = lua.L, lua.U, lua.p - ll,ul,pl = lu(a) + ll,ul,pl = @inferred lu(a) @test ll * ul ≈ a[pl,:] @test l*u ≈ a[p,:] @test (l*u)[invperm(p),:] ≈ a @@ -85,9 +85,9 @@ dimg = randn(n)/2 end κd = cond(Array(d),1) @testset "Tridiagonal LU" begin - lud = lu(d) + lud = @inferred lu(d) @test LinearAlgebra.issuccess(lud) - @test lu(lud) == lud + @test @inferred(lu(lud)) == lud @test_throws ErrorException lud.Z @test lud.L*lud.U ≈ lud.P*Array(d) @test lud.L*lud.U ≈ Array(d)[lud.p,:] @@ -199,14 +199,14 @@ dimg = randn(n)/2 @test lua.L*lua.U ≈ lua.P*a[:,1:n1] end @testset "Fat LU" begin - lua = lu(a[1:n1,:]) + lua = @inferred lu(a[1:n1,:]) @test lua.L*lua.U ≈ lua.P*a[1:n1,:] end end @testset "LU of Symmetric/Hermitian" begin for HS in (Hermitian(a'a), Symmetric(a'a)) - luhs = lu(HS) + luhs = @inferred lu(HS) @test luhs.L*luhs.U ≈ luhs.P*Matrix(HS) end end diff --git a/stdlib/LinearAlgebra/test/qr.jl b/stdlib/LinearAlgebra/test/qr.jl index 394b371e02eac..0f30770e082bb 100644 --- a/stdlib/LinearAlgebra/test/qr.jl +++ b/stdlib/LinearAlgebra/test/qr.jl @@ -49,7 +49,6 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) a_1 = size(a, 1) @testset "QR decomposition (without pivoting)" begin qra = @inferred qr(a) - @inferred qr(a) q, r = qra.Q, qra.R @test_throws ErrorException qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) From 4553c2f998a75c2a8c0183f3f4e2e20ca304ea2e Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Tue, 27 Apr 2021 14:38:51 +0200 Subject: [PATCH 2/8] replace at-inline by at-aggressive_constprop --- stdlib/LinearAlgebra/src/qr.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 382fd0634f36f..255dfdd1f5eed 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -246,7 +246,7 @@ function qrfactPivotedUnblocked!(A::AbstractMatrix) end # LAPACK version -@inline function qr!(A::StridedMatrix{<:BlasFloat}, pivot::Symbol = :none; blocksize=36) +Base.@aggressive_constprop function qr!(A::StridedMatrix{<:BlasFloat}, pivot::Symbol = :none; blocksize=36) if pivot === :none return QRCompactWY(LAPACK.geqrt!(A, min(min(size(A)...), blocksize))...) elseif pivot === :colnorm @@ -298,7 +298,7 @@ Stacktrace: [...] ``` """ -@inline function qr!(A::AbstractMatrix, pivot::Symbol = :none) +Base.@aggressive_constprop function qr!(A::AbstractMatrix, pivot::Symbol = :none) if pivot === :none return qrfactUnblocked!(A) elseif pivot === :colnorm @@ -308,8 +308,8 @@ Stacktrace: end end # TODO: Remove/deprecate towards Julia v2.0 -@inline qr!(A::AbstractMatrix, ::Val{true}) = qr!(A, :colnorm) -@inline qr!(A::AbstractMatrix, ::Val{false}) = qr!(A, :none) +qr!(A::AbstractMatrix, ::Val{true}) = qr!(A, :colnorm) +qr!(A::AbstractMatrix, ::Val{false}) = qr!(A, :none) _qreltype(::Type{T}) where T = typeof(zero(T)/sqrt(abs2(one(T)))) @@ -391,14 +391,14 @@ true elementary reflectors, so that the `Q` and `R` matrices can be stored compactly rather as two separate dense matrices. """ -@inline function qr(A::AbstractMatrix{T}, arg...; kwargs...) where T +Base.@aggressive_constprop function qr(A::AbstractMatrix{T}, arg...; kwargs...) where T require_one_based_indexing(A) AA = similar(A, _qreltype(T), size(A)) copyto!(AA, A) return qr!(AA, arg...; kwargs...) end -@inline qr(A::AbstractMatrix, ::Val{false}; kwargs...) = qr(A, :none; kwargs...) -@inline qr(A::AbstractMatrix, ::Val{true}; kwargs...) = qr(A, :colnorm; kwargs...) +qr(A::AbstractMatrix, ::Val{false}; kwargs...) = qr(A, :none; kwargs...) +qr(A::AbstractMatrix, ::Val{true}; kwargs...) = qr(A, :colnorm; kwargs...) qr(x::Number) = qr(fill(x,1,1)) function qr(v::AbstractVector) From 9cbafa2744f0c96743c8afa8fa5876f8d021ae6e Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 6 May 2021 09:14:10 +0200 Subject: [PATCH 3/8] update docstrings --- stdlib/LinearAlgebra/src/lu.jl | 4 ++-- stdlib/LinearAlgebra/src/qr.jl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index a0e9789a26b06..caeb7d4a56695 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -97,7 +97,7 @@ lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = tr lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{false}; check::Bool = true) = lu!(A, :none; check=check) """ - lu!(A; pivot= :rowmax, check = true) -> LU + lu!(A, pivot = :rowmax; check = true) -> LU `lu!` is the same as [`lu`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. An [`InexactError`](@ref) @@ -224,7 +224,7 @@ validity (via [`issuccess`](@ref)) lies with the user. In most cases, if `A` is a subtype `S` of `AbstractMatrix{T}` with an element type `T` supporting `+`, `-`, `*` and `/`, the return type is `LU{T,S{T}}`. If pivoting is chosen (default) the element type should also support [`abs`](@ref) and -[`<`](@ref). +[`<`](@ref). Pivoting can be turned off by passing `pivot = :none`. The individual components of the factorization `F` can be accessed via [`getproperty`](@ref): diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 255dfdd1f5eed..705e09f60093f 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -261,8 +261,8 @@ end """ qr!(A, pivot = :none; blocksize) -`qr!` is the same as [`qr`](@ref) when `A` is a subtype of -[`StridedMatrix`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. +`qr!` is the same as [`qr`](@ref) when `A` is a subtype of [`StridedMatrix`](@ref), +but saves space by overwriting the input `A`, instead of creating a copy. An [`InexactError`](@ref) exception is thrown if the factorization produces a number not representable by the element type of `A`, e.g. for integer types. From 3576d495c7eb93ff5f6479ddf1d323ed018055f4 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 6 May 2021 11:33:20 +0200 Subject: [PATCH 4/8] update tests --- stdlib/LinearAlgebra/test/diagonal.jl | 2 +- stdlib/LinearAlgebra/test/generic.jl | 4 ++-- stdlib/LinearAlgebra/test/lq.jl | 2 +- stdlib/LinearAlgebra/test/lu.jl | 14 ++++++------ stdlib/LinearAlgebra/test/qr.jl | 25 ++++++++++++--------- stdlib/LinearAlgebra/test/special.jl | 4 ++-- stdlib/LinearAlgebra/test/uniformscaling.jl | 2 +- 7 files changed, 28 insertions(+), 25 deletions(-) diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index b6b52c0a0770c..4e9f4cda4b5b0 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -565,7 +565,7 @@ end D = Diagonal(randn(5)) Q = qr(randn(5, 5)).Q @test D * Q' == Array(D) * Q' - Q = qr(randn(5, 5), Val(true)).Q + Q = qr(randn(5, 5), :colnorm).Q @test_throws ArgumentError lmul!(Q, D) end diff --git a/stdlib/LinearAlgebra/test/generic.jl b/stdlib/LinearAlgebra/test/generic.jl index 92baaa6363b4f..710c7a34c2425 100644 --- a/stdlib/LinearAlgebra/test/generic.jl +++ b/stdlib/LinearAlgebra/test/generic.jl @@ -382,13 +382,13 @@ LinearAlgebra.Transpose(a::ModInt{n}) where {n} = transpose(a) A = [ModInt{2}(1) ModInt{2}(0); ModInt{2}(1) ModInt{2}(1)] b = [ModInt{2}(1), ModInt{2}(0)] - @test A*(lu(A, Val(false))\b) == b + @test A*(lu(A, :none)\b) == b # Needed for pivoting: Base.abs(a::ModInt{n}) where {n} = a Base.:<(a::ModInt{n}, b::ModInt{n}) where {n} = a.k < b.k - @test A*(lu(A, Val(true))\b) == b + @test A*(lu(A, :rowmax)\b) == b end @testset "Issue 18742" begin diff --git a/stdlib/LinearAlgebra/test/lq.jl b/stdlib/LinearAlgebra/test/lq.jl index 6e21b9ac6c1cc..18cf6bd8553c8 100644 --- a/stdlib/LinearAlgebra/test/lq.jl +++ b/stdlib/LinearAlgebra/test/lq.jl @@ -40,7 +40,7 @@ rectangularQ(Q::LinearAlgebra.LQPackedQ) = convert(Array, Q) lqa = lq(a) x = lqa\b l,q = lqa.L, lqa.Q - qra = qr(a, Val(true)) + qra = qr(a, :colnorm) @testset "Basic ops" begin @test size(lqa,1) == size(a,1) @test size(lqa,3) == 1 diff --git a/stdlib/LinearAlgebra/test/lu.jl b/stdlib/LinearAlgebra/test/lu.jl index c8366deafccdc..998ca380adc4d 100644 --- a/stdlib/LinearAlgebra/test/lu.jl +++ b/stdlib/LinearAlgebra/test/lu.jl @@ -229,12 +229,12 @@ end @test_throws SingularException lu!(copy(A); check = true) @test !issuccess(lu(A; check = false)) @test !issuccess(lu!(copy(A); check = false)) - @test_throws ZeroPivotException lu(A, Val(false)) - @test_throws ZeroPivotException lu!(copy(A), Val(false)) - @test_throws ZeroPivotException lu(A, Val(false); check = true) - @test_throws ZeroPivotException lu!(copy(A), Val(false); check = true) - @test !issuccess(lu(A, Val(false); check = false)) - @test !issuccess(lu!(copy(A), Val(false); check = false)) + @test_throws ZeroPivotException lu(A, :none) + @test_throws ZeroPivotException lu!(copy(A), :none) + @test_throws ZeroPivotException lu(A, :none; check = true) + @test_throws ZeroPivotException lu!(copy(A), :none; check = true) + @test !issuccess(lu(A, :none; check = false)) + @test !issuccess(lu!(copy(A), :none; check = false)) F = lu(A; check = false) @test sprint((io, x) -> show(io, "text/plain", x), F) == "Failed factorization of type $(typeof(F))" @@ -320,7 +320,7 @@ include("trickyarithmetic.jl") @testset "lu with type whose sum is another type" begin A = TrickyArithmetic.A[1 2; 3 4] ElT = TrickyArithmetic.D{TrickyArithmetic.C,TrickyArithmetic.C} - B = lu(A, Val(false)) + B = lu(A, :none) @test B isa LinearAlgebra.LU{ElT,Matrix{ElT}} end diff --git a/stdlib/LinearAlgebra/test/qr.jl b/stdlib/LinearAlgebra/test/qr.jl index 0f30770e082bb..4777520537f7e 100644 --- a/stdlib/LinearAlgebra/test/qr.jl +++ b/stdlib/LinearAlgebra/test/qr.jl @@ -77,8 +77,9 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test Base.propertynames(qra) == (:R, :Q) end @testset "Thin QR decomposition (without pivoting)" begin - qra = @inferred qr(a[:, 1:n1], Val(false)) - @inferred qr(a[:, 1:n1], Val(false)) + # test inference within function calls, otherwise const prop won't work + qrnone(A) = qr(A, :none) + qra = @inferred qrnone(a[:, 1:n1]) q,r = qra.Q, qra.R @test_throws ErrorException qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @@ -103,7 +104,9 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test Base.propertynames(qra) == (:R, :Q) end @testset "(Automatic) Fat (pivoted) QR decomposition" begin - @inferred qr(a, Val(true)) + qrcolnorm(A) = qr(A, :colnorm) + # test inference within function calls + @inferred qrcolnorm(a) qrpa = factorize(a[1:n1,:]) q,r = qrpa.Q, qrpa.R @@ -189,7 +192,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test mul!(c, b, q') ≈ b*q' @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n), q, b) - qra = qr(a[:,1:n1], Val(false)) + qra = qr(a[:,1:n1], :none) q, r = qra.Q, qra.R @test rmul!(copy(squareQ(q)'), q) ≈ Matrix(I, n, n) @test_throws DimensionMismatch rmul!(Matrix{eltya}(I, n+1, n+1),q) @@ -214,8 +217,8 @@ end @testset "transpose errors" begin @test_throws MethodError transpose(qr(randn(3,3))) @test_throws MethodError adjoint(qr(randn(3,3))) - @test_throws MethodError transpose(qr(randn(3,3), Val(false))) - @test_throws MethodError adjoint(qr(randn(3,3), Val(false))) + @test_throws MethodError transpose(qr(randn(3,3), :none)) + @test_throws MethodError adjoint(qr(randn(3,3), :none)) @test_throws MethodError transpose(qr(big.(randn(3,3)))) @test_throws MethodError adjoint(qr(big.(randn(3,3)))) end @@ -255,7 +258,7 @@ end A = zeros(1, 2) B = zeros(1, 1) @test A \ B == zeros(2, 1) - @test qr(A, Val(true)) \ B == zeros(2, 1) + @test qr(A, :colnorm) \ B == zeros(2, 1) end @testset "Issue 24107" begin @@ -277,7 +280,7 @@ end @test A \b ≈ ldiv!(c, qr(A ), b) @test b == b0 c0 = copy(c) - @test Ac\c ≈ ldiv!(b, qr(Ac, Val(true)), c) + @test Ac\c ≈ ldiv!(b, qr(Ac, :colnorm), c) @test c0 == c end @@ -294,11 +297,11 @@ end @testset "det(Q::Union{QRCompactWYQ, QRPackedQ})" begin # 40 is the number larger than the default block size 36 of QRCompactWY - @testset for n in [1:3; 40], m in [1:3; 40], pivot in [false, true] + @testset for n in [1:3; 40], m in [1:3; 40], pivot in (:none, :colnorm) @testset "real" begin @testset for k in 0:min(n, m, 5) A = cat(Array(I(k)), randn(n - k, m - k); dims=(1, 2)) - Q, = qr(A, Val(pivot)) + Q, = qr(A, pivot) @test det(Q) ≈ det(collect(Q)) @test abs(det(Q)) ≈ 1 end @@ -306,7 +309,7 @@ end @testset "complex" begin @testset for k in 0:min(n, m, 5) A = cat(Array(I(k)), randn(ComplexF64, n - k, m - k); dims=(1, 2)) - Q, = qr(A, Val(pivot)) + Q, = qr(A, pivot) @test det(Q) ≈ det(collect(Q)) @test abs(det(Q)) ≈ 1 end diff --git a/stdlib/LinearAlgebra/test/special.jl b/stdlib/LinearAlgebra/test/special.jl index c23371f3d072e..63a315d9b3e7c 100644 --- a/stdlib/LinearAlgebra/test/special.jl +++ b/stdlib/LinearAlgebra/test/special.jl @@ -192,10 +192,10 @@ end a = rand(n,n) atri = typ(a) b = rand(n,n) - qrb = qr(b,Val(true)) + qrb = qr(b, :colnorm) @test *(atri, adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' @test rmul!(copy(atri), adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' - qrb = qr(b,Val(false)) + qrb = qr(b, :none) @test *(atri, adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' @test rmul!(copy(atri), adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' end diff --git a/stdlib/LinearAlgebra/test/uniformscaling.jl b/stdlib/LinearAlgebra/test/uniformscaling.jl index b7b2e5c81cf88..d5a4ea3226a06 100644 --- a/stdlib/LinearAlgebra/test/uniformscaling.jl +++ b/stdlib/LinearAlgebra/test/uniformscaling.jl @@ -500,7 +500,7 @@ end @testset "Factorization solutions" begin J = complex(randn(),randn()) * I - qrp = A -> qr(A, Val(true)) + qrp = A -> qr(A, :colnorm) # thin matrices X = randn(3,2) From cafecbf4fef237849e79582ff71d2292f651e110 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 6 May 2021 11:47:24 +0200 Subject: [PATCH 5/8] add NEWS entry --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 93e3b6e523992..6073c60762234 100644 --- a/NEWS.md +++ b/NEWS.md @@ -103,6 +103,9 @@ Standard library changes * The shape of an `UpperHessenberg` matrix is preserved under certain arithmetic operations, e.g. when multiplying or dividing by an `UpperTriangular` matrix. ([#40039]) * `cis(A)` now supports matrix arguments ([#40194]). * `dot` now supports `UniformScaling` with `AbstractMatrix` ([#40250]). +* `qr[!]` and `lu[!]` now support `Symbol` values as their optional `pivot` argument: + defaults are `qr(A, :none)` (vs. `qr(A, :colnorm)` for pivoting) and `lu(A, :rowmax)` + (vs. `lu(A, :none)` without pivoting); the former `Val{true/false}`-based calls are deprecated. ([#40623]) #### Markdown From b8d5251255d1ac8aa8d91508900845c2f3a961d0 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 6 May 2021 11:49:17 +0200 Subject: [PATCH 6/8] deprecate previous behavior --- stdlib/LinearAlgebra/src/lu.jl | 12 ++++++------ stdlib/LinearAlgebra/src/qr.jl | 11 ++++++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index caeb7d4a56695..62a111da9cbd4 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -92,9 +92,9 @@ function lu!(A::HermOrSym, pivot::Symbol = :rowmax; check::Bool = true) lu!(A.data, pivot; check = check) end # for backward compatibility -# TODO: remove/deprecate towards Julia v2 -lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = true) = lu!(A, :rowmax; check=check) -lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{false}; check::Bool = true) = lu!(A, :none; check=check) +# TODO: remove towards Julia v2 +@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = true) lu!(A, :rowmax; check=check) +@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{false}; check::Bool = true) lu!(A, :none; check=check) """ lu!(A, pivot = :rowmax; check = true) -> LU @@ -284,9 +284,9 @@ function lu(A::AbstractMatrix{T}, pivot::Symbol = :rowmax; check::Bool = true) w S = lutype(T) lu!(copy_oftype(A, S), pivot; check = check) end -# TODO: remove/deprecate for Julia v2.0 -lu(A::AbstractMatrix, ::Val{true}; check::Bool = true) = lu(A, :rowmax; check=check) -lu(A::AbstractMatrix, ::Val{false}; check::Bool = true) = lu(A, :none; check=check) +# TODO: remove for Julia v2.0 +@deprecate lu(A::AbstractMatrix, ::Val{true}; check::Bool = true) lu(A, :rowmax; check=check) +@deprecate lu(A::AbstractMatrix, ::Val{false}; check::Bool = true) lu(A, :none; check=check) lu(S::LU) = S diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 705e09f60093f..635caa9bf3261 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -307,9 +307,9 @@ Base.@aggressive_constprop function qr!(A::AbstractMatrix, pivot::Symbol = :none throw(ArgumentError("only `:colnorm` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) end end -# TODO: Remove/deprecate towards Julia v2.0 -qr!(A::AbstractMatrix, ::Val{true}) = qr!(A, :colnorm) -qr!(A::AbstractMatrix, ::Val{false}) = qr!(A, :none) +# TODO: Remove in Julia v2.0 +@deprecate qr!(A::AbstractMatrix, ::Val{true}) qr!(A, :colnorm) +@deprecate qr!(A::AbstractMatrix, ::Val{false}) qr!(A, :none) _qreltype(::Type{T}) where T = typeof(zero(T)/sqrt(abs2(one(T)))) @@ -397,8 +397,9 @@ Base.@aggressive_constprop function qr(A::AbstractMatrix{T}, arg...; kwargs...) copyto!(AA, A) return qr!(AA, arg...; kwargs...) end -qr(A::AbstractMatrix, ::Val{false}; kwargs...) = qr(A, :none; kwargs...) -qr(A::AbstractMatrix, ::Val{true}; kwargs...) = qr(A, :colnorm; kwargs...) +# TODO: remove in Julia v2.0 +@deprecate qr(A::AbstractMatrix, ::Val{false}; kwargs...) qr(A, :none; kwargs...) +@deprecate qr(A::AbstractMatrix, ::Val{true}; kwargs...) qr(A, :colnorm; kwargs...) qr(x::Number) = qr(fill(x,1,1)) function qr(v::AbstractVector) From 4e8487bdc49418cf2557aa202c3d14932cb6a4f4 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Wed, 19 May 2021 17:59:55 +0200 Subject: [PATCH 7/8] use singleton types --- NEWS.md | 6 +- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 7 +++ stdlib/LinearAlgebra/src/dense.jl | 2 +- stdlib/LinearAlgebra/src/factorization.jl | 11 +--- stdlib/LinearAlgebra/src/generic.jl | 2 +- stdlib/LinearAlgebra/src/lu.jl | 63 ++++++++++----------- stdlib/LinearAlgebra/src/qr.jl | 42 +++++--------- stdlib/LinearAlgebra/test/diagonal.jl | 2 +- stdlib/LinearAlgebra/test/generic.jl | 4 +- stdlib/LinearAlgebra/test/lq.jl | 2 +- stdlib/LinearAlgebra/test/lu.jl | 16 +++--- stdlib/LinearAlgebra/test/qr.jl | 20 +++---- stdlib/LinearAlgebra/test/special.jl | 4 +- stdlib/LinearAlgebra/test/uniformscaling.jl | 2 +- 14 files changed, 83 insertions(+), 100 deletions(-) diff --git a/NEWS.md b/NEWS.md index 6073c60762234..9f108b43b36e3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -103,9 +103,9 @@ Standard library changes * The shape of an `UpperHessenberg` matrix is preserved under certain arithmetic operations, e.g. when multiplying or dividing by an `UpperTriangular` matrix. ([#40039]) * `cis(A)` now supports matrix arguments ([#40194]). * `dot` now supports `UniformScaling` with `AbstractMatrix` ([#40250]). -* `qr[!]` and `lu[!]` now support `Symbol` values as their optional `pivot` argument: - defaults are `qr(A, :none)` (vs. `qr(A, :colnorm)` for pivoting) and `lu(A, :rowmax)` - (vs. `lu(A, :none)` without pivoting); the former `Val{true/false}`-based calls are deprecated. ([#40623]) +* `qr[!]` and `lu[!]` now support `PivotingStrategy` values as their optional `pivot` argument: + defaults are `qr(A, NoPivot())` (vs. `qr(A, ColNorm())` for pivoting) and `lu(A, RowMax())` + (vs. `lu(A, NoPivot())` without pivoting); the former `Val{true/false}`-based calls are deprecated. ([#40623]) #### Markdown diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 855e49265af2d..325ce081acba9 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -35,6 +35,7 @@ export BunchKaufman, Cholesky, CholeskyPivoted, + ColNorm, Eigen, GeneralizedEigen, GeneralizedSVD, @@ -42,12 +43,14 @@ export Hessenberg, LU, LDLt, + NoPivot, QR, QRPivoted, LQ, Schur, SVD, Hermitian, + RowMax, Symmetric, LowerTriangular, UpperTriangular, @@ -164,6 +167,10 @@ abstract type Algorithm end struct DivideAndConquer <: Algorithm end struct QRIteration <: Algorithm end +abstract type PivotingStrategy end +struct NoPivot <: PivotingStrategy end +struct RowMax <: PivotingStrategy end +struct ColNorm <: PivotingStrategy end # Check that stride of matrix/vector is 1 # Writing like this to avoid splatting penalty when called with multiple arguments, diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index b1256ec45abde..d5499d8ed68ae 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -1371,7 +1371,7 @@ function factorize(A::StridedMatrix{T}) where T end return lu(A) end - qr(A, :colnorm) + qr(A, ColNorm()) end factorize(A::Adjoint) = adjoint(factorize(parent(A))) factorize(A::Transpose) = transpose(factorize(parent(A))) diff --git a/stdlib/LinearAlgebra/src/factorization.jl b/stdlib/LinearAlgebra/src/factorization.jl index c45adfa76406e..2f7e81946016a 100644 --- a/stdlib/LinearAlgebra/src/factorization.jl +++ b/stdlib/LinearAlgebra/src/factorization.jl @@ -16,14 +16,9 @@ size(F::Adjoint{<:Any,<:Factorization}) = reverse(size(parent(F))) size(F::Transpose{<:Any,<:Factorization}) = reverse(size(parent(F))) checkpositivedefinite(info) = info == 0 || throw(PosDefException(info)) -function checknonsingular(info, pivoted = :rowmax) - if info != 0 - pivoted === :rowmax && throw(SingularException(info)) - pivoted === :none && throw(ZeroPivotException(info)) - else - return nothing - end -end +checknonsingular(info, ::RowMax) = info == 0 || throw(SingularException(info)) +checknonsingular(info, ::NoPivot) = info == 0 || throw(ZeroPivotException(info)) +checknonsingular(info) = checknonsingular(info, RowMax()) """ issuccess(F::Factorization) diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index 2fed6e44baa89..0fdb58e262610 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -1141,7 +1141,7 @@ function (\)(A::AbstractMatrix, B::AbstractVecOrMat) end return lu(A) \ B end - return qr(A, :colnorm) \ B + return qr(A, ColNorm()) \ B end (\)(a::AbstractVector, b::AbstractArray) = pinv(a) * b diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index 62a111da9cbd4..59a421225badc 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -76,28 +76,26 @@ adjoint(F::LU) = Adjoint(F) transpose(F::LU) = Transpose(F) # StridedMatrix -function lu!(A::StridedMatrix{T}, pivot::Symbol = :rowmax; check::Bool = true) where {T<:BlasFloat} - if pivot === :none - return generic_lufact!(A, pivot; check = check) - elseif pivot === :rowmax - lpt = LAPACK.getrf!(A) - check && checknonsingular(lpt[3]) - return LU{T,typeof(A)}(lpt[1], lpt[2], lpt[3]) - else - throw(ArgumentError("only `:rowmax` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) - end +lu!(A::StridedMatrix{<:BlasFloat}; check::Bool = true) = lu!(A, RowMax(); check=check) +function lu!(A::StridedMatrix{T}, ::RowMax; check::Bool = true) where {T<:BlasFloat} + lpt = LAPACK.getrf!(A) + check && checknonsingular(lpt[3]) + return LU{T,typeof(A)}(lpt[1], lpt[2], lpt[3]) end -function lu!(A::HermOrSym, pivot::Symbol = :rowmax; check::Bool = true) +function lu!(A::StridedMatrix{<:BlasFloat}, pivot::NoPivot; check::Bool = true) + return generic_lufact!(A, pivot; check = check) +end +function lu!(A::HermOrSym, pivot::PivotingStrategy = RowMax(); check::Bool = true) copytri!(A.data, A.uplo, isa(A, Hermitian)) lu!(A.data, pivot; check = check) end # for backward compatibility # TODO: remove towards Julia v2 -@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = true) lu!(A, :rowmax; check=check) -@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{false}; check::Bool = true) lu!(A, :none; check=check) +@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = true) lu!(A, RowMax(); check=check) +@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{false}; check::Bool = true) lu!(A, NoPivot(); check=check) """ - lu!(A, pivot = :rowmax; check = true) -> LU + lu!(A, pivot = RowMax(); check = true) -> LU `lu!` is the same as [`lu`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. An [`InexactError`](@ref) @@ -133,18 +131,18 @@ Stacktrace: [...] ``` """ -lu!(A::StridedMatrix, pivot::Symbol = :rowmax; check::Bool = true) = +lu!(A::StridedMatrix, pivot::PivotingStrategy = RowMax(); check::Bool = true) = generic_lufact!(A, pivot; check = check) -function generic_lufact!(A::StridedMatrix{T}, pivot = :rowmax; check::Bool = true) where T - # Check arguments - if pivot !== :rowmax && pivot !== :none - throw(ArgumentError("only `rowmax` and `none` are supported as `pivot` argument but you supplied `$pivot`")) - end - +function generic_lufact!(A::StridedMatrix{T}, pivot::PivotingStrategy = RowMax(); + check::Bool = true) where {T} # Extract values m, n = size(A) minmn = min(m,n) + if pivot !== RowMax() && pivot !== NoPivot() + throw(ArgumentError("only `RowMax()` and `NoPivot()` are supported as `pivot` argument but you supplied `$pivot`")) + end + # Initialize variables info = 0 ipiv = Vector{BlasInt}(undef, minmn) @@ -152,7 +150,7 @@ function generic_lufact!(A::StridedMatrix{T}, pivot = :rowmax; check::Bool = tru for k = 1:minmn # find index max kp = k - if pivot === :rowmax && k < m + if pivot === RowMax() && k < m amax = abs(A[k, k]) for i = k+1:m absi = abs(A[i,k]) @@ -213,7 +211,7 @@ end # for all other types we must promote to a type which is stable under division """ - lu(A, pivot = :rowmax; check = true) -> F::LU + lu(A, pivot = RowMax(); check = true) -> F::LU Compute the LU factorization of `A`. @@ -224,7 +222,7 @@ validity (via [`issuccess`](@ref)) lies with the user. In most cases, if `A` is a subtype `S` of `AbstractMatrix{T}` with an element type `T` supporting `+`, `-`, `*` and `/`, the return type is `LU{T,S{T}}`. If pivoting is chosen (default) the element type should also support [`abs`](@ref) and -[`<`](@ref). Pivoting can be turned off by passing `pivot = :none`. +[`<`](@ref). Pivoting can be turned off by passing `pivot = NoPivot()`. The individual components of the factorization `F` can be accessed via [`getproperty`](@ref): @@ -280,13 +278,13 @@ julia> l == F.L && u == F.U && p == F.p true ``` """ -function lu(A::AbstractMatrix{T}, pivot::Symbol = :rowmax; check::Bool = true) where {T} +function lu(A::AbstractMatrix{T}, pivot::PivotingStrategy = RowMax(); check::Bool = true) where {T} S = lutype(T) lu!(copy_oftype(A, S), pivot; check = check) end # TODO: remove for Julia v2.0 -@deprecate lu(A::AbstractMatrix, ::Val{true}; check::Bool = true) lu(A, :rowmax; check=check) -@deprecate lu(A::AbstractMatrix, ::Val{false}; check::Bool = true) lu(A, :none; check=check) +@deprecate lu(A::AbstractMatrix, ::Val{true}; check::Bool = true) lu(A, RowMax(); check=check) +@deprecate lu(A::AbstractMatrix, ::Val{false}; check::Bool = true) lu(A, NoPivot(); check=check) lu(S::LU) = S @@ -497,13 +495,12 @@ inv(A::LU{<:BlasFloat,<:StridedMatrix}) = inv!(copy(A)) # Tridiagonal # See dgttrf.f -function lu!(A::Tridiagonal{T,V}, pivot::Symbol = :rowmax; check::Bool = true) where {T,V} +function lu!(A::Tridiagonal{T,V}, pivot::PivotingStrategy = RowMax(); check::Bool = true) where {T,V} # Extract values n = size(A, 1) - # Check arguments - if pivot !== :rowmax && pivot !== :none - throw(ArgumentError("only `:row` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) + if pivot !== RowMax() && pivot !== NoPivot() + throw(ArgumentError("only `RowMax()` and `NoPivot()` are supported as `pivot` argument but you supplied `$pivot`")) end # Initialize variables @@ -523,7 +520,7 @@ function lu!(A::Tridiagonal{T,V}, pivot::Symbol = :rowmax; check::Bool = true) w end for i = 1:n-2 # pivot or not? - if pivot === :none || abs(d[i]) >= abs(dl[i]) + if pivot === NoPivot() || abs(d[i]) >= abs(dl[i]) # No interchange if d[i] != 0 fact = dl[i]/d[i] @@ -546,7 +543,7 @@ function lu!(A::Tridiagonal{T,V}, pivot::Symbol = :rowmax; check::Bool = true) w end if n > 1 i = n-1 - if pivot === :none || abs(d[i]) >= abs(dl[i]) + if pivot === NoPivot() || abs(d[i]) >= abs(dl[i]) if d[i] != 0 fact = dl[i]/d[i] dl[i] = fact diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 635caa9bf3261..2e4c43fb3e48f 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -246,20 +246,14 @@ function qrfactPivotedUnblocked!(A::AbstractMatrix) end # LAPACK version -Base.@aggressive_constprop function qr!(A::StridedMatrix{<:BlasFloat}, pivot::Symbol = :none; blocksize=36) - if pivot === :none - return QRCompactWY(LAPACK.geqrt!(A, min(min(size(A)...), blocksize))...) - elseif pivot === :colnorm - return QRPivoted(LAPACK.geqp3!(A)...) - else - throw(ArgumentError("only `:colnorm` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) - end -end +qr!(A::StridedMatrix{<:BlasFloat}, ::NoPivot; blocksize=36) = + QRCompactWY(LAPACK.geqrt!(A, min(min(size(A)...), blocksize))...) +qr!(A::StridedMatrix{<:BlasFloat}, ::ColNorm) = QRPivoted(LAPACK.geqp3!(A)...) # Generic fallbacks """ - qr!(A, pivot = :none; blocksize) + qr!(A, pivot = NoPivot(); blocksize) `qr!` is the same as [`qr`](@ref) when `A` is a subtype of [`StridedMatrix`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. @@ -298,23 +292,17 @@ Stacktrace: [...] ``` """ -Base.@aggressive_constprop function qr!(A::AbstractMatrix, pivot::Symbol = :none) - if pivot === :none - return qrfactUnblocked!(A) - elseif pivot === :colnorm - return qrfactPivotedUnblocked!(A) - else - throw(ArgumentError("only `:colnorm` and `:none` are supported as `pivot` argument but you supplied `$pivot`")) - end -end +qr!(A::AbstractMatrix, ::NoPivot) = qrfactUnblocked!(A) +qr!(A::AbstractMatrix, ::ColNorm) = qrfactPivotedUnblocked!(A) +qr!(A::AbstractMatrix) = qr!(A, NoPivot()) # TODO: Remove in Julia v2.0 -@deprecate qr!(A::AbstractMatrix, ::Val{true}) qr!(A, :colnorm) -@deprecate qr!(A::AbstractMatrix, ::Val{false}) qr!(A, :none) +@deprecate qr!(A::AbstractMatrix, ::Val{true}) qr!(A, ColNorm()) +@deprecate qr!(A::AbstractMatrix, ::Val{false}) qr!(A, NoPivot()) _qreltype(::Type{T}) where T = typeof(zero(T)/sqrt(abs2(one(T)))) """ - qr(A, pivot = :none; blocksize) -> F + qr(A, pivot = NoPivot(); blocksize) -> F Compute the QR factorization of the matrix `A`: an orthogonal (or unitary if `A` is complex-valued) matrix `Q`, and an upper triangular matrix `R` such that @@ -325,7 +313,7 @@ A = Q R The returned object `F` stores the factorization in a packed format: - - if `pivot == :colnorm` then `F` is a [`QRPivoted`](@ref) object, + - if `pivot == ColNorm()` then `F` is a [`QRPivoted`](@ref) object, - otherwise if the element type of `A` is a BLAS type ([`Float32`](@ref), [`Float64`](@ref), `ComplexF32` or `ComplexF64`), then `F` is a [`QRCompactWY`](@ref) object, @@ -355,7 +343,7 @@ and `F.Q*A` are supported. A `Q` matrix can be converted into a regular matrix w orthogonal matrix. The block size for QR decomposition can be specified by keyword argument -`blocksize :: Integer` when `pivot == :none` and `A isa StridedMatrix{<:BlasFloat}`. +`blocksize :: Integer` when `pivot == NoPivot()` and `A isa StridedMatrix{<:BlasFloat}`. It is ignored when `blocksize > minimum(size(A))`. See [`QRCompactWY`](@ref). !!! compat "Julia 1.4" @@ -391,15 +379,15 @@ true elementary reflectors, so that the `Q` and `R` matrices can be stored compactly rather as two separate dense matrices. """ -Base.@aggressive_constprop function qr(A::AbstractMatrix{T}, arg...; kwargs...) where T +function qr(A::AbstractMatrix{T}, arg...; kwargs...) where T require_one_based_indexing(A) AA = similar(A, _qreltype(T), size(A)) copyto!(AA, A) return qr!(AA, arg...; kwargs...) end # TODO: remove in Julia v2.0 -@deprecate qr(A::AbstractMatrix, ::Val{false}; kwargs...) qr(A, :none; kwargs...) -@deprecate qr(A::AbstractMatrix, ::Val{true}; kwargs...) qr(A, :colnorm; kwargs...) +@deprecate qr(A::AbstractMatrix, ::Val{false}; kwargs...) qr(A, NoPivot(); kwargs...) +@deprecate qr(A::AbstractMatrix, ::Val{true}; kwargs...) qr(A, ColNorm(); kwargs...) qr(x::Number) = qr(fill(x,1,1)) function qr(v::AbstractVector) diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index 4e9f4cda4b5b0..2d60b487342ca 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -565,7 +565,7 @@ end D = Diagonal(randn(5)) Q = qr(randn(5, 5)).Q @test D * Q' == Array(D) * Q' - Q = qr(randn(5, 5), :colnorm).Q + Q = qr(randn(5, 5), ColNorm()).Q @test_throws ArgumentError lmul!(Q, D) end diff --git a/stdlib/LinearAlgebra/test/generic.jl b/stdlib/LinearAlgebra/test/generic.jl index 710c7a34c2425..f55eff180b282 100644 --- a/stdlib/LinearAlgebra/test/generic.jl +++ b/stdlib/LinearAlgebra/test/generic.jl @@ -382,13 +382,13 @@ LinearAlgebra.Transpose(a::ModInt{n}) where {n} = transpose(a) A = [ModInt{2}(1) ModInt{2}(0); ModInt{2}(1) ModInt{2}(1)] b = [ModInt{2}(1), ModInt{2}(0)] - @test A*(lu(A, :none)\b) == b + @test A*(lu(A, NoPivot())\b) == b # Needed for pivoting: Base.abs(a::ModInt{n}) where {n} = a Base.:<(a::ModInt{n}, b::ModInt{n}) where {n} = a.k < b.k - @test A*(lu(A, :rowmax)\b) == b + @test A*(lu(A, RowMax())\b) == b end @testset "Issue 18742" begin diff --git a/stdlib/LinearAlgebra/test/lq.jl b/stdlib/LinearAlgebra/test/lq.jl index 18cf6bd8553c8..c4717fa2f2ee4 100644 --- a/stdlib/LinearAlgebra/test/lq.jl +++ b/stdlib/LinearAlgebra/test/lq.jl @@ -40,7 +40,7 @@ rectangularQ(Q::LinearAlgebra.LQPackedQ) = convert(Array, Q) lqa = lq(a) x = lqa\b l,q = lqa.L, lqa.Q - qra = qr(a, :colnorm) + qra = qr(a, ColNorm()) @testset "Basic ops" begin @test size(lqa,1) == size(a,1) @test size(lqa,3) == 1 diff --git a/stdlib/LinearAlgebra/test/lu.jl b/stdlib/LinearAlgebra/test/lu.jl index 998ca380adc4d..6a1c34e511c2e 100644 --- a/stdlib/LinearAlgebra/test/lu.jl +++ b/stdlib/LinearAlgebra/test/lu.jl @@ -85,7 +85,7 @@ dimg = randn(n)/2 end κd = cond(Array(d),1) @testset "Tridiagonal LU" begin - lud = @inferred lu(d) + lud = @inferred lu(d) @test LinearAlgebra.issuccess(lud) @test @inferred(lu(lud)) == lud @test_throws ErrorException lud.Z @@ -229,12 +229,12 @@ end @test_throws SingularException lu!(copy(A); check = true) @test !issuccess(lu(A; check = false)) @test !issuccess(lu!(copy(A); check = false)) - @test_throws ZeroPivotException lu(A, :none) - @test_throws ZeroPivotException lu!(copy(A), :none) - @test_throws ZeroPivotException lu(A, :none; check = true) - @test_throws ZeroPivotException lu!(copy(A), :none; check = true) - @test !issuccess(lu(A, :none; check = false)) - @test !issuccess(lu!(copy(A), :none; check = false)) + @test_throws ZeroPivotException lu(A, NoPivot()) + @test_throws ZeroPivotException lu!(copy(A), NoPivot()) + @test_throws ZeroPivotException lu(A, NoPivot(); check = true) + @test_throws ZeroPivotException lu!(copy(A), NoPivot(); check = true) + @test !issuccess(lu(A, NoPivot(); check = false)) + @test !issuccess(lu!(copy(A), NoPivot(); check = false)) F = lu(A; check = false) @test sprint((io, x) -> show(io, "text/plain", x), F) == "Failed factorization of type $(typeof(F))" @@ -320,7 +320,7 @@ include("trickyarithmetic.jl") @testset "lu with type whose sum is another type" begin A = TrickyArithmetic.A[1 2; 3 4] ElT = TrickyArithmetic.D{TrickyArithmetic.C,TrickyArithmetic.C} - B = lu(A, :none) + B = lu(A, NoPivot()) @test B isa LinearAlgebra.LU{ElT,Matrix{ElT}} end diff --git a/stdlib/LinearAlgebra/test/qr.jl b/stdlib/LinearAlgebra/test/qr.jl index 4777520537f7e..69285772d385c 100644 --- a/stdlib/LinearAlgebra/test/qr.jl +++ b/stdlib/LinearAlgebra/test/qr.jl @@ -77,9 +77,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test Base.propertynames(qra) == (:R, :Q) end @testset "Thin QR decomposition (without pivoting)" begin - # test inference within function calls, otherwise const prop won't work - qrnone(A) = qr(A, :none) - qra = @inferred qrnone(a[:, 1:n1]) + qra = @inferred qr(a[:, 1:n1], NoPivot()) q,r = qra.Q, qra.R @test_throws ErrorException qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @@ -104,9 +102,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test Base.propertynames(qra) == (:R, :Q) end @testset "(Automatic) Fat (pivoted) QR decomposition" begin - qrcolnorm(A) = qr(A, :colnorm) - # test inference within function calls - @inferred qrcolnorm(a) + @inferred qr(a, ColNorm()) qrpa = factorize(a[1:n1,:]) q,r = qrpa.Q, qrpa.R @@ -192,7 +188,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test mul!(c, b, q') ≈ b*q' @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n), q, b) - qra = qr(a[:,1:n1], :none) + qra = qr(a[:,1:n1], NoPivot()) q, r = qra.Q, qra.R @test rmul!(copy(squareQ(q)'), q) ≈ Matrix(I, n, n) @test_throws DimensionMismatch rmul!(Matrix{eltya}(I, n+1, n+1),q) @@ -217,8 +213,8 @@ end @testset "transpose errors" begin @test_throws MethodError transpose(qr(randn(3,3))) @test_throws MethodError adjoint(qr(randn(3,3))) - @test_throws MethodError transpose(qr(randn(3,3), :none)) - @test_throws MethodError adjoint(qr(randn(3,3), :none)) + @test_throws MethodError transpose(qr(randn(3,3), NoPivot())) + @test_throws MethodError adjoint(qr(randn(3,3), NoPivot())) @test_throws MethodError transpose(qr(big.(randn(3,3)))) @test_throws MethodError adjoint(qr(big.(randn(3,3)))) end @@ -258,7 +254,7 @@ end A = zeros(1, 2) B = zeros(1, 1) @test A \ B == zeros(2, 1) - @test qr(A, :colnorm) \ B == zeros(2, 1) + @test qr(A, ColNorm()) \ B == zeros(2, 1) end @testset "Issue 24107" begin @@ -280,7 +276,7 @@ end @test A \b ≈ ldiv!(c, qr(A ), b) @test b == b0 c0 = copy(c) - @test Ac\c ≈ ldiv!(b, qr(Ac, :colnorm), c) + @test Ac\c ≈ ldiv!(b, qr(Ac, ColNorm()), c) @test c0 == c end @@ -297,7 +293,7 @@ end @testset "det(Q::Union{QRCompactWYQ, QRPackedQ})" begin # 40 is the number larger than the default block size 36 of QRCompactWY - @testset for n in [1:3; 40], m in [1:3; 40], pivot in (:none, :colnorm) + @testset for n in [1:3; 40], m in [1:3; 40], pivot in (NoPivot(), ColNorm()) @testset "real" begin @testset for k in 0:min(n, m, 5) A = cat(Array(I(k)), randn(n - k, m - k); dims=(1, 2)) diff --git a/stdlib/LinearAlgebra/test/special.jl b/stdlib/LinearAlgebra/test/special.jl index 63a315d9b3e7c..6632827703859 100644 --- a/stdlib/LinearAlgebra/test/special.jl +++ b/stdlib/LinearAlgebra/test/special.jl @@ -192,10 +192,10 @@ end a = rand(n,n) atri = typ(a) b = rand(n,n) - qrb = qr(b, :colnorm) + qrb = qr(b, ColNorm()) @test *(atri, adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' @test rmul!(copy(atri), adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' - qrb = qr(b, :none) + qrb = qr(b, NoPivot()) @test *(atri, adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' @test rmul!(copy(atri), adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' end diff --git a/stdlib/LinearAlgebra/test/uniformscaling.jl b/stdlib/LinearAlgebra/test/uniformscaling.jl index d5a4ea3226a06..d6542e2185be1 100644 --- a/stdlib/LinearAlgebra/test/uniformscaling.jl +++ b/stdlib/LinearAlgebra/test/uniformscaling.jl @@ -500,7 +500,7 @@ end @testset "Factorization solutions" begin J = complex(randn(),randn()) * I - qrp = A -> qr(A, :colnorm) + qrp = A -> qr(A, ColNorm()) # thin matrices X = randn(3,2) From 4549609e287c1f454ca994d0a65d223d7f1a5504 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 20 May 2021 10:34:36 +0200 Subject: [PATCH 8/8] more verbose type names --- NEWS.md | 7 +++-- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 8 +++--- stdlib/LinearAlgebra/src/dense.jl | 2 +- stdlib/LinearAlgebra/src/factorization.jl | 4 +-- stdlib/LinearAlgebra/src/generic.jl | 2 +- stdlib/LinearAlgebra/src/lu.jl | 32 ++++++++------------- stdlib/LinearAlgebra/src/qr.jl | 10 +++---- stdlib/LinearAlgebra/test/diagonal.jl | 2 +- stdlib/LinearAlgebra/test/generic.jl | 2 +- stdlib/LinearAlgebra/test/lq.jl | 2 +- stdlib/LinearAlgebra/test/qr.jl | 8 +++--- stdlib/LinearAlgebra/test/special.jl | 2 +- stdlib/LinearAlgebra/test/uniformscaling.jl | 2 +- 13 files changed, 38 insertions(+), 45 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9f108b43b36e3..d167490a575ef 100644 --- a/NEWS.md +++ b/NEWS.md @@ -103,9 +103,10 @@ Standard library changes * The shape of an `UpperHessenberg` matrix is preserved under certain arithmetic operations, e.g. when multiplying or dividing by an `UpperTriangular` matrix. ([#40039]) * `cis(A)` now supports matrix arguments ([#40194]). * `dot` now supports `UniformScaling` with `AbstractMatrix` ([#40250]). -* `qr[!]` and `lu[!]` now support `PivotingStrategy` values as their optional `pivot` argument: - defaults are `qr(A, NoPivot())` (vs. `qr(A, ColNorm())` for pivoting) and `lu(A, RowMax())` - (vs. `lu(A, NoPivot())` without pivoting); the former `Val{true/false}`-based calls are deprecated. ([#40623]) +* `qr[!]` and `lu[!]` now support `LinearAlgebra.PivotingStrategy` (singleton type) values + as their optional `pivot` argument: defaults are `qr(A, NoPivot())` (vs. + `qr(A, ColumnNorm())` for pivoting) and `lu(A, RowMaximum())` (vs. `lu(A, NoPivot())` + without pivoting); the former `Val{true/false}`-based calls are deprecated. ([#40623]) #### Markdown diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 325ce081acba9..d5a2a64467f93 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -35,7 +35,7 @@ export BunchKaufman, Cholesky, CholeskyPivoted, - ColNorm, + ColumnNorm, Eigen, GeneralizedEigen, GeneralizedSVD, @@ -50,7 +50,7 @@ export Schur, SVD, Hermitian, - RowMax, + RowMaximum, Symmetric, LowerTriangular, UpperTriangular, @@ -169,8 +169,8 @@ struct QRIteration <: Algorithm end abstract type PivotingStrategy end struct NoPivot <: PivotingStrategy end -struct RowMax <: PivotingStrategy end -struct ColNorm <: PivotingStrategy end +struct RowMaximum <: PivotingStrategy end +struct ColumnNorm <: PivotingStrategy end # Check that stride of matrix/vector is 1 # Writing like this to avoid splatting penalty when called with multiple arguments, diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index d5499d8ed68ae..4159525d07679 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -1371,7 +1371,7 @@ function factorize(A::StridedMatrix{T}) where T end return lu(A) end - qr(A, ColNorm()) + qr(A, ColumnNorm()) end factorize(A::Adjoint) = adjoint(factorize(parent(A))) factorize(A::Transpose) = transpose(factorize(parent(A))) diff --git a/stdlib/LinearAlgebra/src/factorization.jl b/stdlib/LinearAlgebra/src/factorization.jl index 2f7e81946016a..5ff215a3eb665 100644 --- a/stdlib/LinearAlgebra/src/factorization.jl +++ b/stdlib/LinearAlgebra/src/factorization.jl @@ -16,9 +16,9 @@ size(F::Adjoint{<:Any,<:Factorization}) = reverse(size(parent(F))) size(F::Transpose{<:Any,<:Factorization}) = reverse(size(parent(F))) checkpositivedefinite(info) = info == 0 || throw(PosDefException(info)) -checknonsingular(info, ::RowMax) = info == 0 || throw(SingularException(info)) +checknonsingular(info, ::RowMaximum) = info == 0 || throw(SingularException(info)) checknonsingular(info, ::NoPivot) = info == 0 || throw(ZeroPivotException(info)) -checknonsingular(info) = checknonsingular(info, RowMax()) +checknonsingular(info) = checknonsingular(info, RowMaximum()) """ issuccess(F::Factorization) diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index 0fdb58e262610..c5f21451cb2dd 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -1141,7 +1141,7 @@ function (\)(A::AbstractMatrix, B::AbstractVecOrMat) end return lu(A) \ B end - return qr(A, ColNorm()) \ B + return qr(A, ColumnNorm()) \ B end (\)(a::AbstractVector, b::AbstractArray) = pinv(a) * b diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index 59a421225badc..e55508db6b397 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -76,8 +76,8 @@ adjoint(F::LU) = Adjoint(F) transpose(F::LU) = Transpose(F) # StridedMatrix -lu!(A::StridedMatrix{<:BlasFloat}; check::Bool = true) = lu!(A, RowMax(); check=check) -function lu!(A::StridedMatrix{T}, ::RowMax; check::Bool = true) where {T<:BlasFloat} +lu!(A::StridedMatrix{<:BlasFloat}; check::Bool = true) = lu!(A, RowMaximum(); check=check) +function lu!(A::StridedMatrix{T}, ::RowMaximum; check::Bool = true) where {T<:BlasFloat} lpt = LAPACK.getrf!(A) check && checknonsingular(lpt[3]) return LU{T,typeof(A)}(lpt[1], lpt[2], lpt[3]) @@ -85,17 +85,17 @@ end function lu!(A::StridedMatrix{<:BlasFloat}, pivot::NoPivot; check::Bool = true) return generic_lufact!(A, pivot; check = check) end -function lu!(A::HermOrSym, pivot::PivotingStrategy = RowMax(); check::Bool = true) +function lu!(A::HermOrSym, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) copytri!(A.data, A.uplo, isa(A, Hermitian)) lu!(A.data, pivot; check = check) end # for backward compatibility # TODO: remove towards Julia v2 -@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = true) lu!(A, RowMax(); check=check) +@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = true) lu!(A, RowMaximum(); check=check) @deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{false}; check::Bool = true) lu!(A, NoPivot(); check=check) """ - lu!(A, pivot = RowMax(); check = true) -> LU + lu!(A, pivot = RowMaximum(); check = true) -> LU `lu!` is the same as [`lu`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. An [`InexactError`](@ref) @@ -131,18 +131,14 @@ Stacktrace: [...] ``` """ -lu!(A::StridedMatrix, pivot::PivotingStrategy = RowMax(); check::Bool = true) = +lu!(A::StridedMatrix, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) = generic_lufact!(A, pivot; check = check) -function generic_lufact!(A::StridedMatrix{T}, pivot::PivotingStrategy = RowMax(); +function generic_lufact!(A::StridedMatrix{T}, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) where {T} # Extract values m, n = size(A) minmn = min(m,n) - if pivot !== RowMax() && pivot !== NoPivot() - throw(ArgumentError("only `RowMax()` and `NoPivot()` are supported as `pivot` argument but you supplied `$pivot`")) - end - # Initialize variables info = 0 ipiv = Vector{BlasInt}(undef, minmn) @@ -150,7 +146,7 @@ function generic_lufact!(A::StridedMatrix{T}, pivot::PivotingStrategy = RowMax() for k = 1:minmn # find index max kp = k - if pivot === RowMax() && k < m + if pivot === RowMaximum() && k < m amax = abs(A[k, k]) for i = k+1:m absi = abs(A[i,k]) @@ -211,7 +207,7 @@ end # for all other types we must promote to a type which is stable under division """ - lu(A, pivot = RowMax(); check = true) -> F::LU + lu(A, pivot = RowMaximum(); check = true) -> F::LU Compute the LU factorization of `A`. @@ -278,12 +274,12 @@ julia> l == F.L && u == F.U && p == F.p true ``` """ -function lu(A::AbstractMatrix{T}, pivot::PivotingStrategy = RowMax(); check::Bool = true) where {T} +function lu(A::AbstractMatrix{T}, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) where {T} S = lutype(T) lu!(copy_oftype(A, S), pivot; check = check) end # TODO: remove for Julia v2.0 -@deprecate lu(A::AbstractMatrix, ::Val{true}; check::Bool = true) lu(A, RowMax(); check=check) +@deprecate lu(A::AbstractMatrix, ::Val{true}; check::Bool = true) lu(A, RowMaximum(); check=check) @deprecate lu(A::AbstractMatrix, ::Val{false}; check::Bool = true) lu(A, NoPivot(); check=check) @@ -495,14 +491,10 @@ inv(A::LU{<:BlasFloat,<:StridedMatrix}) = inv!(copy(A)) # Tridiagonal # See dgttrf.f -function lu!(A::Tridiagonal{T,V}, pivot::PivotingStrategy = RowMax(); check::Bool = true) where {T,V} +function lu!(A::Tridiagonal{T,V}, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) where {T,V} # Extract values n = size(A, 1) - if pivot !== RowMax() && pivot !== NoPivot() - throw(ArgumentError("only `RowMax()` and `NoPivot()` are supported as `pivot` argument but you supplied `$pivot`")) - end - # Initialize variables info = 0 ipiv = Vector{BlasInt}(undef, n) diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 2e4c43fb3e48f..390c8a5875773 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -248,7 +248,7 @@ end # LAPACK version qr!(A::StridedMatrix{<:BlasFloat}, ::NoPivot; blocksize=36) = QRCompactWY(LAPACK.geqrt!(A, min(min(size(A)...), blocksize))...) -qr!(A::StridedMatrix{<:BlasFloat}, ::ColNorm) = QRPivoted(LAPACK.geqp3!(A)...) +qr!(A::StridedMatrix{<:BlasFloat}, ::ColumnNorm) = QRPivoted(LAPACK.geqp3!(A)...) # Generic fallbacks @@ -293,10 +293,10 @@ Stacktrace: ``` """ qr!(A::AbstractMatrix, ::NoPivot) = qrfactUnblocked!(A) -qr!(A::AbstractMatrix, ::ColNorm) = qrfactPivotedUnblocked!(A) +qr!(A::AbstractMatrix, ::ColumnNorm) = qrfactPivotedUnblocked!(A) qr!(A::AbstractMatrix) = qr!(A, NoPivot()) # TODO: Remove in Julia v2.0 -@deprecate qr!(A::AbstractMatrix, ::Val{true}) qr!(A, ColNorm()) +@deprecate qr!(A::AbstractMatrix, ::Val{true}) qr!(A, ColumnNorm()) @deprecate qr!(A::AbstractMatrix, ::Val{false}) qr!(A, NoPivot()) _qreltype(::Type{T}) where T = typeof(zero(T)/sqrt(abs2(one(T)))) @@ -313,7 +313,7 @@ A = Q R The returned object `F` stores the factorization in a packed format: - - if `pivot == ColNorm()` then `F` is a [`QRPivoted`](@ref) object, + - if `pivot == ColumnNorm()` then `F` is a [`QRPivoted`](@ref) object, - otherwise if the element type of `A` is a BLAS type ([`Float32`](@ref), [`Float64`](@ref), `ComplexF32` or `ComplexF64`), then `F` is a [`QRCompactWY`](@ref) object, @@ -387,7 +387,7 @@ function qr(A::AbstractMatrix{T}, arg...; kwargs...) where T end # TODO: remove in Julia v2.0 @deprecate qr(A::AbstractMatrix, ::Val{false}; kwargs...) qr(A, NoPivot(); kwargs...) -@deprecate qr(A::AbstractMatrix, ::Val{true}; kwargs...) qr(A, ColNorm(); kwargs...) +@deprecate qr(A::AbstractMatrix, ::Val{true}; kwargs...) qr(A, ColumnNorm(); kwargs...) qr(x::Number) = qr(fill(x,1,1)) function qr(v::AbstractVector) diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index 2d60b487342ca..dcd82618c4968 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -565,7 +565,7 @@ end D = Diagonal(randn(5)) Q = qr(randn(5, 5)).Q @test D * Q' == Array(D) * Q' - Q = qr(randn(5, 5), ColNorm()).Q + Q = qr(randn(5, 5), ColumnNorm()).Q @test_throws ArgumentError lmul!(Q, D) end diff --git a/stdlib/LinearAlgebra/test/generic.jl b/stdlib/LinearAlgebra/test/generic.jl index f55eff180b282..0574523027d54 100644 --- a/stdlib/LinearAlgebra/test/generic.jl +++ b/stdlib/LinearAlgebra/test/generic.jl @@ -388,7 +388,7 @@ LinearAlgebra.Transpose(a::ModInt{n}) where {n} = transpose(a) Base.abs(a::ModInt{n}) where {n} = a Base.:<(a::ModInt{n}, b::ModInt{n}) where {n} = a.k < b.k - @test A*(lu(A, RowMax())\b) == b + @test A*(lu(A, RowMaximum())\b) == b end @testset "Issue 18742" begin diff --git a/stdlib/LinearAlgebra/test/lq.jl b/stdlib/LinearAlgebra/test/lq.jl index c4717fa2f2ee4..5161dc9e77047 100644 --- a/stdlib/LinearAlgebra/test/lq.jl +++ b/stdlib/LinearAlgebra/test/lq.jl @@ -40,7 +40,7 @@ rectangularQ(Q::LinearAlgebra.LQPackedQ) = convert(Array, Q) lqa = lq(a) x = lqa\b l,q = lqa.L, lqa.Q - qra = qr(a, ColNorm()) + qra = qr(a, ColumnNorm()) @testset "Basic ops" begin @test size(lqa,1) == size(a,1) @test size(lqa,3) == 1 diff --git a/stdlib/LinearAlgebra/test/qr.jl b/stdlib/LinearAlgebra/test/qr.jl index 69285772d385c..16f828b4f8861 100644 --- a/stdlib/LinearAlgebra/test/qr.jl +++ b/stdlib/LinearAlgebra/test/qr.jl @@ -102,7 +102,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test Base.propertynames(qra) == (:R, :Q) end @testset "(Automatic) Fat (pivoted) QR decomposition" begin - @inferred qr(a, ColNorm()) + @inferred qr(a, ColumnNorm()) qrpa = factorize(a[1:n1,:]) q,r = qrpa.Q, qrpa.R @@ -254,7 +254,7 @@ end A = zeros(1, 2) B = zeros(1, 1) @test A \ B == zeros(2, 1) - @test qr(A, ColNorm()) \ B == zeros(2, 1) + @test qr(A, ColumnNorm()) \ B == zeros(2, 1) end @testset "Issue 24107" begin @@ -276,7 +276,7 @@ end @test A \b ≈ ldiv!(c, qr(A ), b) @test b == b0 c0 = copy(c) - @test Ac\c ≈ ldiv!(b, qr(Ac, ColNorm()), c) + @test Ac\c ≈ ldiv!(b, qr(Ac, ColumnNorm()), c) @test c0 == c end @@ -293,7 +293,7 @@ end @testset "det(Q::Union{QRCompactWYQ, QRPackedQ})" begin # 40 is the number larger than the default block size 36 of QRCompactWY - @testset for n in [1:3; 40], m in [1:3; 40], pivot in (NoPivot(), ColNorm()) + @testset for n in [1:3; 40], m in [1:3; 40], pivot in (NoPivot(), ColumnNorm()) @testset "real" begin @testset for k in 0:min(n, m, 5) A = cat(Array(I(k)), randn(n - k, m - k); dims=(1, 2)) diff --git a/stdlib/LinearAlgebra/test/special.jl b/stdlib/LinearAlgebra/test/special.jl index 6632827703859..48cb65e33eb74 100644 --- a/stdlib/LinearAlgebra/test/special.jl +++ b/stdlib/LinearAlgebra/test/special.jl @@ -192,7 +192,7 @@ end a = rand(n,n) atri = typ(a) b = rand(n,n) - qrb = qr(b, ColNorm()) + qrb = qr(b, ColumnNorm()) @test *(atri, adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' @test rmul!(copy(atri), adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' qrb = qr(b, NoPivot()) diff --git a/stdlib/LinearAlgebra/test/uniformscaling.jl b/stdlib/LinearAlgebra/test/uniformscaling.jl index d6542e2185be1..8c69308d06ce8 100644 --- a/stdlib/LinearAlgebra/test/uniformscaling.jl +++ b/stdlib/LinearAlgebra/test/uniformscaling.jl @@ -500,7 +500,7 @@ end @testset "Factorization solutions" begin J = complex(randn(),randn()) * I - qrp = A -> qr(A, ColNorm()) + qrp = A -> qr(A, ColumnNorm()) # thin matrices X = randn(3,2)