diff --git a/src/MPSKit.jl b/src/MPSKit.jl index a6c586144..8e96d607d 100644 --- a/src/MPSKit.jl +++ b/src/MPSKit.jl @@ -18,6 +18,7 @@ export QP, LeftGaugedQP, RightGaugedQP # operators: export AbstractMPO export MPO, FiniteMPO, InfiniteMPO +export JordanMPOTensor, JordanMPOTensorMap export MPOHamiltonian, FiniteMPOHamiltonian, InfiniteMPOHamiltonian export MultilineMPO export UntimedOperator, TimedOperator, MultipliedOperator, LazySum @@ -123,7 +124,6 @@ include("operators/projection.jl") include("operators/timedependence.jl") include("operators/multipliedoperator.jl") include("operators/lazysum.jl") -include("operators/show.jl") include("transfermatrix/transfermatrix.jl") include("transfermatrix/transfer.jl") @@ -189,6 +189,8 @@ include("algorithms/ED.jl") include("algorithms/unionalg.jl") +include("utility/show.jl") + function __init__() Defaults.set_scheduler!() return nothing diff --git a/src/environments/finite_envs.jl b/src/environments/finite_envs.jl index 7f26c8ddf..6372f65ab 100644 --- a/src/environments/finite_envs.jl +++ b/src/environments/finite_envs.jl @@ -1,7 +1,7 @@ """ struct FiniteEnvironments <: AbstractMPSEnvironments -Environment manager for `FiniteMPS` and `WindowMPS`. This structure is responsable for automatically checking +Environment manager for `FiniteMPS` and `WindowMPS`. This structure is responsible for automatically checking if the queried environment is still correctly cached and if not recalculates. """ struct FiniteEnvironments{A, B, C, D} <: AbstractMPSEnvironments diff --git a/src/operators/jordanmpotensor.jl b/src/operators/jordanmpotensor.jl index 6688b8182..4a3dbe798 100644 --- a/src/operators/jordanmpotensor.jl +++ b/src/operators/jordanmpotensor.jl @@ -58,6 +58,14 @@ struct JordanMPOTensor{ end end +const JordanMPOTensorMap{T, S, A <: DenseVector{T}} = JordanMPOTensor{ + T, S, + Union{TensorMap{T, S, 2, 2, A}, BraidingTensor{T, S}}, + TensorMap{T, S, 2, 1, A}, + TensorMap{T, S, 1, 2, A}, + TensorMap{T, S, 1, 1, A}, +} + function JordanMPOTensor{E, S}(::UndefInitializer, V::TensorMapSumSpace{S}) where {E, S} return jordanmpotensortype(S, E)(undef, V) end @@ -378,15 +386,12 @@ function Base.isapprox(W1::JordanMPOTensor, W2::JordanMPOTensor; kwargs...) isapprox(W1.D, W2.D; kwargs...) end -function Base.summary(io::IO, W::JordanMPOTensor) - szstring = Base.dims2string(size(W)) - TT = eltype(W) - typeinfo = get(io, :typeinfo, Any) - if typeinfo <: typeof(W) || typeinfo <: TT - typestring = "" - else - typestring = "{$TT}" - end - V = space(W) - return print(io, "$szstring JordanMPOTensor$typestring($V)") +function Base.showarg(io::IO, W::JordanMPOTensor, toplevel::Bool) + !toplevel && print(io, "::") + print(io, TensorKit.type_repr(typeof(W))) + return nothing +end + +function TensorKit.type_repr(::Type{<:JordanMPOTensor{E, S}}) where {E, S} + return "JordanMPOTensor{$E, " * TensorKit.type_repr(S) * ", …}" end diff --git a/src/operators/show.jl b/src/operators/show.jl deleted file mode 100644 index 020ad895f..000000000 --- a/src/operators/show.jl +++ /dev/null @@ -1,97 +0,0 @@ -# AbstractMPO -# ----------- -function Base.show(io::IO, ::MIME"text/plain", W::AbstractMPO) - L = length(W) - println(io, L == 1 ? "single site " : "$L-site ", typeof(W), ":") - context = IOContext(io, :typeinfo => eltype(W), :compact => true) - return show(context, W) -end - -Base.show(io::IO, mpo::AbstractMPO) = show(convert(IOContext, io), mpo) -function Base.show(io::IOContext, mpo::AbstractMPO) - charset = (; top = "┬", bot = "┴", mid = "┼", ver = "│", dash = "──") - limit = get(io, :limit, false)::Bool - half_screen_rows = limit ? div(displaysize(io)[1] - 8, 2) : typemax(Int) - L = length(mpo) - - # used to align all mposite infos regardless of the length of the mpo (100 takes up more space than 5) - npad = floor(Int, log10(L)) - mpoletter = mpo isa MPOHamiltonian ? "W" : "O" - isfinite = (mpo isa FiniteMPO) || (mpo isa FiniteMPOHamiltonian) - - !isfinite && println(io, "╷ ⋮") - for site in reverse(1:L) - if site < half_screen_rows || site > L - half_screen_rows - if site == L && isfinite - println( - io, charset.top, " $mpoletter[$site]: ", - repeat(" ", npad - floor(Int, log10(site))), mpo[site] - ) - elseif (site == 1) && isfinite - println( - io, charset.bot, " $mpoletter[$site]: ", - repeat(" ", npad - floor(Int, log10(site))), mpo[site] - ) - else - println( - io, charset.mid, " $mpoletter[$site]: ", - repeat(" ", npad - floor(Int, log10(site))), mpo[site] - ) - end - elseif site == half_screen_rows - println(io, " ", "⋮") - end - end - !isfinite && println(io, "╵ ⋮") - return nothing -end - -# braille -# ------- -""" - braille(io::IO, H::Union{SparseMPO, MPOHamiltonian}) - braille(H::Union{SparseMPO, MPOHamiltonian}) - -Prints a compact, human-readable "braille" visualization of a sparseMPO or MPOHamiltonian. -Each site of the MPO is represented as a block of Unicode braille characters, with sites separated by dashes. -This visualization is useful for quickly inspecting the structure and sparsity pattern of MPOs. - -# Arguments -- `io::IO`: The output stream to print to (e.g., `stdout`). -- `H::Union{SparseMPO, MPOHamiltonian}`: The `SparseMPO` or `MPOHamiltonian` to visualize. - -If called without an `io` argument, output is printed to `stdout`. -""" -function braille(io::IO, H::Union{SparseMPO, MPOHamiltonian}) - dash = "🭻" - stride = 2 #amount of dashes between braille - L = length(H) - - brailles = Vector{Vector{String}}(undef, L) - buffer = IOBuffer() - for (i, W) in enumerate(H) - BlockTensorKit.show_braille(buffer, W) - brailles[i] = split(String(take!(buffer))) - end - - maxheight = maximum(length.(brailles)) - - for i in 1:maxheight - line = "" - line *= ((i == 1 && !isfinite(H)) ? ("... " * dash) : " ") - line *= (i > 1 && !isfinite(H)) ? " " : "" - for (j, braille) in enumerate(brailles) - line *= ( - checkbounds(Bool, braille, i) ? braille[i] : repeat(" ", length(braille[1])) - ) - if j < L - line *= repeat(((i == 1) ? dash : " "), stride) - end - end - line *= ((i == 1 && !isfinite(H)) ? (dash * " ...") : " ") - println(io, line) - end - return nothing -end - -braille(H::Union{SparseMPO, MPOHamiltonian}) = braille(stdout, H) diff --git a/src/states/finitemps.jl b/src/states/finitemps.jl index 9d0fe986a..4c6b6a0c4 100644 --- a/src/states/finitemps.jl +++ b/src/states/finitemps.jl @@ -439,71 +439,6 @@ Compute the dimension of the maximal virtual space at a given site. """ max_Ds(ψ::FiniteMPS) = dim.(max_virtualspaces(ψ)) -function Base.summary(io::IO, ψ::FiniteMPS) - return print(io, "$(length(ψ))-site FiniteMPS ($(scalartype(ψ)), $(spacetype(ψ)))") -end -function Base.show(io::IO, ::MIME"text/plain", ψ::FiniteMPS) - println(io, summary(ψ), ":") - context = IOContext(io, :typeinfo => eltype(ψ), :compact => true) - return show(context, ψ) -end -Base.show(io::IO, ψ::FiniteMPS) = show(convert(IOContext, io), ψ) -function Base.show(io::IOContext, ψ::FiniteMPS) - charset = (; start = "┌", mid = "├", stop = "└", ver = "│", dash = "──") - limit = get(io, :limit, false)::Bool - half_screen_rows = limit ? div(displaysize(io)[1] - 8, 2) : typemax(Int) - if !haskey(io, :compact) - io = IOContext(io, :compact => true) - end - - L = length(ψ) - c = ψ.center - - for site in HalfInt.(reverse((1 / 2):(1 / 2):(L + 1 / 2))) - if site < half_screen_rows || site > L - half_screen_rows - if site > c # ARs - if isinteger(site) - println( - io, Int(site) == L ? charset.start : charset.mid, charset.dash, - " AR[$(Int(site))]: ", ψ.ARs[Int(site)] - ) - end - elseif site == c # AC or C - if isinteger(c) # center is an AC - println( - io, if site == L - charset.start - elseif site == 1 - charset.stop - else - charset.mid - end, charset.dash, " AC[$(Int(site))]: ", ψ.ACs[Int(site)] - ) - else # center is a bond-tensor - println( - io, if site == HalfInt(L + 1 / 2) - charset.start - elseif site == HalfInt(1 / 2) - charset.stop - else - charset.ver - end, " C[$(Int(site - 1 / 2))]: ", ψ.Cs[Int(site + 1 / 2)] - ) - end - else - if isinteger(site) - println( - io, site == 1 ? charset.stop : charset.mid, charset.dash, - " AL[$(Int(site))]: ", ψ.ALs[Int(site)] - ) - end - end - elseif site == half_screen_rows - println(io, charset.ver, "⋮") - end - end - return nothing -end #=========================================================================================== Linear Algebra diff --git a/src/states/infinitemps.jl b/src/states/infinitemps.jl index c9a4cf906..989aa114b 100644 --- a/src/states/infinitemps.jl +++ b/src/states/infinitemps.jl @@ -311,36 +311,6 @@ function Base.isapprox(ψ₁::InfiniteMPS, ψ₂::InfiniteMPS; kwargs...) return isapprox(dot(ψ₁, ψ₂), 1; kwargs...) end -function Base.show(io::IO, ::MIME"text/plain", ψ::InfiniteMPS) - L = length(ψ) - println(io, L == 1 ? "single site" : "$L-site", " InfiniteMPS:") - context = IOContext(io, :typeinfo => eltype(ψ), :compact => true) - return show(context, ψ) -end -Base.show(io::IO, ψ::InfiniteMPS) = show(convert(IOContext, io), ψ) -function Base.show(io::IOContext, ψ::InfiniteMPS) - charset = (; mid = "├", ver = "│", dash = "──") - limit = get(io, :limit, false)::Bool - half_screen_rows = limit ? div(displaysize(io)[1] - 8, 2) : typemax(Int) - if !haskey(io, :compact) - io = IOContext(io, :compact => true) - end - L = length(ψ) - println(io, charset.ver, " ⋮") - for site in reverse(1:L) - if site < half_screen_rows || site > L - half_screen_rows - if site == L - println(io, charset.ver, " C[$site]: ", ψ.C[site]) - end - println(io, charset.mid, charset.dash, " AL[$site]: ", ψ.AL[site]) - elseif site == half_screen_rows - println(io, charset.ver, "⋮") - end - end - println(io, charset.ver, " ⋮") - return nothing -end - #=========================================================================================== Fixedpoints ===========================================================================================# diff --git a/src/utility/show.jl b/src/utility/show.jl new file mode 100644 index 000000000..bd132dd6c --- /dev/null +++ b/src/utility/show.jl @@ -0,0 +1,236 @@ +for T in (:FiniteMPS, :InfiniteMPS, :FiniteMPO, :InfiniteMPO, :FiniteMPOHamiltonian, :InfiniteMPOHamiltonian) + @eval function Base.summary(io::IO, x::$T) + L = length(x) + D = maximum(dim, left_virtualspace(x)) + E = scalartype(x) + S = TensorKit.type_repr(spacetype(x)) + print(io, L, "-site ", $(string(T)), "(", E, ", ", S, ") with maximal dimension ", D) + $(T === :FiniteMPS) && print(io, " and center ", x.center) + return nothing + end +end + +function Base.show(io::IO, ::MIME"text/plain", ψ::FiniteMPS) + summary(io, ψ) + get(io, :compact, false)::Bool && return nothing + + println(io, ":") + io = IOContext(io, :typeinfo => spacetype(ψ)) + + limit = get(io, :limit, true)::Bool + half_screen_rows = limit ? div(displaysize(io)[1] - 2, 4) : typemax(Int) + L = length(ψ) + if L <= 2 * half_screen_rows # everything fits! + half_screen_rows = typemax(Int) + end + + # special handling of edge spaces => don't print if trivial + Vright = right_virtualspace(ψ, L) + right_trivial = Vright == oneunit(Vright) + Vleft = left_virtualspace(ψ, 1) + left_trivial = Vleft == oneunit(Vleft) + + + right_trivial || println(io, "│ ", Vright) + for i in reverse(1:L) + if i > L - half_screen_rows + if i == L + connector = right_trivial ? "┌" : "├" + println(io, connector, "─[$i]─ ", physicalspace(ψ, i)) + elseif i == 1 + connector = left_trivial ? "└" : "├" + println(io, connector, "─[$i]─ ", physicalspace(ψ, i)) + else + println(io, "├─[$i]─ ", physicalspace(ψ, i)) + end + + i != 1 && println(io, "│ ", left_virtualspace(ψ, i)) + elseif i == half_screen_rows + println(io, "│ ⋮") + elseif i < half_screen_rows + i != L && println(io, "│ ", right_virtualspace(ψ, i)) + if i == L + connector = right_trivial ? "┌" : "├" + println(io, connector, "─[$i]─ ", physicalspace(ψ, i)) + elseif i == 1 + connector = left_trivial ? "└" : "├" + println(io, connector, "─[$i]─ ", physicalspace(ψ, i)) + else + println(io, "├─[$i]─ ", physicalspace(ψ, i)) + end + end + end + left_trivial || println(io, "│ ", Vleft) + + return nothing +end + +function Base.show(io::IO, ::MIME"text/plain", ψ::InfiniteMPS) + summary(io, ψ) + get(io, :compact, false)::Bool && return nothing + + println(io, ":") + io = IOContext(io, :typeinfo => spacetype(ψ)) + + limit = get(io, :limit, true)::Bool + half_screen_rows = limit ? div(displaysize(io)[1] - 6, 4) : typemax(Int) + L = length(ψ) + if L <= 2 * half_screen_rows # everything fits! + half_screen_rows = typemax(Int) + end + + println(io, "| ⋮") + println(io, "| ", right_virtualspace(ψ, L)) + for i in reverse(1:L) + if i > L - half_screen_rows || i < half_screen_rows + println(io, "├─[$i]─ ", physicalspace(ψ, i)) + println(io, "│ ", left_virtualspace(ψ, i)) + elseif i == half_screen_rows + println(io, "│ ⋮") + println(io, "│ ", left_virtualspace(ψ, i)) + end + end + println(io, "| ⋮") + + return nothing +end + +function Base.show(io::IO, ::MIME"text/plain", mpo::AbstractMPO) + summary(io, mpo) + get(io, :compact, false)::Bool && return nothing + + println(io, ":") + io = IOContext(io, :typeinfo => spacetype(mpo)) + + limit = get(io, :limit, true)::Bool + half_screen_rows = limit ? div(displaysize(io)[1] - 6, 4) : typemax(Int) + L = length(mpo) + if L <= 2 * half_screen_rows # everything fits! + half_screen_rows = typemax(Int) + end + + if isfinite(mpo) + # special handling of edge spaces => don't print if trivial + Vright = right_virtualspace(mpo, L) + right_trivial = Vright == oneunit(Vright) + Vleft = left_virtualspace(mpo, 1) + left_trivial = Vleft == oneunit(Vleft) + + right_trivial || println(io, "│ ", Vright) + for i in reverse(1:L) + if i > L - half_screen_rows + if i == L + connector = right_trivial ? "┬" : "┼" + println(io, connector, "─[$i]─ ", physicalspace(mpo, i)) + elseif i == 1 + connector = left_trivial ? "┴" : "┼" + println(io, connector, "─[$i]─ ", physicalspace(mpo, i)) + else + println(io, "┼─[$i]─ ", physicalspace(mpo, i)) + end + + i != 1 && println(io, "│ ", left_virtualspace(mpo, i)) + elseif i == half_screen_rows + println(io, "│ ⋮") + elseif i < half_screen_rows + i != L && println(io, "│ ", right_virtualspace(mpo, i)) + if i == L + connector = right_trivial ? "┬" : "┼" + println(io, connector, "─[$i]─ ", physicalspace(mpo, i)) + elseif i == 1 + connector = left_trivial ? "┴" : "┼" + println(io, connector, "─[$i]─ ", physicalspace(mpo, i)) + else + println(io, "┼─[$i]─ ", physicalspace(mpo, i)) + end + end + end + left_trivial || println(io, "│ ", Vleft) + else + println(io, "| ⋮") + println(io, "| ", right_virtualspace(mpo, L)) + for i in reverse(1:L) + if i > L - half_screen_rows || i < half_screen_rows + println(io, "┼─[$i]─ ", physicalspace(mpo, i)) + println(io, "│ ", left_virtualspace(mpo, i)) + elseif i == half_screen_rows + println(io, "│ ⋮") + println(io, "│ ", left_virtualspace(mpo, i)) + end + end + println(io, "| ⋮") + end + + return nothing +end + +function Base.summary(io::IO, envs::Union{FiniteEnvironments, InfiniteEnvironments}) + print(io, length(envs.GLs), "-site ") + Base.showarg(io, envs, true) + return nothing +end + +function Base.show(io::IO, ::MIME"text/plain", envs::Union{InfiniteEnvironments, FiniteEnvironments}) + Base.summary(io, envs) + get(io, :compact, false)::Bool && return nothing + println(io, ":") + + for i in reverse(eachindex(envs.GLs)) + println(io, "GL[$i]: ", space(envs.GLs[i])) + end + for i in reverse(eachindex(envs.GRs)) + println(io, "GR[$i]: ", space(envs.GRs[i])) + end + + return nothing +end + +# braille +# ------- +""" + braille(io::IO, H::Union{SparseMPO, MPOHamiltonian}) + braille(H::Union{SparseMPO, MPOHamiltonian}) + +Prints a compact, human-readable "braille" visualization of a sparseMPO or MPOHamiltonian. +Each site of the MPO is represented as a block of Unicode braille characters, with sites separated by dashes. +This visualization is useful for quickly inspecting the structure and sparsity pattern of MPOs. + +# Arguments +- `io::IO`: The output stream to print to (e.g., `stdout`). +- `H::Union{SparseMPO, MPOHamiltonian}`: The `SparseMPO` or `MPOHamiltonian` to visualize. + +If called without an `io` argument, output is printed to `stdout`. +""" +function braille(io::IO, H::Union{SparseMPO, MPOHamiltonian}) + dash = "🭻" + stride = 2 #amount of dashes between braille + L = length(H) + + brailles = Vector{Vector{String}}(undef, L) + buffer = IOBuffer() + for (i, W) in enumerate(H) + BlockTensorKit.show_braille(buffer, W) + brailles[i] = split(String(take!(buffer))) + end + + maxheight = maximum(length.(brailles)) + + for i in 1:maxheight + line = "" + line *= ((i == 1 && !isfinite(H)) ? ("... " * dash) : " ") + line *= (i > 1 && !isfinite(H)) ? " " : "" + for (j, braille) in enumerate(brailles) + line *= ( + checkbounds(Bool, braille, i) ? braille[i] : repeat(" ", length(braille[1])) + ) + if j < L + line *= repeat(((i == 1) ? dash : " "), stride) + end + end + line *= ((i == 1 && !isfinite(H)) ? (dash * " ...") : " ") + println(io, line) + end + return nothing +end + +braille(H::Union{SparseMPO, MPOHamiltonian}) = braille(stdout, H)