changeset 2060:797553341212 feature/lazy_tensors/pretty_printing tip

Merge default
author Jonatan Werpers <jonatan@werpers.com>
date Sat, 14 Feb 2026 23:38:32 +0100
parents 8a2a0d678d6f (diff) 377df47849cb (current diff)
children
files
diffstat 5 files changed, 109 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Notes.md	Sat Feb 14 23:37:40 2026 +0100
+++ b/Notes.md	Sat Feb 14 23:38:32 2026 +0100
@@ -107,6 +107,14 @@
 dictionary-structure containing stencils, tuples, scalars and other types
 ready for input to the methods creating the operators.
 
+## Pretty printing
+From the documentation of `show` it seems that the correct way to setup
+printing of instances is to let `show(x)` print valid julia code for creating
+the instance if possible. With a specified MIME type
+`show(::IO, ::MIME"text/plain", x)` should print a human readable, possible
+more verbose version. Compare to what the standard library does for regular
+vectors.
+
 ## Known size of range and domain?
 Is there any reason to use a trait to differentiate between fixed size and unknown size?
 
--- a/src/LazyTensors/lazy_tensor_operations.jl	Sat Feb 14 23:37:40 2026 +0100
+++ b/src/LazyTensors/lazy_tensor_operations.jl	Sat Feb 14 23:38:32 2026 +0100
@@ -140,6 +140,7 @@
     apply_transpose(c.t2, c.t1'*v, I...)
 end
 
+
 """
     TensorComposition(tm, tmi::IdentityTensor)
     TensorComposition(tmi::IdentityTensor, tm)
@@ -257,6 +258,15 @@
     return apply_transpose(itm.tm, v_inner, inner_index...)
 end
 
+function Base.show(io::IO, ::MIME"text/plain", tm::InflatedTensor{T}) where T
+    show(IOContext(io, :compact=>true), MIME("text/plain"), tm.before)
+    print(io, "⊗")
+    # if get(io, :compact, false)
+    show(io, MIME("text/plain"), tm.tm)
+    print(io, "⊗")
+    show(IOContext(io, :compact=>true), MIME("text/plain"), tm.after)
+end
+
 
 @doc raw"""
     LazyOuterProduct(tms...)
--- a/src/LazyTensors/tensor_types.jl	Sat Feb 14 23:37:40 2026 +0100
+++ b/src/LazyTensors/tensor_types.jl	Sat Feb 14 23:38:32 2026 +0100
@@ -18,6 +18,17 @@
 apply(tmi::IdentityTensor{T,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,D}) where {T,D} = v[I...]
 apply_transpose(tmi::IdentityTensor{T,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,D}) where {T,D} = v[I...]
 
+function Base.show(io::IO, tm::IdentityTensor{T}) where T
+    if get(io, :compact, false)
+        print(io, "I")
+    else
+        print(io, "IdentityTensor{$T}")
+    end
+    print(io, "(")
+    join(io, tm.size, ",")
+    print(io, ")")
+end
+
 
 """
     ScalingTensor{T,D} <: LazyTensor{T,D,D}
@@ -35,6 +46,18 @@
 LazyTensors.range_size(m::ScalingTensor) = m.size
 LazyTensors.domain_size(m::ScalingTensor) = m.size
 
+function Base.show(io::IO, tm::ScalingTensor{T}) where T
+    if get(io, :compact, false)
+        print(io, "$(tm.λ)*I(")
+        join(io, tm.size, ",")
+        print(io, ")")
+    else
+        print(io, "ScalingTensor(")
+        print(io, tm.λ, ", ")
+        print(io, tm.size)
+        print(io, ")")
+    end
+end
 
 """
     DiagonalTensor{T,D,...} <: LazyTensor{T,D,D}
@@ -49,10 +72,21 @@
 range_size(tm::DiagonalTensor) = size(tm.diagonal)
 domain_size(tm::DiagonalTensor) = size(tm.diagonal)
 
-
 LazyTensors.apply(tm::DiagonalTensor{T,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,D}) where {T,D} = tm.diagonal[I...]*v[I...]
 LazyTensors.apply_transpose(tm::DiagonalTensor{T,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,D}) where {T,D} = tm.diagonal[I...]*v[I...]
 
+function Base.show(io::IO, tm::DiagonalTensor)
+    print(io, "DiagonalTensor(")
+    print(io, tm.diagonal)
+    print(io, ")")
+end
+
+function Base.show(io::IO, ::MIME"text/plain", tm::DiagonalTensor{T,D}) where {T,D}
+    println(io, "DiagonalTensor{$T, $D}:")
+    Base.print_array(io, tm.diagonal)
+    print(io, "\n")
+end
+
 
 """
     DenseTensor{T,R,D,...}(A, range_indicies, domain_indicies)
--- a/test/LazyTensors/lazy_tensor_operations_test.jl	Sat Feb 14 23:37:40 2026 +0100
+++ b/test/LazyTensors/lazy_tensor_operations_test.jl	Sat Feb 14 23:38:32 2026 +0100
@@ -367,6 +367,20 @@
 
         @test InflatedTensor(I(2), I(2), I(2)) isa InflatedTensor # The constructor should always return its type.
     end
+
+    @testset "Pretty printing" begin
+        cases = [
+            InflatedTensor(I(4), ScalingTensor(2., (3,2)), I(2)) => (
+                regular="I(4)⊗ScalingTensor{Float64}(2.0, (3, 2))⊗I(2)",
+                compact="I(4)⊗2.0*I(3,2)⊗I(2)"
+            )
+        ]
+
+        @testset "$tm" for (tm, r) ∈ cases
+            @test repr(MIME("text/plain"), tm) == r.regular
+            @test repr(MIME("text/plain"), tm, context=:compact=>true) == r.compact
+        end
+    end
 end
 
 @testset "LazyOuterProduct" begin
--- a/test/LazyTensors/tensor_types_test.jl	Sat Feb 14 23:37:40 2026 +0100
+++ b/test/LazyTensors/tensor_types_test.jl	Sat Feb 14 23:38:32 2026 +0100
@@ -42,6 +42,17 @@
     @test_throws DomainSizeMismatch I1∘A
     @test_throws DomainSizeMismatch A∘I2
     @test_throws DomainSizeMismatch I1∘I2
+
+    @testset "Pretty printing" begin
+        @test repr(IdentityTensor{Float64}(5)) == "IdentityTensor{Float64}(5)"
+        @test repr(IdentityTensor{Int}(4,5)) == "IdentityTensor{Int64}(4,5)"
+
+        @test repr(MIME("text/plain"), IdentityTensor{Float64}(5)) == "IdentityTensor{Float64}(5)"
+        @test repr(MIME("text/plain"), IdentityTensor{Int}(4,5)) == "IdentityTensor{Int64}(4,5)"
+
+        @test repr(MIME("text/plain"), IdentityTensor{Float64}(5), context=:compact=>true) == "I(5)"
+        @test repr(MIME("text/plain"), IdentityTensor{Int}(4,5), context=:compact=>true) == "I(4,5)"
+    end
 end
 
 
@@ -57,6 +68,17 @@
 
     @inferred (st*v)[2,2]
     @inferred (st'*v)[2,2]
+
+    @testset "Pretty printing" begin
+        @test repr(ScalingTensor(2., (5,))) == "ScalingTensor(2.0, (5,))"
+        @test repr(ScalingTensor(3, (4,5))) == "ScalingTensor(3, (4, 5))"
+
+        @test repr(MIME("text/plain"), ScalingTensor(2., (5,))) == "ScalingTensor(2.0, (5,))"
+        @test repr(MIME("text/plain"), ScalingTensor(3, (4,5))) == "ScalingTensor(3, (4, 5))"
+
+        @test repr(MIME("text/plain"), ScalingTensor(4., (5,)), context=:compact=>true) == "4.0*I(5)"
+        @test repr(MIME("text/plain"), ScalingTensor(2, (4,5)), context=:compact=>true) == "2*I(4,5)"
+    end
 end
 
 @testset "DiagonalTensor" begin
@@ -98,6 +120,26 @@
     v = rand(sz...)
     LazyTensors.apply(tm,v, 2,1)
     @test (@ballocated LazyTensors.apply($tm,$v, 2,1)) == 0
+
+
+    @testset "Pretty printing" begin
+        @test repr(DiagonalTensor([1,2,3,4])) == "DiagonalTensor([1, 2, 3, 4])"
+        @test repr(DiagonalTensor([1.,1.,1.])) == "DiagonalTensor([1.0, 1.0, 1.0])"
+
+        @test repr(MIME("text/plain"), DiagonalTensor([1,2,3,4])) == """
+        DiagonalTensor{Int64, 1}:
+         1
+         2
+         3
+         4
+        """
+        @test repr(MIME("text/plain"), DiagonalTensor([1.,1.,1.])) == """
+        DiagonalTensor{Float64, 1}:
+         1.0
+         1.0
+         1.0
+        """
+    end
 end