Repository navigation
Conversation
For sectors with a simple unit, a superset of the coupled sectors suffices, as the fusion tree iterators yield nothing for the others: the unit if one side is empty, and otherwise the fusion product of the shorter side only, instead of the intersection of the fusion products of both sides. The trees and their order are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Instead of constructing a block for every combination of codomain and domain sectors, `fusionblocks` groups the cached `fusiontrees(W)` by their uncoupled sectors, in the same order as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
||
| # note: cs is unique due to ⊗ returning unique fusion results | ||
| cs = if N₁ == 0 | ||
| cs = if UnitStyle(I) isa SimpleUnit |
There was a problem hiding this comment.
Two notes here:
- I think the SimpleUnit check is actually not required anymore, since we are now guaranteeing that the coupled sectors will belong to exactly one color.
- My original reservations about the validity of using only one side for the coupled sectors is wrong here, because what is actually going on is that you moved the
filtercall into thefor c in csloop below, therefore getting equivalent results.
I think this does make sense, because you no longer need to generate all fusiontrees and instead can simply only verify the candidate cs the other side already restricted to.
There was a problem hiding this comment.
I removed the SimpleUnit check. For N₁ == 0 or N₂ == 0 the candidates are now allunits(I), otherwise the fusion product of the shorter side, for every UnitStyle. Only the longer side is checked for trees, since the shorter one has trees for every candidate.
There was a problem hiding this comment.
In principle leftunit/rightunit of the other side is exactly the one you want, because I'm not sure if otherwise the fusiontree iterator might error
| f₁ in fusiontrees(uncoupled[1], c, isdual[1]) | ||
| push!(trees, (f₁, f₂)) | ||
| for c in cs | ||
| isempty(fusiontrees(uncoupled[1], c, isdual[1])) && continue |
There was a problem hiding this comment.
TODO: check that our iterator has a fast path for isempty, or is actually calling a fast path here.
There was a problem hiding this comment.
There doesn't seem to be a fast path, this just goes through iterate. So if there's no tree for a given coupled charge, it still goes through the intermediate channels. Do you think it's best to add a fast path for this?
There was a problem hiding this comment.
I'm not entirely sure, I don't really have a concrete idea of what I was after, I just wanted to double-check that this is not doing something silly
| return fblocks | ||
| # in the order of `sectors(domain(W))` (outer) and `sectors(codomain(W))` (inner), each of | ||
| # which runs fastest over its first space | ||
| position(V) = Dict{I, Int}(s => i for (i, s) in enumerate(sectors(V))) |
There was a problem hiding this comment.
Do we need to map every sector to an Int, or can we get away with just calling < on the sectors themselves since they should appear in the same order, thereby avoiding having to allocate the Dicts here?
There was a problem hiding this comment.
We could do this, but I checked and the isless approach is actually slower (almost a factor of 2) for the product sectors I was testing with, since that callsfindindex for each factor at every comparison. So I would be inclined to keep the Dict positions since they're faster.
Also note I fixed an issue with the sorting below, where previously the Dict lookups were run at every comparison, whereas now we run the lookup on each block once and then sort on the obtained results.
There was a problem hiding this comment.
let me investigate if we can actually speed up the comparisons a bit, I think there are quite a few fast paths that might be able to get this closer together. It's also just about this looking a bit "ugly" or complicated, if we could just use comparison it's a bit easier to read
There was a problem hiding this comment.
Is this specifically for the SU(3) case by the way? I would guess the findindex on the other factors is cheap (unless we are missing some fast definitions here)
There was a problem hiding this comment.
QuantumKitHub/TensorKitSectors.jl#115
Mind giving it a go with that included?
| @@ -210,13 +210,18 @@ grouped by their uncoupled charges. | |||
| function fusionblocks(W::HomSpace) | |||
There was a problem hiding this comment.
Do we have an idea how much time this takes? If it is too much, there might be a point in caching the combination of fusiontrees and fusionblocks for non-abelian tensors
There was a problem hiding this comment.
After c643ae2: 0.43 s (fℤ₂ × U(1) × SU(3)) and 4.15 s (fℤ₂ × U(1) × SU(2) × U(1)) for all spaces of one CTMRG iteration. With #580 that is 4–8 % of building the braid transformers, and it runs before the threaded part. One iteration calls fusionblocks 550 times on 396 distinct spaces, so caching alone saves about 30 %. Caching it together with sectorstructure would also give the tree indices of each block, which saves the gettoken lookups of the source trees in GenericTreeTransformer.
Do you think it's worth looking into that for a follow-up?
There was a problem hiding this comment.
It might actually be worth it, and feels a bit more uniform since very often fusionblocks is actually what you want for the non-abelian things while we are only caching fusiontrees
`sort!(...; by = rank)` evaluated `rank`, and with it the `Dict` lookups of (product) sectors, at every comparison. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… only the longer side for trees Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…no legs on one side Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For several units, a coupled sector of a block must be compatible with the units at both ends of either side; otherwise the fusion tree iterator throws instead of being empty. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This is a draft illustrating some potential performance improvements; the actual implementations are
very much up for discussion.
Same blocks, same order, less work:
FusionTreeBlock{I}(uncoupled, isdual): forSimpleUnitsectors, the coupled sectors come fromthe fusion product of the shorter side only, instead of intersecting the products of both sides.
fusionblocks(W): groups the cachedfusiontrees(W)by uncoupled sectors, instead of constructinga (mostly empty) block for every combination of sectors.
New test: the blocks of a
HomSpacehold exactly its trees, in order.Cold construction of the recoupling data for one permutation of a tensor from a PEPS CTMRG step
(scripts below), main → this PR:
SU(2) gains little from threads:
FsymbolforSU2Irrepgoes through WignerSymbols, which takesa lock on every call. Removing that lock (caching the F-symbols in TensorKitSectors) is scheduled
as a follow-up.
TensorKit main (ae8abfc), SUNRepresentations c02a3f3, TensorKitSectors v0.3.10, Julia 1.12.5; shared 80-core
machine, two interleaved rounds agree within 15 %.
fℤ₂ × U(1) × SU(2) × U(1) reproducer (
julia -t8)fℤ₂ × U(1) × SU(3) reproducer (
julia -t8)🤖 Generated with Claude Code