From 7364ef3eb99e03932b430109e77033966484d394 Mon Sep 17 00:00:00 2001 From: Jutho Haegeman Date: Wed, 3 Dec 2025 23:42:21 +0100 Subject: [PATCH 1/6] further tweak tensor and block show --- src/tensors/abstracttensor.jl | 27 +++++++++++++------------- src/tensors/blockiterator.jl | 36 ++++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/tensors/abstracttensor.jl b/src/tensors/abstracttensor.jl index 4e28000ed..47bdd304c 100644 --- a/src/tensors/abstracttensor.jl +++ b/src/tensors/abstracttensor.jl @@ -652,22 +652,21 @@ function Base.show(io::IO, mime::MIME"text/plain", t::AbstractTensorMap) # 1) show summary: typically d₁×d₂×… ← d₃×d₄×… $(typeof(t)) summary(io, t) - # case without `\n`: - if get(io, :compact, true) + if get(io, :compact, false) + # case without `\n`: print(io, "(…, ") show(io, mime, space(t)) print(io, ')') - return nothing + else + # case with `\n` + # 2) show spaces + println(io, ':') + println(io, " codomain: ", codomain(t)) + println(io, " domain: ", domain(t)) + # 3) show data + println(io, " blocks: ") + (numlines, numcols) = get(io, :displaysize, displaysize(io)) + newio = IOContext(io, :displaysize => (numlines - 4, numcols)) + show_blocks(newio, mime, blocks(t)) end - - # case with `\n` - # 2) show spaces - println(io, ':') - println(io, " codomain: ", codomain(t)) - println(io, " domain: ", domain(t)) - - # 3) [optional]: show data - println(io, "\n\n blocks: ") - show_blocks(io, mime, blocks(t)) - return nothing end diff --git a/src/tensors/blockiterator.jl b/src/tensors/blockiterator.jl index e5f5e562a..8bef00523 100644 --- a/src/tensors/blockiterator.jl +++ b/src/tensors/blockiterator.jl @@ -46,12 +46,32 @@ function foreachblock(f, t::AbstractTensorMap; scheduler = nothing) end function show_blocks(io, mime::MIME"text/plain", iter) - first = true - for (c, b) in iter - first || print(io, "\n\n") - print(io, " * ", c, " => ") - show(io, mime, b) - first = false + numlinesleft, numcols = get(io, :displaysize, displaysize(io)) + # lines of headers should already have been subtracted, but not the 3 spare lines for old and new prompts + maxnumlinesperblock = max(div(numlinesleft - 4, min(3, length(iter))), 7) + # aim to show at least 3 blocks, but not if this means that there + # would be less than 7 lines per block (= 5 lines for the actual matrix) + # we deduct 4 lines to leave space for a truncation message and prompts + for (n, (c, b)) in enumerate(iter) + n == 1 || print(io, "\n\n") + if get(io, :limit, false) + numlinesneeded = min(size(b, 1) + 2, maxnumlinesperblock) + if numlinesleft >= numlinesneeded + 4 + # we can still print at least this block, and have one line + # for the truncation message and 3 more lines for old and new prompts + print(io, " * ", c, " => ") + newio = IOContext(io, :displaysize => (maxnumlinesperblock - 1 + 3, numcols)) + # subtract 1 line for the newline, but add 3 because of how matrices are printed + show(newio, mime, b) + numlinesleft -= numlinesneeded + else + print(io, " * ", " \u2026 [output of ", length(iter) - n + 1, " more block(s) truncated]") + break + end + else + print(io, " * ", c, " => ") + show(io, mime, b) + end end return nothing end @@ -73,7 +93,9 @@ end function Base.show(io::IO, mime::MIME"text/plain", b::BlockIterator) summary(io, b) println(io, ":") - show_blocks(io, mime, b) + (numlines, numcols) = get(io, :displaysize, displaysize(io)) + newio = IOContext(io, :displaysize => (numlines - 1, numcols)) + show_blocks(newio, mime, b) return nothing end From 5e48a37362bccccd6d16e3b0e444db60b61b459d Mon Sep 17 00:00:00 2001 From: Jutho Haegeman Date: Thu, 4 Dec 2025 00:04:22 +0100 Subject: [PATCH 2/6] some more finetuning and code improvement --- src/tensors/blockiterator.jl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/tensors/blockiterator.jl b/src/tensors/blockiterator.jl index 8bef00523..5133e54ce 100644 --- a/src/tensors/blockiterator.jl +++ b/src/tensors/blockiterator.jl @@ -47,18 +47,22 @@ end function show_blocks(io, mime::MIME"text/plain", iter) numlinesleft, numcols = get(io, :displaysize, displaysize(io)) - # lines of headers should already have been subtracted, but not the 3 spare lines for old and new prompts - maxnumlinesperblock = max(div(numlinesleft - 4, min(3, length(iter))), 7) + numlinesleft -= 2 + # lines of headers should already have been subtracted, but not the 2 spare lines for old and new prompts + minlinesperblock = 7 + minnumberofblocks = min(3, length(iter)) # aim to show at least this many blocks + truncateblocks = sum(cb->min(size(cb[2], 1) + 2, minlinesperblock), iter; init = 0) > numlinesleft + maxnumlinesperblock = max(div(numlinesleft - 2 * truncateblocks, minnumberofblocks), minlinesperblock) # aim to show at least 3 blocks, but not if this means that there # would be less than 7 lines per block (= 5 lines for the actual matrix) - # we deduct 4 lines to leave space for a truncation message and prompts + # we deduct a line for a truncation message depending on truncateblocks for (n, (c, b)) in enumerate(iter) n == 1 || print(io, "\n\n") if get(io, :limit, false) numlinesneeded = min(size(b, 1) + 2, maxnumlinesperblock) - if numlinesleft >= numlinesneeded + 4 - # we can still print at least this block, and have one line - # for the truncation message and 3 more lines for old and new prompts + if numlinesleft >= numlinesneeded + 2 * truncateblocks + # we can still print at least this block, and have two lines for + # the truncation message (and its newline) if it is required print(io, " * ", c, " => ") newio = IOContext(io, :displaysize => (maxnumlinesperblock - 1 + 3, numcols)) # subtract 1 line for the newline, but add 3 because of how matrices are printed From 4bbd0d1082dbe14acc7cb673ec8cd4f2d1fbbfa6 Mon Sep 17 00:00:00 2001 From: Jutho Haegeman Date: Thu, 4 Dec 2025 00:07:40 +0100 Subject: [PATCH 3/6] more code comments --- src/tensors/blockiterator.jl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/tensors/blockiterator.jl b/src/tensors/blockiterator.jl index 5133e54ce..fcbe8dcf1 100644 --- a/src/tensors/blockiterator.jl +++ b/src/tensors/blockiterator.jl @@ -47,15 +47,13 @@ end function show_blocks(io, mime::MIME"text/plain", iter) numlinesleft, numcols = get(io, :displaysize, displaysize(io)) - numlinesleft -= 2 - # lines of headers should already have been subtracted, but not the 2 spare lines for old and new prompts - minlinesperblock = 7 + numlinesleft -= 2 # lines of headers have already been subtracted, but not the 2 spare lines for old and new prompts + minlinesperblock = 7 # aim to have at least this many lines per printed block (= 5 lines for the actual matrix) minnumberofblocks = min(3, length(iter)) # aim to show at least this many blocks truncateblocks = sum(cb->min(size(cb[2], 1) + 2, minlinesperblock), iter; init = 0) > numlinesleft maxnumlinesperblock = max(div(numlinesleft - 2 * truncateblocks, minnumberofblocks), minlinesperblock) - # aim to show at least 3 blocks, but not if this means that there - # would be less than 7 lines per block (= 5 lines for the actual matrix) - # we deduct a line for a truncation message depending on truncateblocks + # aim to show at least minnumberofblocks, but not if this means that there would be less than minlinesperblock + # deduct two lines for a truncation message (and newline) if needed for (n, (c, b)) in enumerate(iter) n == 1 || print(io, "\n\n") if get(io, :limit, false) From dbeaab2960c2f5b227770ffc52536a93f30f3983 Mon Sep 17 00:00:00 2001 From: Jutho Haegeman Date: Thu, 4 Dec 2025 21:14:52 +0100 Subject: [PATCH 4/6] more changes and formatting --- src/tensors/abstracttensor.jl | 1 + src/tensors/blockiterator.jl | 33 +++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/tensors/abstracttensor.jl b/src/tensors/abstracttensor.jl index 47bdd304c..7eeb3af9d 100644 --- a/src/tensors/abstracttensor.jl +++ b/src/tensors/abstracttensor.jl @@ -669,4 +669,5 @@ function Base.show(io::IO, mime::MIME"text/plain", t::AbstractTensorMap) newio = IOContext(io, :displaysize => (numlines - 4, numcols)) show_blocks(newio, mime, blocks(t)) end + return nothing end diff --git a/src/tensors/blockiterator.jl b/src/tensors/blockiterator.jl index fcbe8dcf1..f36afae65 100644 --- a/src/tensors/blockiterator.jl +++ b/src/tensors/blockiterator.jl @@ -45,18 +45,18 @@ function foreachblock(f, t::AbstractTensorMap; scheduler = nothing) return nothing end -function show_blocks(io, mime::MIME"text/plain", iter) - numlinesleft, numcols = get(io, :displaysize, displaysize(io)) - numlinesleft -= 2 # lines of headers have already been subtracted, but not the 2 spare lines for old and new prompts - minlinesperblock = 7 # aim to have at least this many lines per printed block (= 5 lines for the actual matrix) - minnumberofblocks = min(3, length(iter)) # aim to show at least this many blocks - truncateblocks = sum(cb->min(size(cb[2], 1) + 2, minlinesperblock), iter; init = 0) > numlinesleft - maxnumlinesperblock = max(div(numlinesleft - 2 * truncateblocks, minnumberofblocks), minlinesperblock) - # aim to show at least minnumberofblocks, but not if this means that there would be less than minlinesperblock - # deduct two lines for a truncation message (and newline) if needed - for (n, (c, b)) in enumerate(iter) - n == 1 || print(io, "\n\n") - if get(io, :limit, false) +function show_blocks(io, mime::MIME"text/plain", iter; maytruncate::Bool = true) + if maytruncate && get(io, :limit, false) + numlinesleft, numcols = get(io, :displaysize, displaysize(io)) + numlinesleft -= 2 # lines of headers have already been subtracted, but not the 2 spare lines for old and new prompts + minlinesperblock = 7 # aim to have at least this many lines per printed block (= 5 lines for the actual matrix) + minnumberofblocks = min(3, length(iter)) # aim to show at least this many blocks + truncateblocks = sum(cb -> min(size(cb[2], 1) + 2, minlinesperblock), iter; init = 0) > numlinesleft + maxnumlinesperblock = max(div(numlinesleft - 2 * truncateblocks, minnumberofblocks), minlinesperblock) + # aim to show at least minnumberofblocks, but not if this means that there would be less than minlinesperblock + # deduct two lines for a truncation message (and newline) if needed + for (n, (c, b)) in enumerate(iter) + n == 1 || print(io, "\n\n") numlinesneeded = min(size(b, 1) + 2, maxnumlinesperblock) if numlinesleft >= numlinesneeded + 2 * truncateblocks # we can still print at least this block, and have two lines for @@ -70,9 +70,14 @@ function show_blocks(io, mime::MIME"text/plain", iter) print(io, " * ", " \u2026 [output of ", length(iter) - n + 1, " more block(s) truncated]") break end - else + end + else + first = true + for (c, b) in iter + first || print(io, "\n\n") print(io, " * ", c, " => ") show(io, mime, b) + first = false end end return nothing @@ -97,7 +102,7 @@ function Base.show(io::IO, mime::MIME"text/plain", b::BlockIterator) println(io, ":") (numlines, numcols) = get(io, :displaysize, displaysize(io)) newio = IOContext(io, :displaysize => (numlines - 1, numcols)) - show_blocks(newio, mime, b) + show_blocks(newio, mime, b; maytruncate = false) return nothing end From d409741de929b162929e19b12777a06c991fc7c7 Mon Sep 17 00:00:00 2001 From: Jutho Date: Thu, 4 Dec 2025 22:37:54 +0100 Subject: [PATCH 5/6] add type assertion for stability Co-authored-by: Lukas Devos --- src/tensors/blockiterator.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tensors/blockiterator.jl b/src/tensors/blockiterator.jl index f36afae65..d33cb0f4a 100644 --- a/src/tensors/blockiterator.jl +++ b/src/tensors/blockiterator.jl @@ -47,7 +47,7 @@ end function show_blocks(io, mime::MIME"text/plain", iter; maytruncate::Bool = true) if maytruncate && get(io, :limit, false) - numlinesleft, numcols = get(io, :displaysize, displaysize(io)) + numlinesleft, numcols = get(io, :displaysize, displaysize(io))::Tuple{Int, Int} numlinesleft -= 2 # lines of headers have already been subtracted, but not the 2 spare lines for old and new prompts minlinesperblock = 7 # aim to have at least this many lines per printed block (= 5 lines for the actual matrix) minnumberofblocks = min(3, length(iter)) # aim to show at least this many blocks @@ -100,7 +100,7 @@ end function Base.show(io::IO, mime::MIME"text/plain", b::BlockIterator) summary(io, b) println(io, ":") - (numlines, numcols) = get(io, :displaysize, displaysize(io)) + (numlines, numcols) = get(io, :displaysize, displaysize(io))::Tuple{Int, Int} newio = IOContext(io, :displaysize => (numlines - 1, numcols)) show_blocks(newio, mime, b; maytruncate = false) return nothing From 628ae4afe6dea2ea0bad35c7a48ad180a5a134c1 Mon Sep 17 00:00:00 2001 From: Jutho Haegeman Date: Thu, 4 Dec 2025 23:35:37 +0100 Subject: [PATCH 6/6] add some show testing --- test/tensors/tensors.jl | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/tensors/tensors.jl b/test/tensors/tensors.jl index 43481e7d1..0d932cdc7 100644 --- a/test/tensors/tensors.jl +++ b/test/tensors/tensors.jl @@ -624,3 +624,52 @@ end end end end + +@timedtestset "show tensors" begin + for V in (ℂ^2, Z2Space(0 => 2, 1 => 2), SU2Space(0 => 2, 1 => 2)) + t1 = ones(Float32, V ⊗ V, V) + t2 = randn(ComplexF64, V ⊗ V ⊗ V) + # test unlimited output + for t in (t1, t2, t1', t2') + output = IOBuffer() + summary(output, t) + print(output, ":\n codomain: ") + show(output, MIME("text/plain"), codomain(t)) + print(output, "\n domain: ") + show(output, MIME("text/plain"), domain(t)) + print(output, "\n blocks: \n") + first = true + for (c, b) in blocks(t) + first || print(output, "\n\n") + print(output, " * ") + show(output, MIME("text/plain"), c) + print(output, " => ") + show(output, MIME("text/plain"), b) + first = false + end + outputstr = String(take!(output)) + @test outputstr == sprint(show, MIME("text/plain"), t) + end + + # test limited output with a single block + t = randn(Float64, V ⊗ V, V)' # we know there is a single space in the codomain, so that blocks have 2 rows + output = IOBuffer() + summary(output, t) + print(output, ":\n codomain: ") + show(output, MIME("text/plain"), codomain(t)) + print(output, "\n domain: ") + show(output, MIME("text/plain"), domain(t)) + print(output, "\n blocks: \n") + c = unit(sectortype(t)) + b = block(t, c) + print(output, " * ") + show(output, MIME("text/plain"), c) + print(output, " => ") + show(output, MIME("text/plain"), b) + if length(blocks(t)) > 1 + print(output, "\n\n * … [output of 1 more block(s) truncated]") + end + outputstr = String(take!(output)) + @test outputstr == sprint(show, MIME("text/plain"), t; context = (:limit => true, :displaysize => (12, 100))) + end +end