From 6177b3bed522fc90cd30eb3d479abf5095d55ff4 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Tue, 11 Jul 2017 01:29:57 +0200 Subject: [PATCH] parametrize Bidiagonal on wrapped vector type --- NEWS.md | 10 +++--- base/linalg/bidiag.jl | 38 ++++++++++++----------- base/test.jl | 4 +++ test/linalg/bidiag.jl | 71 +++++++++++++++++++++++++++++++------------ test/show.jl | 4 +-- 5 files changed, 85 insertions(+), 42 deletions(-) diff --git a/NEWS.md b/NEWS.md index 2ea0e333ddd0ae..7b7b9e5f7c5a1a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -73,8 +73,9 @@ This section lists changes that do not have deprecation warnings. longer present. Use `first(R)` and `last(R)` to obtain start/stop. ([#20974]) - * The `Diagonal` type definition has changed from `Diagonal{T}` to - `Diagonal{T,V<:AbstractVector{T}}` ([#22718]). + * The `Diagonal` and `Bidiagonal` type definitions have changed from `Diagonal{T}` and + `Bidiagonal{T}` to `Diagonal{T,V<:AbstractVector{T}}` and + `Bidiagonal{T,V<:AbstractVector{T}}` respectively ([#22718], [#22925]). * Spaces are no longer allowed between `@` and the name of a macro in a macro call ([#22868]). @@ -142,8 +143,9 @@ Library improvements * `Char`s can now be concatenated with `String`s and/or other `Char`s using `*` ([#22532]). - * `Diagonal` is now parameterized on the type of the wrapped vector. This allows - for `Diagonal` matrices with arbitrary `AbstractVector`s ([#22718]). + * `Diagonal` and `Bidiagonal` are now parameterized on the type of the wrapped vectors, + allowing `Diagonal` and `Bidiagonal` matrices with arbitrary + `AbstractVector`s ([#22718], [#22925]). * Mutating versions of `randperm` and `randcycle` have been added: `randperm!` and `randcycle!` ([#22723]). diff --git a/base/linalg/bidiag.jl b/base/linalg/bidiag.jl index b37ddd03d69c45..d37e5737294476 100644 --- a/base/linalg/bidiag.jl +++ b/base/linalg/bidiag.jl @@ -1,17 +1,17 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license # Bidiagonal matrices -struct Bidiagonal{T} <: AbstractMatrix{T} - dv::Vector{T} # diagonal - ev::Vector{T} # sub/super diagonal - uplo::Char # upper bidiagonal ('U') or lower ('L') - function Bidiagonal{T}(dv::Vector{T}, ev::Vector{T}, uplo::Char) where T +struct Bidiagonal{T,V<:AbstractVector{T}} <: AbstractMatrix{T} + dv::V # diagonal + ev::V # sub/super diagonal + uplo::Char # upper bidiagonal ('U') or lower ('L') + function Bidiagonal{T}(dv::V, ev::V, uplo::Char) where {T,V<:AbstractVector{T}} if length(ev) != length(dv)-1 throw(DimensionMismatch("length of diagonal vector is $(length(dv)), length of off-diagonal vector is $(length(ev))")) end - new(dv, ev, uplo) + new{T,V}(dv, ev, uplo) end - function Bidiagonal(dv::Vector{T}, ev::Vector{T}, uplo::Char) where T + function Bidiagonal(dv::V, ev::V, uplo::Char) where {T,V<:AbstractVector{T}} Bidiagonal{T}(dv, ev, uplo) end end @@ -41,26 +41,30 @@ julia> ev = [7, 8, 9] 9 julia> Bu = Bidiagonal(dv, ev, :U) # ev is on the first superdiagonal -4×4 Bidiagonal{Int64}: +4×4 Bidiagonal{Int64,Array{Int64,1}}: 1 7 ⋅ ⋅ ⋅ 2 8 ⋅ ⋅ ⋅ 3 9 ⋅ ⋅ ⋅ 4 julia> Bl = Bidiagonal(dv, ev, :L) # ev is on the first subdiagonal -4×4 Bidiagonal{Int64}: +4×4 Bidiagonal{Int64,Array{Int64,1}}: 1 ⋅ ⋅ ⋅ 7 2 ⋅ ⋅ ⋅ 8 3 ⋅ ⋅ ⋅ 9 4 ``` """ -function Bidiagonal(dv::AbstractVector{T}, ev::AbstractVector{T}, uplo::Symbol) where T - Bidiagonal{T}(collect(dv), collect(ev), char_uplo(uplo)) +function Bidiagonal(dv::V, ev::V, uplo::Symbol) where {T,V<:AbstractVector{T}} + Bidiagonal{T}(dv, ev, char_uplo(uplo)) +end + +function Bidiagonal(dv::AbstractVector{T}, ev::AbstractVector{S}, uplo::Symbol) where {T,S} + R = promote_type(T,S) + Bidiagonal(convert(AbstractVector{R}, dv), convert(AbstractVector{R}, ev), uplo) end -function Bidiagonal(dv::AbstractVector{Td}, ev::AbstractVector{Te}, uplo::Symbol) where {Td,Te} - T = promote_type(Td,Te) +function Bidiagonal(dv::AbstractVector{T}, ev::AbstractVector{T}, uplo::Symbol) where T Bidiagonal(convert(Vector{T}, dv), convert(Vector{T}, ev), uplo) end @@ -79,15 +83,15 @@ julia> A = [1 1 1 1; 2 2 2 2; 3 3 3 3; 4 4 4 4] 3 3 3 3 4 4 4 4 -julia> Bidiagonal(A, :U) #contains the main diagonal and first superdiagonal of A -4×4 Bidiagonal{Int64}: +julia> Bidiagonal(A, :U) # contains the main diagonal and first superdiagonal of A +4×4 Bidiagonal{Int64,Array{Int64,1}}: 1 1 ⋅ ⋅ ⋅ 2 2 ⋅ ⋅ ⋅ 3 3 ⋅ ⋅ ⋅ 4 -julia> Bidiagonal(A, :L) #contains the main diagonal and first subdiagonal of A -4×4 Bidiagonal{Int64}: +julia> Bidiagonal(A, :L) # contains the main diagonal and first subdiagonal of A +4×4 Bidiagonal{Int64,Array{Int64,1}}: 1 ⋅ ⋅ ⋅ 2 2 ⋅ ⋅ ⋅ 3 3 ⋅ diff --git a/base/test.jl b/base/test.jl index 32cd0e1be0ce46..24df0da3e7c6f0 100644 --- a/base/test.jl +++ b/base/test.jl @@ -1315,6 +1315,10 @@ end GenericArray{T}(args...) where {T} = GenericArray(Array{T}(args...)) GenericArray{T,N}(args...) where {T,N} = GenericArray(Array{T,N}(args...)) +function Base.convert(::Type{AbstractArray{T,N}}, a::GenericArray) where {T,N} + GenericArray{T,N}(convert(Array{T,N}, a.a)) +end + Base.eachindex(a::GenericArray) = eachindex(a.a) Base.indices(a::GenericArray) = indices(a.a) Base.length(a::GenericArray) = length(a.a) diff --git a/test/linalg/bidiag.jl b/test/linalg/bidiag.jl index d7b95a00dd9f69..3ec12ee306f595 100644 --- a/test/linalg/bidiag.jl +++ b/test/linalg/bidiag.jl @@ -24,7 +24,15 @@ srand(1) end @testset "Constructors" begin - @test Bidiagonal(dv,ev,:U) != Bidiagonal(dv,ev,:L) + ubd = Bidiagonal(dv, ev, :U) + lbd = Bidiagonal(dv, ev, :L) + @test ubd != lbd + @test ubd.dv === dv + @test lbd.ev === ev + ubd = Bidiagonal{elty}(dv, ev, :U) + lbd = Bidiagonal{elty}(dv, ev, :L) + @test ubd.dv === dv + @test lbd.ev === ev @test_throws ArgumentError Bidiagonal(dv,ev,:R) @test_throws DimensionMismatch Bidiagonal(dv,ones(elty,n),:U) @test_throws MethodError Bidiagonal(dv,ev) @@ -97,29 +105,30 @@ srand(1) end @testset "triu and tril" begin + bidiagcopy(dv, ev, uplo) = Bidiagonal(copy(dv), copy(ev), uplo) @test istril(Bidiagonal(dv,ev,:L)) @test !istril(Bidiagonal(dv,ev,:U)) - @test tril!(Bidiagonal(dv,ev,:U),-1) == Bidiagonal(zeros(dv),zeros(ev),:U) - @test tril!(Bidiagonal(dv,ev,:L),-1) == Bidiagonal(zeros(dv),ev,:L) - @test tril!(Bidiagonal(dv,ev,:U),-2) == Bidiagonal(zeros(dv),zeros(ev),:U) - @test tril!(Bidiagonal(dv,ev,:L),-2) == Bidiagonal(zeros(dv),zeros(ev),:L) - @test tril!(Bidiagonal(dv,ev,:U),1) == Bidiagonal(dv,ev,:U) - @test tril!(Bidiagonal(dv,ev,:L),1) == Bidiagonal(dv,ev,:L) - @test tril!(Bidiagonal(dv,ev,:U)) == Bidiagonal(dv,zeros(ev),:U) - @test tril!(Bidiagonal(dv,ev,:L)) == Bidiagonal(dv,ev,:L) - @test_throws ArgumentError tril!(Bidiagonal(dv,ev,:U),n+1) + @test tril!(bidiagcopy(dv,ev,:U),-1) == Bidiagonal(zeros(dv),zeros(ev),:U) + @test tril!(bidiagcopy(dv,ev,:L),-1) == Bidiagonal(zeros(dv),ev,:L) + @test tril!(bidiagcopy(dv,ev,:U),-2) == Bidiagonal(zeros(dv),zeros(ev),:U) + @test tril!(bidiagcopy(dv,ev,:L),-2) == Bidiagonal(zeros(dv),zeros(ev),:L) + @test tril!(bidiagcopy(dv,ev,:U),1) == Bidiagonal(dv,ev,:U) + @test tril!(bidiagcopy(dv,ev,:L),1) == Bidiagonal(dv,ev,:L) + @test tril!(bidiagcopy(dv,ev,:U)) == Bidiagonal(dv,zeros(ev),:U) + @test tril!(bidiagcopy(dv,ev,:L)) == Bidiagonal(dv,ev,:L) + @test_throws ArgumentError tril!(bidiagcopy(dv,ev,:U),n+1) @test istriu(Bidiagonal(dv,ev,:U)) @test !istriu(Bidiagonal(dv,ev,:L)) - @test triu!(Bidiagonal(dv,ev,:L),1) == Bidiagonal(zeros(dv),zeros(ev),:L) - @test triu!(Bidiagonal(dv,ev,:U),1) == Bidiagonal(zeros(dv),ev,:U) - @test triu!(Bidiagonal(dv,ev,:U),2) == Bidiagonal(zeros(dv),zeros(ev),:U) - @test triu!(Bidiagonal(dv,ev,:L),2) == Bidiagonal(zeros(dv),zeros(ev),:L) - @test triu!(Bidiagonal(dv,ev,:U),-1) == Bidiagonal(dv,ev,:U) - @test triu!(Bidiagonal(dv,ev,:L),-1) == Bidiagonal(dv,ev,:L) - @test triu!(Bidiagonal(dv,ev,:L)) == Bidiagonal(dv,zeros(ev),:L) - @test triu!(Bidiagonal(dv,ev,:U)) == Bidiagonal(dv,ev,:U) - @test_throws ArgumentError triu!(Bidiagonal(dv,ev,:U),n+1) + @test triu!(bidiagcopy(dv,ev,:L),1) == Bidiagonal(zeros(dv),zeros(ev),:L) + @test triu!(bidiagcopy(dv,ev,:U),1) == Bidiagonal(zeros(dv),ev,:U) + @test triu!(bidiagcopy(dv,ev,:U),2) == Bidiagonal(zeros(dv),zeros(ev),:U) + @test triu!(bidiagcopy(dv,ev,:L),2) == Bidiagonal(zeros(dv),zeros(ev),:L) + @test triu!(bidiagcopy(dv,ev,:U),-1) == Bidiagonal(dv,ev,:U) + @test triu!(bidiagcopy(dv,ev,:L),-1) == Bidiagonal(dv,ev,:L) + @test triu!(bidiagcopy(dv,ev,:L)) == Bidiagonal(dv,zeros(ev),:L) + @test triu!(bidiagcopy(dv,ev,:U)) == Bidiagonal(dv,ev,:U) + @test_throws ArgumentError triu!(bidiagcopy(dv,ev,:U),n+1) end Tfull = Array(T) @@ -255,7 +264,31 @@ srand(1) end BD = Bidiagonal(dv, ev, :U) @test Matrix{Complex{Float64}}(BD) == BD +end +@testset "arbitrary AbstractVector in Bidiagonal" begin + S, T = Float32, Float64 + R = promote_type(T, S) + dvT = rand(T, n); dvS = rand(S, n) + evT = rand(T, n-1); evS = rand(S, n-1) + GdvT = GenericArray(dvT); GdvS = GenericArray(dvS) + GevT = GenericArray(evT); GevS = GenericArray(evS) + for uplo in (:U, :L) + @test isa(Bidiagonal(dvT, evT, uplo), Bidiagonal{T,Vector{T}}) + @test isa(Bidiagonal(dvT, evS, uplo), Bidiagonal{R,Vector{R}}) + @test isa(Bidiagonal(dvS, evT, uplo), Bidiagonal{R,Vector{R}}) + @test isa(Bidiagonal(dvS, evS, uplo), Bidiagonal{S,Vector{S}}) + + @test isa(Bidiagonal(GdvT, GevT, uplo), Bidiagonal{T,GenericArray{T,1}}) + @test isa(Bidiagonal(GdvT, GevS, uplo), Bidiagonal{R,GenericArray{R,1}}) + @test isa(Bidiagonal(GdvS, GevT, uplo), Bidiagonal{R,GenericArray{R,1}}) + @test isa(Bidiagonal(GdvS, GevS, uplo), Bidiagonal{S,GenericArray{S,1}}) + + @test isa(Bidiagonal(GdvT, evT, uplo), Bidiagonal{T,Vector{T}}) + @test isa(Bidiagonal(GdvT, evS, uplo), Bidiagonal{R,Vector{R}}) + @test isa(Bidiagonal(GdvS, evT, uplo), Bidiagonal{R,Vector{R}}) + @test isa(Bidiagonal(GdvS, evS, uplo), Bidiagonal{S,Vector{S}}) + end end # Issue 10742 and similar diff --git a/test/show.jl b/test/show.jl index db6f39b4849a10..009f945abbc654 100644 --- a/test/show.jl +++ b/test/show.jl @@ -556,8 +556,8 @@ end # test structured zero matrix printing for select structured types A = reshape(1:16,4,4) @test replstr(Diagonal(A)) == "4×4 Diagonal{$(Int),Array{$(Int),1}}:\n 1 ⋅ ⋅ ⋅\n ⋅ 6 ⋅ ⋅\n ⋅ ⋅ 11 ⋅\n ⋅ ⋅ ⋅ 16" -@test replstr(Bidiagonal(A,:U)) == "4×4 Bidiagonal{$Int}:\n 1 5 ⋅ ⋅\n ⋅ 6 10 ⋅\n ⋅ ⋅ 11 15\n ⋅ ⋅ ⋅ 16" -@test replstr(Bidiagonal(A,:L)) == "4×4 Bidiagonal{$Int}:\n 1 ⋅ ⋅ ⋅\n 2 6 ⋅ ⋅\n ⋅ 7 11 ⋅\n ⋅ ⋅ 12 16" +@test replstr(Bidiagonal(A,:U)) == "4×4 Bidiagonal{$(Int),Array{$(Int),1}}:\n 1 5 ⋅ ⋅\n ⋅ 6 10 ⋅\n ⋅ ⋅ 11 15\n ⋅ ⋅ ⋅ 16" +@test replstr(Bidiagonal(A,:L)) == "4×4 Bidiagonal{$(Int),Array{$(Int),1}}:\n 1 ⋅ ⋅ ⋅\n 2 6 ⋅ ⋅\n ⋅ 7 11 ⋅\n ⋅ ⋅ 12 16" @test replstr(SymTridiagonal(A+A')) == "4×4 SymTridiagonal{$Int}:\n 2 7 ⋅ ⋅\n 7 12 17 ⋅\n ⋅ 17 22 27\n ⋅ ⋅ 27 32" @test replstr(Tridiagonal(diag(A,-1),diag(A),diag(A,+1))) == "4×4 Tridiagonal{$Int}:\n 1 5 ⋅ ⋅\n 2 6 10 ⋅\n ⋅ 7 11 15\n ⋅ ⋅ 12 16" @test replstr(UpperTriangular(copy(A))) == "4×4 UpperTriangular{$Int,Array{$Int,2}}:\n 1 5 9 13\n ⋅ 6 10 14\n ⋅ ⋅ 11 15\n ⋅ ⋅ ⋅ 16"