diff --git a/src/bidiag.jl b/src/bidiag.jl index 2fb1415..626f04c 100644 --- a/src/bidiag.jl +++ b/src/bidiag.jl @@ -198,7 +198,13 @@ function Matrix{T}(A::Bidiagonal) where T end return B end -Matrix(A::Bidiagonal{T}) where {T} = Matrix{promote_type(T, typeof(zero(T)))}(A) +function Matrix(A::Bidiagonal{T}) where {T} + if haszero(T) + Matrix{promote_type(T, typeof(zero(T)))}(A) + else + convert(Matrix, [x for x in A]) + end +end Array(A::Bidiagonal) = Matrix(A) promote_rule(::Type{Matrix{T}}, ::Type{<:Bidiagonal{S}}) where {T,S} = @isdefined(T) && @isdefined(S) ? Matrix{promote_type(T,S)} : Matrix diff --git a/src/dense.jl b/src/dense.jl index e68f7e9..d4186cf 100644 --- a/src/dense.jl +++ b/src/dense.jl @@ -114,7 +114,8 @@ norm2(x::Union{Array{T},StridedVector{T}}) where {T<:BlasFloat} = Return whether a type `T` has a unique zero element defined using `zero(T)`. If a type `M` specializes `zero(M)`, it may also choose to set `haszero(M)` to `true`. By default, `haszero` is assumed to be `false`, in which case the zero elements -are deduced from values rather than the type. +are deduced from values rather than the type. In general, if a type defines `zero(::Type{MyType})`, +it should also define `haszero(::Type{MyType}) = true`. !!! note `haszero` is a conservative check that is used to dispatch to diff --git a/src/diagonal.jl b/src/diagonal.jl index 280caec..35e4330 100644 --- a/src/diagonal.jl +++ b/src/diagonal.jl @@ -113,7 +113,13 @@ Diagonal{T}(D::Diagonal) where {T} = Diagonal{T}(D.diag) AbstractMatrix{T}(D::Diagonal) where {T} = Diagonal{T}(D) AbstractMatrix{T}(D::Diagonal{T}) where {T} = copy(D) -Matrix(D::Diagonal{T}) where {T} = Matrix{promote_type(T, typeof(zero(T)))}(D) +function Matrix(D::Diagonal{T}) where {T} + if haszero(T) + Matrix{promote_type(T, typeof(zero(T)))}(D) + else + convert(Matrix, [i for i in D]) + end +end Matrix(D::Diagonal{Any}) = Matrix{Any}(D) Array(D::Diagonal{T}) where {T} = Matrix(D) function Matrix{T}(D::Diagonal) where {T} diff --git a/src/tridiag.jl b/src/tridiag.jl index a24cc50..dd2b95a 100644 --- a/src/tridiag.jl +++ b/src/tridiag.jl @@ -148,7 +148,13 @@ function Matrix{T}(M::SymTridiagonal) where T end return Mf end -Matrix(M::SymTridiagonal{T}) where {T} = Matrix{promote_type(T, typeof(zero(T)))}(M) +function Matrix(M::SymTridiagonal{T}) where {T} + if haszero(T) + Matrix{promote_type(T, typeof(zero(T)))}(M) + else + convert(Matrix, [x for x in M]) + end +end Array(M::SymTridiagonal) = Matrix(M) size(A::SymTridiagonal) = (n = length(A.dv); (n, n)) @@ -620,7 +626,13 @@ function Matrix{T}(M::Tridiagonal) where {T} end A end -Matrix(M::Tridiagonal{T}) where {T} = Matrix{promote_type(T, typeof(zero(T)))}(M) +function Matrix(M::Tridiagonal{T}) where {T} + if haszero(T) + Matrix{promote_type(T, typeof(zero(T)))}(M) + else + convert(Matrix, [x for x in M]) + end +end Array(M::Tridiagonal) = Matrix(M) similar(M::Tridiagonal, ::Type{T}) where {T} = Tridiagonal(similar(M.dl, T), similar(M.d, T), similar(M.du, T)) diff --git a/test/bidiag.jl b/test/bidiag.jl index ea4cfcf..ca3a8fb 100644 --- a/test/bidiag.jl +++ b/test/bidiag.jl @@ -1164,4 +1164,11 @@ end @test opnorm(B, Inf) == opnorm(Matrix(B), Inf) end +@testset "Matrix conversion without zero" begin + D = Bidiagonal(fill(ones(2,2), 4), fill(ones(2,2), 3), :U) + M = Matrix(D) + @test M isa Matrix{eltype(D)} + @test M == D +end + end # module TestBidiagonal diff --git a/test/diagonal.jl b/test/diagonal.jl index 1cd2e9d..7cc908d 100644 --- a/test/diagonal.jl +++ b/test/diagonal.jl @@ -1473,4 +1473,11 @@ end @test opnorm(D, Inf) == opnorm(A, Inf) end +@testset "Matrix conversion without zero" begin + D = Diagonal(fill(ones(2,2), 4)) + M = Matrix(D) + @test M isa Matrix{eltype(D)} + @test M == D +end + end # module TestDiagonal diff --git a/test/special.jl b/test/special.jl index 4b91bcf..4202d47 100644 --- a/test/special.jl +++ b/test/special.jl @@ -115,6 +115,8 @@ Random.seed!(1) struct TypeWithZero end Base.promote_rule(::Type{TypeWithoutZero}, ::Type{TypeWithZero}) = TypeWithZero Base.convert(::Type{TypeWithZero}, ::TypeWithoutZero) = TypeWithZero() + LinearAlgebra.haszero(::Type{TypeWithoutZero}) = true + LinearAlgebra.haszero(::Type{TypeWithZero}) = true Base.zero(x::Union{TypeWithoutZero, TypeWithZero}) = zero(typeof(x)) Base.zero(::Type{<:Union{TypeWithoutZero, TypeWithZero}}) = TypeWithZero() LinearAlgebra.symmetric(::TypeWithoutZero, ::Symbol) = TypeWithoutZero() diff --git a/test/tridiag.jl b/test/tridiag.jl index 4b592a8..78a829a 100644 --- a/test/tridiag.jl +++ b/test/tridiag.jl @@ -1099,4 +1099,13 @@ end @test opnorm(S, Inf) == opnorm(Matrix(S), Inf) end +@testset "Matrix conversion without zero" begin + dv, ev = fill(ones(2,2), 2), fill(ones(2,2), 1) + for T in (Tridiagonal(ev, dv, ev), SymTridiagonal(dv, ev)) + M = Matrix(T) + @test M isa Matrix + @test M == T + end +end + end # module TestTridiagonal