From bc28fbf61b12b6d32f8c0c8a1b916bd5fee338cf Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Mon, 11 Dec 2017 20:40:24 +0100 Subject: [PATCH 1/4] rename LinAlg.fillslots! LinAlg.fillstored! --- NEWS.md | 4 +++- base/deprecated.jl | 7 +++++-- base/linalg/bidiag.jl | 4 ++-- test/linalg/bidiag.jl | 24 ++++++++++++------------ 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/NEWS.md b/NEWS.md index 7d1277a02dc3a..c59ce539d679c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -465,8 +465,10 @@ Deprecated or removed `Matrix{Int}(uninitialized, (2, 4))`, and `Array{Float32,3}(11, 13, 17)` is now `Array{Float32,3}(uninitialized, 11, 13, 17)` ([#24781]). + * `LinAlg.fillslots!` has been renamed `LinAlg.fillstored!` ([#25030]). + * `fill!(A::Diagonal, x)` and `fill!(A::AbstractTriangular, x)` have been deprecated - in favor of `Base.LinAlg.fillslots!(A, x)` ([#24413]). + in favor of `Base.LinAlg.fillstored!(A, x)` ([#24413]). * `eye` has been deprecated in favor of `I` and `Matrix` constructors. Please see the deprecation warnings for replacement details ([#24438]). diff --git a/base/deprecated.jl b/base/deprecated.jl index bc953759b22f9..54fad39fb051a 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1855,8 +1855,11 @@ end # Also un-comment the new definition in base/indices.jl # deprecate odd fill! methods -@deprecate fill!(D::Diagonal, x) LinAlg.fillslots!(D, x) -@deprecate fill!(A::Base.LinAlg.AbstractTriangular, x) LinAlg.fillslots!(A, x) +@deprecate fill!(D::Diagonal, x) LinAlg.fillstored!(D, x) +@deprecate fill!(A::Base.LinAlg.AbstractTriangular, x) LinAlg.fillstored!(A, x) + +# PR #25030 +@eval LinAlg @deprecate fillslots! fillstored! false function diagm(v::BitVector) depwarn(string("diagm(v::BitVector) is deprecated, use diagm(0 => v) or ", diff --git a/base/linalg/bidiag.jl b/base/linalg/bidiag.jl index 9a42b278f431f..b527e86456851 100644 --- a/base/linalg/bidiag.jl +++ b/base/linalg/bidiag.jl @@ -646,7 +646,7 @@ _valuefields(::Type{<:AbstractTriangular}) = [:data] const SpecialArrays = Union{Diagonal,Bidiagonal,Tridiagonal,SymTridiagonal,AbstractTriangular} -function fillslots!(A::SpecialArrays, x) +function fillstored!(A::SpecialArrays, x) xT = convert(eltype(A), x) if @generated quote @@ -666,7 +666,7 @@ _small_enough(A::SymTridiagonal) = size(A, 1) <= 2 function fill!(A::Union{Bidiagonal,Tridiagonal,SymTridiagonal}, x) xT = convert(eltype(A), x) - (xT == zero(eltype(A)) || _small_enough(A)) && return fillslots!(A, xT) + (xT == zero(eltype(A)) || _small_enough(A)) && return fillstored!(A, xT) throw(ArgumentError("array A of type $(typeof(A)) and size $(size(A)) can not be filled with x=$x, since some of its entries are constrained.")) end diff --git a/test/linalg/bidiag.jl b/test/linalg/bidiag.jl index 94c749d6531c2..00c74bbdf7aa9 100644 --- a/test/linalg/bidiag.jl +++ b/test/linalg/bidiag.jl @@ -310,18 +310,18 @@ end @test promote(C,A) isa Tuple{Tridiagonal, Tridiagonal} end -import Base.LinAlg: fillslots!, UnitLowerTriangular -@testset "fill! and fillslots!" begin +import Base.LinAlg: fillstored!, UnitLowerTriangular +@testset "fill! and fillstored!" begin let #fill! - let # fillslots! + let # fillstored! A = Tridiagonal(randn(2), randn(3), randn(2)) - @test fillslots!(A, 3) == Tridiagonal([3, 3.], [3, 3, 3.], [3, 3.]) + @test fillstored!(A, 3) == Tridiagonal([3, 3.], [3, 3, 3.], [3, 3.]) B = Bidiagonal(randn(3), randn(2), :U) - @test fillslots!(B, 2) == Bidiagonal([2.,2,2], [2,2.], :U) + @test fillstored!(B, 2) == Bidiagonal([2.,2,2], [2,2.], :U) S = SymTridiagonal(randn(3), randn(2)) - @test fillslots!(S, 1) == SymTridiagonal([1,1,1.], [1,1.]) + @test fillstored!(S, 1) == SymTridiagonal([1,1,1.], [1,1.]) Ult = UnitLowerTriangular(randn(3,3)) - @test fillslots!(Ult, 3) == UnitLowerTriangular([1 0 0; 3 1 0; 3 3 1]) + @test fillstored!(Ult, 3) == UnitLowerTriangular([1 0 0; 3 1 0; 3 3 1]) end let # fill!(exotic, 0) exotic_arrays = Any[Tridiagonal(randn(3), randn(4), randn(3)), @@ -339,14 +339,14 @@ import Base.LinAlg: fillslots!, UnitLowerTriangular @test a == 0 end end - # Diagonal and AbstractTriangular fill! were defined as fillslots!, + # Diagonal and AbstractTriangular fill! were defined as fillstored!, # not matching the general behavior of fill!, and so have been deprecated. # In a future dev cycle, these fill! methods should probably be reintroduced # with behavior matching that of fill! for other structured matrix types. - # In the interm, equivalently test fillslots! below - @test iszero(fillslots!(Diagonal(fill(1, 3)), 0)) - @test iszero(fillslots!(LowerTriangular(fill(1, 3, 3)), 0)) - @test iszero(fillslots!(UpperTriangular(fill(1, 3, 3)), 0)) + # In the interm, equivalently test fillstored! below + @test iszero(fillstored!(Diagonal(fill(1, 3)), 0)) + @test iszero(fillstored!(LowerTriangular(fill(1, 3, 3)), 0)) + @test iszero(fillstored!(UpperTriangular(fill(1, 3, 3)), 0)) end let # fill!(small, x) val = randn() From 197ada2a8aff3d30e616600cc8911b154e6a273f Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Mon, 11 Dec 2017 21:55:55 +0100 Subject: [PATCH 2/4] rewrite fillstored!(::SpecialMatrix, x) without generated function move implementations to more suitable places --- base/linalg/bidiag.jl | 34 -------------- base/linalg/special.jl | 18 ++++++++ base/linalg/triangular.jl | 2 + test/linalg/bidiag.jl | 96 +++++++++++++++++++-------------------- 4 files changed, 67 insertions(+), 83 deletions(-) diff --git a/base/linalg/bidiag.jl b/base/linalg/bidiag.jl index b527e86456851..4d5635a19727c 100644 --- a/base/linalg/bidiag.jl +++ b/base/linalg/bidiag.jl @@ -636,37 +636,3 @@ function eigvecs(M::Bidiagonal{T}) where T Q #Actually Triangular end eigfact(M::Bidiagonal) = Eigen(eigvals(M), eigvecs(M)) - -# fill! methods -_valuefields(::Type{<:Diagonal}) = [:diag] -_valuefields(::Type{<:Bidiagonal}) = [:dv, :ev] -_valuefields(::Type{<:Tridiagonal}) = [:dl, :d, :du] -_valuefields(::Type{<:SymTridiagonal}) = [:dv, :ev] -_valuefields(::Type{<:AbstractTriangular}) = [:data] - -const SpecialArrays = Union{Diagonal,Bidiagonal,Tridiagonal,SymTridiagonal,AbstractTriangular} - -function fillstored!(A::SpecialArrays, x) - xT = convert(eltype(A), x) - if @generated - quote - $([ :(fill!(A.$field, xT)) for field in _valuefields(A) ]...) - end - else - for field in _valuefields(A) - fill!(getfield(A, field), xT) - end - end - return A -end - -_small_enough(A::Bidiagonal) = size(A, 1) <= 1 -_small_enough(A::Tridiagonal) = size(A, 1) <= 2 -_small_enough(A::SymTridiagonal) = size(A, 1) <= 2 - -function fill!(A::Union{Bidiagonal,Tridiagonal,SymTridiagonal}, x) - xT = convert(eltype(A), x) - (xT == zero(eltype(A)) || _small_enough(A)) && return fillstored!(A, xT) - throw(ArgumentError("array A of type $(typeof(A)) and size $(size(A)) can - not be filled with x=$x, since some of its entries are constrained.")) -end diff --git a/base/linalg/special.jl b/base/linalg/special.jl index 2a751008e1869..e4fab76829250 100644 --- a/base/linalg/special.jl +++ b/base/linalg/special.jl @@ -126,3 +126,21 @@ mul!(A::AbstractTriangular, adjB::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}} (B = adjB.parent; mul!(full!(A), Adjoint(B))) *(A::AbstractTriangular, adjB::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) = (B = adjB.parent; *(copy!(similar(parent(A)), A), Adjoint(B))) + +# fill[stored]! methods +fillstored!(A::Diagonal, x) = (fill!(A.diag, x); A) +fillstored!(A::Bidiagonal, x) = (fill!(A.dv, x); fill!(A.ev, x); A) +fillstored!(A::Tridiagonal, x) = (fill!(A.dl, x); fill!(A.d, x); fill!(A.du, x); A) +fillstored!(A::SymTridiagonal, x) = (fill!(A.dv, x); fill!(A.ev, x); A) + +_small_enough(A::Bidiagonal) = size(A, 1) <= 1 +_small_enough(A::Tridiagonal) = size(A, 1) <= 2 +_small_enough(A::SymTridiagonal) = size(A, 1) <= 2 + +# TODO: Add Diagonal to this method when 0.7 deprecations are removed +function fill!(A::Union{Bidiagonal,Tridiagonal,SymTridiagonal}, x) + xT = convert(eltype(A), x) + (iszero(xT) || _small_enough(A)) && return fillstored!(A, xT) + throw(ArgumentError("array of type $(typeof(A)) and size $(size(A)) can + not be filled with x=$x, since some of its entries are constrained.")) +end diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index 30807f2011664..24f9f7cab9de5 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -418,6 +418,8 @@ end scale!(A::Union{UpperTriangular,LowerTriangular}, c::Number) = scale!(A,A,c) scale!(c::Number, A::Union{UpperTriangular,LowerTriangular}) = scale!(A,c) +fillstored!(A::AbstractTriangular, x) = (fill!(A.data, x); A) + # Binary operations +(A::UpperTriangular, B::UpperTriangular) = UpperTriangular(A.data + B.data) +(A::LowerTriangular, B::LowerTriangular) = LowerTriangular(A.data + B.data) diff --git a/test/linalg/bidiag.jl b/test/linalg/bidiag.jl index 00c74bbdf7aa9..f262cbe862bac 100644 --- a/test/linalg/bidiag.jl +++ b/test/linalg/bidiag.jl @@ -310,58 +310,56 @@ end @test promote(C,A) isa Tuple{Tridiagonal, Tridiagonal} end -import Base.LinAlg: fillstored!, UnitLowerTriangular +using Base.LinAlg: fillstored!, UnitLowerTriangular @testset "fill! and fillstored!" begin - let #fill! - let # fillstored! - A = Tridiagonal(randn(2), randn(3), randn(2)) - @test fillstored!(A, 3) == Tridiagonal([3, 3.], [3, 3, 3.], [3, 3.]) - B = Bidiagonal(randn(3), randn(2), :U) - @test fillstored!(B, 2) == Bidiagonal([2.,2,2], [2,2.], :U) - S = SymTridiagonal(randn(3), randn(2)) - @test fillstored!(S, 1) == SymTridiagonal([1,1,1.], [1,1.]) - Ult = UnitLowerTriangular(randn(3,3)) - @test fillstored!(Ult, 3) == UnitLowerTriangular([1 0 0; 3 1 0; 3 3 1]) - end - let # fill!(exotic, 0) - exotic_arrays = Any[Tridiagonal(randn(3), randn(4), randn(3)), - Bidiagonal(randn(3), randn(2), rand([:U,:L])), - SymTridiagonal(randn(3), randn(2)), - sparse(randn(3,4)), - # Diagonal(randn(5)), # Diagonal fill! deprecated, see below - sparse(rand(3)), - # LowerTriangular(randn(3,3)), # AbstractTriangular fill! deprecated, see below - # UpperTriangular(randn(3,3)) # AbstractTriangular fill! deprecated, see below - ] - for A in exotic_arrays - fill!(A, 0) - for a in A - @test a == 0 - end + let # fillstored! + A = Tridiagonal(randn(2), randn(3), randn(2)) + @test fillstored!(A, 3) == Tridiagonal([3, 3.], [3, 3, 3.], [3, 3.]) + B = Bidiagonal(randn(3), randn(2), :U) + @test fillstored!(B, 2) == Bidiagonal([2.,2,2], [2,2.], :U) + S = SymTridiagonal(randn(3), randn(2)) + @test fillstored!(S, 1) == SymTridiagonal([1,1,1.], [1,1.]) + Ult = UnitLowerTriangular(randn(3,3)) + @test fillstored!(Ult, 3) == UnitLowerTriangular([1 0 0; 3 1 0; 3 3 1]) + end + let # fill!(exotic, 0) + exotic_arrays = Any[Tridiagonal(randn(3), randn(4), randn(3)), + Bidiagonal(randn(3), randn(2), rand([:U,:L])), + SymTridiagonal(randn(3), randn(2)), + sparse(randn(3,4)), + # Diagonal(randn(5)), # Diagonal fill! deprecated, see below + sparse(rand(3)), + # LowerTriangular(randn(3,3)), # AbstractTriangular fill! deprecated, see below + # UpperTriangular(randn(3,3)) # AbstractTriangular fill! deprecated, see below + ] + for A in exotic_arrays + fill!(A, 0) + for a in A + @test a == 0 end - # Diagonal and AbstractTriangular fill! were defined as fillstored!, - # not matching the general behavior of fill!, and so have been deprecated. - # In a future dev cycle, these fill! methods should probably be reintroduced - # with behavior matching that of fill! for other structured matrix types. - # In the interm, equivalently test fillstored! below - @test iszero(fillstored!(Diagonal(fill(1, 3)), 0)) - @test iszero(fillstored!(LowerTriangular(fill(1, 3, 3)), 0)) - @test iszero(fillstored!(UpperTriangular(fill(1, 3, 3)), 0)) end - let # fill!(small, x) - val = randn() - b = Bidiagonal(randn(1,1), :U) - st = SymTridiagonal(randn(1,1)) - for x in (b, st) - @test Array(fill!(x, val)) == fill!(Array(x), val) - end - b = Bidiagonal(randn(2,2), :U) - st = SymTridiagonal(randn(3), randn(2)) - t = Tridiagonal(randn(3,3)) - for x in (b, t, st) - @test_throws ArgumentError fill!(x, val) - @test Array(fill!(x, 0)) == fill!(Array(x), 0) - end + # Diagonal and AbstractTriangular fill! were defined as fillstored!, + # not matching the general behavior of fill!, and so have been deprecated. + # In a future dev cycle, these fill! methods should probably be reintroduced + # with behavior matching that of fill! for other structured matrix types. + # In the interm, equivalently test fillstored! below + @test iszero(fillstored!(Diagonal(fill(1, 3)), 0)) + @test iszero(fillstored!(LowerTriangular(fill(1, 3, 3)), 0)) + @test iszero(fillstored!(UpperTriangular(fill(1, 3, 3)), 0)) + end + let # fill!(small, x) + val = randn() + b = Bidiagonal(randn(1,1), :U) + st = SymTridiagonal(randn(1,1)) + for x in (b, st) + @test Array(fill!(x, val)) == fill!(Array(x), val) + end + b = Bidiagonal(randn(2,2), :U) + st = SymTridiagonal(randn(3), randn(2)) + t = Tridiagonal(randn(3,3)) + for x in (b, t, st) + @test_throws ArgumentError fill!(x, val) + @test Array(fill!(x, 0)) == fill!(Array(x), 0) end end end From 893281d27482e7b17ccc3067ed5b38ad5007be82 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Wed, 13 Dec 2017 22:14:57 +0100 Subject: [PATCH 3/4] implement fillband! and call it from fillstored!(::AbstractTriangular) --- base/linalg/dense.jl | 16 ++++++++++++++++ base/linalg/triangular.jl | 5 ++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/base/linalg/dense.jl b/base/linalg/dense.jl index 1adbfc683ce78..bab1093716979 100644 --- a/base/linalg/dense.jl +++ b/base/linalg/dense.jl @@ -242,6 +242,22 @@ function tril!(M::AbstractMatrix, k::Integer) end tril(M::Matrix, k::Integer) = tril!(copy(M), k) +""" + fillband!(A::AbstractMatrix, x, l, u) + +Fill the band between diagonals `l` and `u` with the value `x`. +""" +function fillband!(A::AbstractMatrix{T}, x, l, u) where T + m, n = size(A) + xT = convert(T, x) + for j in 1:n + for i in max(1,j-u):min(m,j-l) + @inbounds A[i, j] = xT + end + end + return A +end + function diagind(m::Integer, n::Integer, k::Integer=0) if !(-m <= k <= n) throw(ArgumentError(string("requested diagonal, $k, must be at least $(-m) and ", diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index 24f9f7cab9de5..b1472887ca1b9 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -418,7 +418,10 @@ end scale!(A::Union{UpperTriangular,LowerTriangular}, c::Number) = scale!(A,A,c) scale!(c::Number, A::Union{UpperTriangular,LowerTriangular}) = scale!(A,c) -fillstored!(A::AbstractTriangular, x) = (fill!(A.data, x); A) +fillstored!(A::LowerTriangular, x) = (fillband!(A.data, x, 1-size(A,1), 0); A) +fillstored!(A::UnitLowerTriangular, x) = (fillband!(A.data, x, 1-size(A,1), -1); A) +fillstored!(A::UpperTriangular, x) = (fillband!(A.data, x, 0, size(A,2)-1); A) +fillstored!(A::UnitUpperTriangular, x) = (fillband!(A.data, x, 1, size(A,2)-1); A) # Binary operations +(A::UpperTriangular, B::UpperTriangular) = UpperTriangular(A.data + B.data) From 69369a7bde59cf3008db2f752835179459f1ff53 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 14 Dec 2017 08:06:45 +0100 Subject: [PATCH 4/4] review fixes --- base/linalg/special.jl | 2 +- test/linalg/bidiag.jl | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/base/linalg/special.jl b/base/linalg/special.jl index e4fab76829250..92a4b5ebba0e0 100644 --- a/base/linalg/special.jl +++ b/base/linalg/special.jl @@ -142,5 +142,5 @@ function fill!(A::Union{Bidiagonal,Tridiagonal,SymTridiagonal}, x) xT = convert(eltype(A), x) (iszero(xT) || _small_enough(A)) && return fillstored!(A, xT) throw(ArgumentError("array of type $(typeof(A)) and size $(size(A)) can - not be filled with x=$x, since some of its entries are constrained.")) + not be filled with $x, since some of its entries are constrained.")) end diff --git a/test/linalg/bidiag.jl b/test/linalg/bidiag.jl index f262cbe862bac..6fbe671a6b262 100644 --- a/test/linalg/bidiag.jl +++ b/test/linalg/bidiag.jl @@ -314,11 +314,11 @@ using Base.LinAlg: fillstored!, UnitLowerTriangular @testset "fill! and fillstored!" begin let # fillstored! A = Tridiagonal(randn(2), randn(3), randn(2)) - @test fillstored!(A, 3) == Tridiagonal([3, 3.], [3, 3, 3.], [3, 3.]) + @test fillstored!(A, 3) == Tridiagonal([3, 3], [3, 3, 3], [3, 3]) B = Bidiagonal(randn(3), randn(2), :U) - @test fillstored!(B, 2) == Bidiagonal([2.,2,2], [2,2.], :U) + @test fillstored!(B, 2) == Bidiagonal([2,2,2], [2,2], :U) S = SymTridiagonal(randn(3), randn(2)) - @test fillstored!(S, 1) == SymTridiagonal([1,1,1.], [1,1.]) + @test fillstored!(S, 1) == SymTridiagonal([1,1,1], [1,1]) Ult = UnitLowerTriangular(randn(3,3)) @test fillstored!(Ult, 3) == UnitLowerTriangular([1 0 0; 3 1 0; 3 3 1]) end @@ -333,10 +333,7 @@ using Base.LinAlg: fillstored!, UnitLowerTriangular # UpperTriangular(randn(3,3)) # AbstractTriangular fill! deprecated, see below ] for A in exotic_arrays - fill!(A, 0) - for a in A - @test a == 0 - end + @test iszero(fill!(A, 0)) end # Diagonal and AbstractTriangular fill! were defined as fillstored!, # not matching the general behavior of fill!, and so have been deprecated.