Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

define nsymbol #4

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

define nsymbol #4

wants to merge 1 commit into from

Conversation

ogauthe
Copy link
Contributor

@ogauthe ogauthe commented Dec 11, 2024

This PR defines nsymbol, a function to accede the number of time label s3 appears in the tensor product s1⊗s2. To stay consistent with the interface, the output is a labelled integer.

@ogauthe ogauthe mentioned this pull request Dec 11, 2024
@mtfishman
Copy link
Member

mtfishman commented Dec 11, 2024

Maybe as an alternative, if we had an API for getting the block length associated with a certain sector it would be easy enough to write this function outside of the library.

I.e. we could redefine blocklengths(a::AbstractGradedUnitRange) such that you can write:

r = gradedrange([U1(0) => 2, U1(1) => 3])
blocklengths(r)[U1(1)] == 3

(or I guess it would output labelled(3, U1(1))). That could be done by defining blocklengths so that it outputs an object that wraps the graded unit range, maybe called SectorBlockLengths, such that it acts like the vector of block lengths but you can index into it either with integers or with a symmetry sector (similar to the design of AxisKeys.jl as we have discussed, where we can think about integer positions of the blocks as indices and sectors as the keys).

Then, the logic of not being sure if the sector exists can be handled by the standard Julia API get(blocklengths(r), U1(2), nothing).

That is analogous to how in BlockArrays.jl, blocksizes(a::AbstractBlockArray) outputs a BlockSizes object:

julia> a = BlockedArray(randn(5, 5), [2, 3], [2, 3])
2×2-blocked 5×5 BlockedMatrix{Float64}:
  0.0903129   1.485560.210218   0.36306    0.327547 
 -1.16907    -1.512920.38288    1.82632   -1.43893  
 ──────────────────────┼──────────────────────────────────
 -0.268323   -1.160971.18574    0.258269   0.362909 
 -0.37301     0.90419-0.552486  -0.218437  -0.0195218
  2.22222    -1.60995-0.704768  -0.317308   0.0766319

julia> blocksizes(a)
2×2 BlockArrays.BlockSizes{Tuple{Int64, Int64}, 2, BlockedMatrix{Float64, Matrix{Float64}, Tuple{BlockedOneTo{Int64, Vector{Int64}}, BlockedOneTo{Int64, Vector{Int64}}}}}:
 (2, 2)  (2, 3)
 (3, 2)  (3, 3)

Copy link

codecov bot commented Dec 11, 2024

Codecov Report

Attention: Patch coverage is 0% with 5 lines in your changes missing coverage. Please review.

Please upload report for BASE (main@8767c22). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/abstractsector.jl 0.00% 5 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff           @@
##             main      #4   +/-   ##
======================================
  Coverage        ?   0.00%           
======================================
  Files           ?      12           
  Lines           ?     412           
  Branches        ?       0           
======================================
  Hits            ?       0           
  Misses          ?     412           
  Partials        ?       0           
Flag Coverage Δ
docs 0.00% <0.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@lkdvos
Copy link
Contributor

lkdvos commented Dec 11, 2024

Would you like me to wait for this PR, or shall I already register a version for convenience?

@mtfishman
Copy link
Member

Is nsymbol a standard name for this functionality?

@mtfishman
Copy link
Member

Would you like me to wait for this PR, or shall I already register a version for convenience?

Go ahead and register the latest main, I want to use it in ITensor/BlockSparseArrays.jl#10.

@lkdvos
Copy link
Contributor

lkdvos commented Dec 11, 2024

I am not sure how standard it is, but it is quite common to write something like this for decomposing tensor products (or category theory decompositions)

$$a \otimes b \rightarrow \bigoplus_c N_{ab}^c c$$

This data is what qualifies the fusion ring of the irreps (or simple objects), ie how these multiply. For example the notation is here, and of course TensorKit has Nsymbol.

On the other hand, the fusion category bible just talks about fusion rings, and doesn't actually name the coefficients.

In any case, I would say that this is definitely a convenient concept to have a shorthand function for, since it is quite often that you need to loop over 1:Nsymbol when dealing with groups with multiplicities. Of course, for abelian groups and even for SU(2), $$N \in 0,1$$, so there it can look like it's not that useful

@mtfishman
Copy link
Member

mtfishman commented Dec 11, 2024

I see, thanks for clarifying. The notation nsymbol confused me, I thought it stood for "number of symbols". I see now that I'm supposed to think about it as an order-3 tensor that you are indexing into with a set of sectors to get the degeneracy. In this case, I think it makes sense to follow TensorKit's approach and use the capitalized version Nsymbol, even though that goes against Julia's standard naming conventions.

I also see that in many cases you can directly get the number and circumvent getting all of the sectors through fusion so it makes sense to have a devoted function for it, but even so using fusion seems like a reasonable fallback definition. But I would still vote for basing this implementation that uses fusion around a more general functionality for getting the block length associated with a sector as I outlined above.

I would almost prefer going "all in" on the tensor analogy, and define Nsymbol as a type and define indexing so that the notation is Nsymbol[s1, s2, s3]. Though maybe that is too fancy. (Maybe what makes more sense is a notation Nsymbol(s1, s2)[s3], i.e. Nsymbol(s1, s2) creates an object representing the the fused sectors and indexing into it gets the length, so going back to my suggestions above it could be defined as Nsymbol(s1, s2) = blocklengths(s1 ⊗ s2).)

@lkdvos
Copy link
Contributor

lkdvos commented Dec 12, 2024

I do quite like the Nsymbol[a, b, c] approach, since it typically really is group data that you are indexing into. The one thing that's slightly annoying is that it's a different array for different groups, so that kind of goes back to it being a function Nsymbol(a, b, c) which dispatches on the types of the arguments. (of course you can achieve this with getindex as well, but it's not obvious to me if that is very "julian").

It's not obvious to me why this should return a labelled integer though, this integer is really the number of times c appears in the decomposition of a ⊗ b, and really is just counting that. In mathematical terms, it's the dimension of the fusion space associated with that tensor product, so it's less obvious to give it a label c or a or b, since it really requires all three. (it's the vertex labels on the fusion tree)

@mtfishman
Copy link
Member

mtfishman commented Dec 12, 2024

Yeah, I'm fine with Nsymbol returning an unlabelled integer, what I think could arguably return a labelled integer is blocklengths(s1 ⊗ s2)[s3], since in our current design the length of a graded unit range also has the sector attached to it. But even there maybe one could argue it should output an unlabelled integer.

@mtfishman
Copy link
Member

I do quite like the Nsymbol[a, b, c] approach, since it typically really is group data that you are indexing into.

Right, I guess following that logic there could be Nsymbol(U1)[1, 1, 2] == Nsymbol(U1(1), U1(1), U1(2)) or something like that.

@ogauthe
Copy link
Contributor Author

ogauthe commented Dec 12, 2024

We may have a similar function inside GradedUnitRanges, however I think nsymbol has its place in SymmetrySectors, it is a well defined mathematical object (sharing GradedUnitRanges implementation). I hesitated between returning LabelledInteger and Int, both are possible.

I will have a try for a custom SectorBlockLengths, hopefully it will stay compatible with blocklengths(::BlockedUnitRange)

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.

3 participants