Skip to content

Commit

Permalink
LinearAlgebra: round-trippable 2-argument show for Tridiagonal/`Sym…
Browse files Browse the repository at this point in the history
…Tridiagonal` (JuliaLang#55415)

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`.
  • Loading branch information
jishnub authored Aug 9, 2024
1 parent 7ec39e7 commit 86231ce
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
18 changes: 18 additions & 0 deletions stdlib/LinearAlgebra/src/tridiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
16 changes: 16 additions & 0 deletions stdlib/LinearAlgebra/test/tridiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

0 comments on commit 86231ce

Please sign in to comment.