From 86231ce5763a41a6661d7834a28ad1c37526044a Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Fri, 9 Aug 2024 19:20:42 +0000 Subject: [PATCH] LinearAlgebra: round-trippable 2-argument show for `Tridiagonal`/`SymTridiagonal` (#55415) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the displayed form of a `Tridiaognal` and a `SymTridiagonal` valid constructors. ```julia julia> T = Tridiagonal(1:3, 1:4, 1:3) 4×4 Tridiagonal{Int64, UnitRange{Int64}}: 1 1 ⋅ ⋅ 1 2 2 ⋅ ⋅ 2 3 3 ⋅ ⋅ 3 4 julia> show(T) Tridiagonal(1:3, 1:4, 1:3) julia> S = SymTridiagonal(1:4, 1:3) 4×4 SymTridiagonal{Int64, UnitRange{Int64}}: 1 1 ⋅ ⋅ 1 2 2 ⋅ ⋅ 2 3 3 ⋅ ⋅ 3 4 julia> show(S) SymTridiagonal(1:4, 1:3) ``` Displaying the bands has several advantages: firstly, it's briefer than printing the full array, and secondly, it displays the special structure in the bands, if any. E.g.: ```julia julia> T = Tridiagonal(spzeros(3), spzeros(4), spzeros(3)); julia> show(T) Tridiagonal(sparsevec(Int64[], Float64[], 3), sparsevec(Int64[], Float64[], 4), sparsevec(Int64[], Float64[], 3)) ``` It's clear from the displayed form that `T` has sparse bands. A special handling for `SymTridiagonal` matrices is necessary, as the diagonal band is symmetrized. This means: ```julia julia> using StaticArrays julia> m = SMatrix{2,2}(1:4); julia> S = SymTridiagonal(fill(m,3), fill(m,2)) 3×3 SymTridiagonal{SMatrix{2, 2, Int64, 4}, Vector{SMatrix{2, 2, Int64, 4}}}: [1 3; 3 4] [1 3; 2 4] ⋅ [1 2; 3 4] [1 3; 3 4] [1 3; 2 4] ⋅ [1 2; 3 4] [1 3; 3 4] julia> show(S) SymTridiagonal(SMatrix{2, 2, Int64, 4}[[1 3; 3 4], [1 3; 3 4], [1 3; 3 4]], SMatrix{2, 2, Int64, 4}[[1 3; 2 4], [1 3; 2 4]]) ``` The displayed values correspond to the symmetrized band, and not the actual input arguments. I think displaying the symmetrized elements makes more sense here, as this matches the form in the 3-argument `show`. --- stdlib/LinearAlgebra/src/tridiag.jl | 18 ++++++++++++++++++ stdlib/LinearAlgebra/test/tridiag.jl | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/stdlib/LinearAlgebra/src/tridiag.jl b/stdlib/LinearAlgebra/src/tridiag.jl index c14ed5690198c..0ba03634d82ad 100644 --- a/stdlib/LinearAlgebra/src/tridiag.jl +++ b/stdlib/LinearAlgebra/src/tridiag.jl @@ -1045,3 +1045,21 @@ function _copyto_banded!(A::SymTridiagonal, B::Tridiagonal) _evview(A) .= B.du return A end + +# display +function show(io::IO, T::Tridiagonal) + print(io, "Tridiagonal(") + show(io, T.dl) + print(io, ", ") + show(io, T.d) + print(io, ", ") + show(io, T.du) + print(io, ")") +end +function show(io::IO, S::SymTridiagonal) + print(io, "SymTridiagonal(") + show(io, eltype(S) <: Number ? S.dv : view(S, diagind(S, IndexStyle(S)))) + print(io, ", ") + show(io, S.ev) + print(io, ")") +end diff --git a/stdlib/LinearAlgebra/test/tridiag.jl b/stdlib/LinearAlgebra/test/tridiag.jl index 41a28631b27a0..e0a8e32d77852 100644 --- a/stdlib/LinearAlgebra/test/tridiag.jl +++ b/stdlib/LinearAlgebra/test/tridiag.jl @@ -18,6 +18,9 @@ using .Main.FillArrays isdefined(Main, :OffsetArrays) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "OffsetArrays.jl")) using .Main.OffsetArrays +isdefined(Main, :SizedArrays) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "SizedArrays.jl")) +using .Main.SizedArrays + include("testutils.jl") # test_approx_eq_modphase #Test equivalence of eigenvectors/singular vectors taking into account possible phase (sign) differences @@ -914,4 +917,17 @@ end end end +@testset "show" begin + T = Tridiagonal(1:3, 1:4, 1:3) + @test sprint(show, T) == "Tridiagonal(1:3, 1:4, 1:3)" + S = SymTridiagonal(1:4, 1:3) + @test sprint(show, S) == "SymTridiagonal(1:4, 1:3)" + + m = SizedArrays.SizedArray{(2,2)}(reshape([1:4;],2,2)) + T = Tridiagonal(fill(m,2), fill(m,3), fill(m,2)) + @test sprint(show, T) == "Tridiagonal($(repr(diag(T,-1))), $(repr(diag(T))), $(repr(diag(T,1))))" + S = SymTridiagonal(fill(m,3), fill(m,2)) + @test sprint(show, S) == "SymTridiagonal($(repr(diag(S))), $(repr(diag(S,1))))" +end + end # module TestTridiagonal