Skip to content

Add hash for FusionTreeBlock to fix cacheing behind AdjointTensorMap permutes - #518

Open
leburgel wants to merge 1 commit into
mainfrom
lb/fusiontreeblock_hash
Open

Add hash for FusionTreeBlock to fix cacheing behind AdjointTensorMap permutes#518
leburgel wants to merge 1 commit into
mainfrom
lb/fusiontreeblock_hash

Conversation

@leburgel

@leburgel leburgel commented Aug 27, 2026

Copy link
Copy Markdown
Member

Potential first step to addressing #516.

The cache underlying permutes of AdjointTensorMaps ( GLOBAL_FSBRAID_CACHE) never gets a single hit, making it effectively useless. This cache uses keys generated from a FusionTreeBlock, but Base.hash wasn't defined for this type causing literally all keys to miss. Adding the hash improves the performance of permuting AdjointTensorMaps with non-Abelian sector types.

Running the reproduction script from #516 gives:

Reproduction script
using TensorKit, BenchmarkTools
using TensorKit.VectorInterface: One, Zero

p = ((2, 3), (4, 1))

function compare(name, V)
    t   = randn(ComplexF64, V  V  V  V)
    adj = t'         # AdjointTensorMap
    mat = copy(t')   # identical space and contents, but a genuine TensorMap

    Vdst    = TensorKit.permute(space(mat), p)
    dst_adj = similar(mat, Vdst)
    dst_mat = similar(mat, Vdst)

    # NB: permute(::AdjointTensorMap, p) unwraps the adjoint and is therefore NOT affected.
    # The slow path is the in-place one, which is what `tensoradd!`/`blas_contract!` use.
    f_adj() = permute!(dst_adj, adj, p, One(), Zero())
    f_mat() = permute!(dst_mat, mat, p, One(), Zero())
    f_adj(); f_mat()
    @assert convert(Array, dst_adj)  convert(Array, dst_mat)

    b_adj = @benchmark $f_adj() samples = 500 seconds = 10
    b_mat = @benchmark $f_mat() samples = 500 seconds = 10
    println(rpad(name, 14),
            " adjoint ", round(minimum(b_adj).time / 1e6; digits = 4), " ms (", b_adj.allocs, " allocs)",
            "  tensormap ", round(minimum(b_mat).time / 1e6; digits = 4), " ms (", b_mat.allocs, " allocs)",
            "  ratio ", round(minimum(b_adj).time / minimum(b_mat).time; digits = 2), "x")
end

compare("fZ2",    Vect[FermionParity](0 => 8, 1 => 8))
compare("fZ2xU1", Vect[FermionParity  U1Irrep]((0,0) => 4, (1,1) => 4, (0,2) => 3, (1,-1) => 3))
compare("SU2",    Vect[SU2Irrep](0 => 4, 1//2 => 4, 1 => 3, 3//2 => 2))

# needs SUNRepresentations
using SUNRepresentations
compare("fZ2xU1xSU3", Vect[FermionParity  U1Irrep  SU3Irrep](
    (0, 0, SU3Irrep(0,0,0)) => 2, (1, 1, SU3Irrep(1,0,0)) => 1,
    (0, 2, SU3Irrep(1,1,0)) => 1, (1, 3, SU3Irrep(1,1,1)) => 1))

After

sector type adjoint TensorMap ratio allocs (adjoint / TensorMap)
fℤ₂ 0.0784 ms 0.0580 ms 1.35× 129 / 65
fℤ₂ ⊠ U(1) 0.1302 ms 0.0360 ms 3.62× 669 / 317
SU(2) 1.1759 ms 0.4083 ms 2.88× 7 864 / 2 847
fℤ₂ ⊠ U(1) ⊠ SU(3) 0.6915 ms 0.0527 ms 13.12× 8 011 / 652

Before

sector type adjoint TensorMap ratio allocs (adjoint / TensorMap)
fℤ₂ 0.0717 ms 0.0539 ms 1.33× 122 / 58
fℤ₂ ⊠ U(1) 0.1232 ms 0.0319 ms 3.86× 794 / 310
SU(2) 2.4282 ms 0.3382 ms 7.18× 27 094 / 2 840
fℤ₂ ⊠ U(1) ⊠ SU(3) 3.8169 ms 0.0465 ms 82.08× 43 529 / 645

@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
src/fusiontrees/fusiontrees.jl 96.66% <100.00%> (+0.01%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

end
return h
end
Base.hash(b::FusionTreeBlock, h::UInt) = hash(fusiontrees(b), h)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you only want to hash the uncoupled and isdual on these, which is probably a lot faster than hashing the actual array

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants