diff --git a/Project.toml b/Project.toml index 9a7a204..ee80b10 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "BlockTensorKit" uuid = "5f87ffc2-9cf1-4a46-8172-465d160bd8cd" authors = ["Lukas Devos and contributors"] -version = "0.3.0" +version = "0.3.1" [deps] BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" @@ -25,7 +25,7 @@ MatrixAlgebraKit = "0.5" Random = "1" SafeTestsets = "0.1" Strided = "2" -TensorKit = "0.15" +TensorKit = "0.15.2" TensorOperations = "5" Test = "1" TestExtras = "0.2, 0.3" diff --git a/src/tensors/abstractblocktensor/abstractarray.jl b/src/tensors/abstractblocktensor/abstractarray.jl index 9211fa9..41a1623 100644 --- a/src/tensors/abstractblocktensor/abstractarray.jl +++ b/src/tensors/abstractblocktensor/abstractarray.jl @@ -142,6 +142,14 @@ end setindex!(parent(t), v, args...); t ) +# ambiguity fix +function Base.setindex!(::AbstractBlockTensorMap, ::AbstractTensorMap, sectors::Tuple{I, Vararg{I}}) where {I <: Sector} + error("invalid indexing for blocktensormap") +end +function Base.setindex!(::AbstractBlockTensorMap, ::AbstractTensorMap, ::FusionTree, ::FusionTree) + error("invalid indexing for blocktensormap") +end + # setindex verifies structure is correct @inline function Base.setindex!( t::AbstractBlockTensorMap, v::AbstractTensorMap, indices::Vararg{SliceIndex} diff --git a/src/tensors/abstractblocktensor/abstracttensormap.jl b/src/tensors/abstractblocktensor/abstracttensormap.jl index fee2344..af33901 100644 --- a/src/tensors/abstractblocktensor/abstracttensormap.jl +++ b/src/tensors/abstractblocktensor/abstracttensormap.jl @@ -10,15 +10,14 @@ end eachspace(t::AbstractBlockTensorMap) = SumSpaceIndices(space(t)) -# TODO: delete this method -@inline function Base.getindex(t::AbstractBlockTensorMap, ::Nothing, ::Nothing) - sectortype(t) === Trivial || throw(SectorMismatch()) - return mortar(map(x -> x[nothing, nothing], parent(t))) -end -@inline function Base.getindex( - t::AbstractBlockTensorMap{E, S, N₁, N₂}, f₁::FusionTree{I, N₁}, f₂::FusionTree{I, N₂} - ) where {E, S, I, N₁, N₂} - sectortype(S) === I || throw(SectorMismatch()) +@inline function TensorKit.subblock( + t::AbstractBlockTensorMap, (f₁, f₂)::Tuple{FusionTree, FusionTree} + ) + sectortype(t) === sectortype(f₁) === sectortype(f₂) || + throw(SectorMismatch("Not a valid sectortype for this tensor")) + numout(t) == length(f₁) && numin(t) == length(f₂) || + throw(DimensionMismatch("Invalid number of fusiontree legs for this tensor")) + subblocks = map(eachspace(t), parent(t)) do V, x sz = (dims(codomain(V), f₁.uncoupled)..., dims(domain(V), f₂.uncoupled)...) if prod(sz) == 0 @@ -28,6 +27,7 @@ end return x[f₁, f₂] end end + return mortar(subblocks) end @inline function Base.setindex!( diff --git a/src/tensors/abstractblocktensor/show.jl b/src/tensors/abstractblocktensor/show.jl index 919547f..c783d91 100644 --- a/src/tensors/abstractblocktensor/show.jl +++ b/src/tensors/abstractblocktensor/show.jl @@ -1,13 +1,10 @@ # Show # ---- -function Base.show(io::IO, t::AbstractBlockTensorMap) - summary(io, t) - get(io, :compact, false) && return nothing - println(io, ":") - for (c, b) in TensorKit.blocks(t) - println(io, "* Block for sector $c:") - show(io, b) - end +function Base.summary(io::IO, t::AbstractBlockTensorMap) + V = space(t) + sz = size(t) + print(io, Base.dims2string(sz), "-blocked ", Base.dims2string(V), " ") + Base.showarg(io, t, true) return nothing end @@ -15,9 +12,14 @@ function Base.show(io::IO, ::MIME"text/plain", t::AbstractBlockTensorMap) # header: summary(io, t) nnz = nonzero_length(t) - println( - io, " with ", nnz, " stored entr", isone(nnz) ? "y" : "ies", iszero(nnz) ? "" : ":" - ) + if issparse(t) + println( + io, " with ", nnz, " stored entr", isone(nnz) ? "y" : "ies", iszero(nnz) ? "" : ":" + ) + end + println(io, ":") + println(io, " codomain: ", codomain(t)) + println(io, " domain: ", domain(t)) # body: compact = get(io, :compact, false)::Bool @@ -44,7 +46,10 @@ function show_elements(io::IO, x::AbstractBlockTensorMap) nz_pairs = sort(vec(collect(nonzero_pairs(x))); by = first) for (k, (ind, val)) in enumerate(nz_pairs) if k < half_screen_rows || k > length(nzind) - half_screen_rows - println(io, " ", '[', Base.join(lpad.(Tuple(ind), pads), ","), "] = ", val) + print(io, " ", '[', Base.join(lpad.(Tuple(ind), pads), ","), "] = ") + show(io, MIME"text/plain"(), val) + println(io) + elseif k == half_screen_rows println(io, " ", Base.join(" " .^ pads, " "), " \u22ee") end diff --git a/src/tensors/blocktensor.jl b/src/tensors/blocktensor.jl index 9a0d374..8fb6258 100644 --- a/src/tensors/blocktensor.jl +++ b/src/tensors/blocktensor.jl @@ -175,22 +175,18 @@ Base.delete!(t::BlockTensorMap, I...) = (zerovector!(getindex(t, I...)); t) # Show # ---- -function Base.summary(io::IO, t::BlockTensorMap) - szstring = Base.dims2string(size(t)) - TT = eltype(t) - typeinfo = get(io, :typeinfo, Any) - if typeinfo <: typeof(t) || typeinfo <: TT - typestring = "" - else - typestring = "{$TT}" - end - V = space(t) - return print(io, "$szstring BlockTensorMap$typestring($V)") +function Base.showarg(io::IO, t::BlockTensorMap, toplevel::Bool) + !toplevel && print(io, "::") + print(io, TK.type_repr(typeof(t))) + return nothing +end + +function TK.type_repr(::Type{BlockTensorMap{T, E, S, N₁, N₂, N}}) where {T, E, S, N₁, N₂, N} + return "BlockTensorMap{" * TK.type_repr(T) * ", …}" end # Converters # ---------- - function Base.promote_rule( ::Type{<:BlockTensorMap{TT₁}}, ::Type{<:BlockTensorMap{TT₂}} ) where {TT₁, TT₂} diff --git a/src/tensors/sparseblocktensor.jl b/src/tensors/sparseblocktensor.jl index a8b7682..2618805 100644 --- a/src/tensors/sparseblocktensor.jl +++ b/src/tensors/sparseblocktensor.jl @@ -181,15 +181,12 @@ end # Show # ---- -function Base.summary(io::IO, t::SparseBlockTensorMap) - szstring = Base.dims2string(size(t)) - TT = eltype(t) - typeinfo = get(io, :typeinfo, Any) - if typeinfo <: typeof(t) || typeinfo <: TT - typestring = "" - else - typestring = "{$TT}" - end - V = space(t) - return print(io, "$szstring SparseBlockTensorMap$typestring($V)") +function Base.showarg(io::IO, t::SparseBlockTensorMap, toplevel::Bool) + !toplevel && print(io, "::") + print(io, TK.type_repr(typeof(t))) + return nothing +end + +function TK.type_repr(::Type{SparseBlockTensorMap{T, E, S, N₁, N₂, N}}) where {T, E, S, N₁, N₂, N} + return "SparseBlockTensorMap{" * join((TK.type_repr(T), E, TK.type_repr(S), N₁, N₂, N), ", ") * "}" end diff --git a/src/vectorspaces/sumspace.jl b/src/vectorspaces/sumspace.jl index 2c8ac45..3b1fda6 100644 --- a/src/vectorspaces/sumspace.jl +++ b/src/vectorspaces/sumspace.jl @@ -161,16 +161,15 @@ TensorKit.infimum(V::S, W::S) where {S <: SumSpace} = infimum(⊕(V), ⊕(W)) TensorKit.supremum(V::S, W::S) where {S <: SumSpace} = supremum(⊕(V), ⊕(W)) TensorKit.ominus(V::S, W::S) where {S <: SumSpace} = ominus(⊕(V), ⊕(W)) -TensorKit.oplus(V::SumSpace{S}) where {S} = reduce(⊕, V.spaces; init = isdual(V) ? zero(S)' : zero(S)) +TensorKit.oplus(V::SumSpace{S}) where {S} = reduce(⊕, V.spaces; init = isdual(V) ? zerospace(S)' : zerospace(S)) TensorKit.oplus(V1::SumSpace{S}, V2::SumSpace{S}...) where {S} = mapreduce(⊕, ⊕, (V1, V2...)) function TensorKit.fuse(V1::S, V2::S) where {S <: SumSpace} return SumSpace(vec([fuse(v1, v2) for (v1, v2) in Base.product(V1.spaces, V2.spaces)])) end -Base.oneunit(S::Type{<:SumSpace}) = SumSpace(oneunit(eltype(S))) -Base.zero(V::SumSpace{S}) where {S} = SumSpace{S}(; dual = isdual(V)) -Base.zero(::Type{SumSpace{S}}) where {S} = SumSpace{S}() +TensorKit.unitspace(S::Type{<:SumSpace}) = SumSpace(TensorKit.unitspace(eltype(S))) +TensorKit.zerospace(::Type{SumSpace{S}}) where {S} = SumSpace{S}() # Promotion and conversion # ------------------------ @@ -228,19 +227,40 @@ function Base.show(io::IO, V::SumSpace) end limited = get(io, :limited, true) + ioc = IOContext(io, :compact => true) if limited && length(V) > SUMSPACE_SHOW_LIMIT[] ax = axes(V.spaces, 1) f, l = first(ax), last(ax) h = SUMSPACE_SHOW_LIMIT[] ÷ 2 - Base.show_delim_array(io, V.spaces, "(", " ⊞", "", false, f, f + h) + Base.show_delim_array(ioc, V.spaces, "(", " ⊞", "", false, f, f + h) print(io, " ⊞ ⋯ ⊞ ") - Base.show_delim_array(io, V.spaces, "", " ⊞", ")", false, l - h, l) + Base.show_delim_array(ioc, V.spaces, "", " ⊞", ")", false, l - h, l) else - Base.show_delim_array(io, V.spaces, "(", " ⊞", ")", false) + Base.show_delim_array(ioc, V.spaces, "(", " ⊞", ")", false) end return nothing end +function Base.show(io::IO, ::MIME"text/plain", V::SumSpace) + # print small summary, e.g.: l-element SumSpace(Vect[I](…)) of dim d + l = length(V.spaces) + d = dim(V) + print(io, l, "-element ⊞(::", TK.type_repr(eltype(V)), "…)") + isdual(V) && print(io, "'") + print(io, " of dim ", d) + + compact = get(io, :compact, false)::Bool + (iszero(d) || compact) && return nothing + + # print detailed space information - hijack Base.Vector printing + print(io, ":\n") + print_data = V.spaces + ioc = IOContext(io, :typeinfo => eltype(print_data)) + Base.print_matrix(ioc, print_data) + + return nothing +end + # TensorMapSumSpace # ----------------- # function TensorKit.fusionblockstructure( diff --git a/test/abstracttensor/blocktensor.jl b/test/abstracttensor/blocktensor.jl index a2df900..9eff209 100644 --- a/test/abstracttensor/blocktensor.jl +++ b/test/abstracttensor/blocktensor.jl @@ -117,7 +117,7 @@ end @test i1 * i2 == @constinferred(id(storagetype(t), V1 ⊗ V2)) @test i2 * i1 == @constinferred(id(storagetype(t), V2 ⊗ V1)) - w = @constinferred(isometry(storagetype(t), V1 ⊗ (oneunit(V1) ⊕ oneunit(V1)), V1)) + w = @constinferred(isometry(storagetype(t), V1 ⊗ (unitspace(V1) ⊕ unitspace(V1)), V1)) @test dim(w) == 2 * dim(V1 ← V1) @test w' * w == id(storagetype(t), V1) @test w * w' == (w * w')^2 diff --git a/test/abstracttensor/sparseblocktensor.jl b/test/abstracttensor/sparseblocktensor.jl index bde8ce0..e404ad6 100644 --- a/test/abstracttensor/sparseblocktensor.jl +++ b/test/abstracttensor/sparseblocktensor.jl @@ -123,7 +123,7 @@ end @test i1 * i2 == @constinferred(id(storagetype(t), V1 ⊗ V2)) @test i2 * i1 == @constinferred(id(storagetype(t), V2 ⊗ V1)) - w = @constinferred(isometry(storagetype(t), V1 ⊗ (oneunit(V1) ⊞ oneunit(V1)), V1)) + w = @constinferred(isometry(storagetype(t), V1 ⊗ (unitspace(V1) ⊞ unitspace(V1)), V1)) @test dim(w) == 2 * dim(V1 ← V1) @test w' * w == id(storagetype(t), V1) @test w * w' == (w * w')^2 diff --git a/test/vectorspaces/sumspace.jl b/test/vectorspaces/sumspace.jl index 32adf11..8f9ef76 100644 --- a/test/vectorspaces/sumspace.jl +++ b/test/vectorspaces/sumspace.jl @@ -40,9 +40,9 @@ using TensorKit, BlockTensorKit @test (sectors(typeof(V)())...,) == () @test @constinferred(axes(V)) == Base.OneTo(d) W = @constinferred SumSpace(ℝ^1) - @test @constinferred(oneunit(V)) == W == oneunit(typeof(V)) + @test @constinferred(unitspace(V)) == W == unitspace(typeof(V)) @test @constinferred(⊞(V, V)) == SumSpace(vcat(V.spaces, V.spaces)) - @test @constinferred(⊞(V, oneunit(V))) == SumSpace(vcat(V.spaces, ℝ^1)) + @test @constinferred(⊞(V, unitspace(V))) == SumSpace(vcat(V.spaces, ℝ^1)) @test @constinferred(⊞(V, V, V, V)) == SumSpace(repeat(V.spaces, 4)) @test @constinferred(fuse(V, V)) ≅ SumSpace(ℝ^(d^2)) @test @constinferred(fuse(V, V', V, V')) ≅ SumSpace(ℝ^(d^4)) @@ -87,9 +87,9 @@ end @test (sectors(typeof(V)())...,) == () @test @constinferred(axes(V)) == Base.OneTo(d) W = @constinferred SumSpace(ℂ^1) - @test @constinferred(oneunit(V)) == W == oneunit(typeof(V)) + @test @constinferred(unitspace(V)) == W == unitspace(typeof(V)) @test @constinferred(⊞(V, V)) == SumSpace(vcat(V.spaces, V.spaces)) - @test @constinferred(⊞(V, oneunit(V))) == SumSpace(vcat(V.spaces, ℂ^1)) + @test @constinferred(⊞(V, unitspace(V))) == SumSpace(vcat(V.spaces, ℂ^1)) @test @constinferred(⊞(V, V, V, V)) == SumSpace(repeat(V.spaces, 4)) @test @constinferred(fuse(V, V)) ≅ SumSpace(ℂ^(d^2)) @test @constinferred(fuse(V, V', V, V')) ≅ SumSpace(ℂ^(d^4)) @@ -139,9 +139,9 @@ end @test (sectors(typeof(V)())...,) == () @test @constinferred(axes(V)) == Base.OneTo(d) W = @constinferred SumSpace(U1Space(0 => 1)) - @test @constinferred(oneunit(V)) == W == @constinferred(oneunit(typeof(V))) + @test @constinferred(unitspace(V)) == W == @constinferred(unitspace(typeof(V))) @test @constinferred(⊞(V, V)) == SumSpace(vcat(V.spaces, V.spaces)) - @test @constinferred(⊞(V, oneunit(V))) == SumSpace(vcat(V.spaces, oneunit(V1))) + @test @constinferred(⊞(V, unitspace(V))) == SumSpace(vcat(V.spaces, unitspace(V1))) @test @constinferred(⊞(V, V, V, V)) == SumSpace(repeat(V.spaces, 4)) @test @constinferred(fuse(V, V)) ≅ SumSpace(U1Space(0 => 9, 1 => 24, 2 => 16)) @test @constinferred(fuse(V, V', V, V')) ≅