From 80f36ed559317f6e8a66d967ff4ab78795f085c2 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 11 Nov 2026 12:16:04 +0100 Subject: [PATCH] Use comprehensions for `dims`, `dual` and `flip` of `SumSpace` When the type of a `SumSpace` is not concrete, `map(dual, S.spaces)` maps over a vector with an abstract element type. If such a call is reached from within another `map` call, type inference applies its recursion limit to it. The limited results are not cached, so every function between the two `map` calls is inferred again at every call site (JuliaLang/julia#64862). Comprehensions give the same result and are not limited. First call of `InfiniteMPOHamiltonian([P, P], (1, 2) => h, (2, 3) => h)` from that issue, with MPSKit at 263fe273: | Julia | before | after | |---------------|------------------|------------------| | 1.10.13 | 10.7 s, 4.5 GiB | 9.4 s, 3.5 GiB | | 1.13.3 | 36.0 s, 16.7 GiB | 17.5 s, 7.8 GiB | | 1.14.0-alpha2 | 29.5 s, 16.4 GiB | 14.4 s, 7.8 GiB | Co-Authored-By: Claude Fable 5.2 --- src/vectorspaces/sumspace.jl | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vectorspaces/sumspace.jl b/src/vectorspaces/sumspace.jl index a9b30f5..423fa51 100644 --- a/src/vectorspaces/sumspace.jl +++ b/src/vectorspaces/sumspace.jl @@ -103,16 +103,19 @@ Return the type of a `SumSpace` with elements of type `S`. """ sumspacetype(::Type{S}) where {S <: ElementarySpace} = SumSpace{S} -TensorKit.dims(S::SumSpace) = map(dim, S.spaces) +# The comprehensions below are deliberate. When the type of `S` is not concrete, a `map` over +# `S.spaces` hits the recursion limit of type inference whenever it is reached from within +# another `map` call, and nothing that calls it is cached (JuliaLang/julia#64862). +TensorKit.dims(S::SumSpace) = [dim(V) for V in S.spaces] TensorKit.dim(S::SumSpace, n::Int) = dim(S.spaces[n]) TensorKit.dim(S::SumSpace) = sum(dims(S)) TensorKit.isdual(S::SumSpace) = S.dual -TensorKit.dual(S::SumSpace{CartesianSpace}) = SumSpace(map(dual, S.spaces); dual = false) -TensorKit.dual(S::SumSpace) = SumSpace(map(dual, S.spaces); dual = !isdual(S)) +TensorKit.dual(S::SumSpace{CartesianSpace}) = SumSpace([dual(V) for V in S.spaces]; dual = false) +TensorKit.dual(S::SumSpace) = SumSpace([dual(V) for V in S.spaces]; dual = !isdual(S)) Base.conj(S::SumSpace) = dual(S) -TensorKit.flip(S::SumSpace{CartesianSpace}) = SumSpace(map(flip, S.spaces); dual = false) -TensorKit.flip(S::SumSpace) = SumSpace(map(flip, S.spaces); dual = isdual(S)) +TensorKit.flip(S::SumSpace{CartesianSpace}) = SumSpace([flip(V) for V in S.spaces]; dual = false) +TensorKit.flip(S::SumSpace) = SumSpace([flip(V) for V in S.spaces]; dual = isdual(S)) function TensorKit.hassector(S::SumSpace, s::Sector) return mapreduce(v -> hassector(v, s), |, S.spaces; init = false)