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
[Sectors] Non-abelian fusion #1363
base: main
Are you sure you want to change the base?
Conversation
rebase on latest GradedAxes set GradedAxes as a Sector dependency define fusion rules for simple categories pass test for simple categories
# name conflict with LabelledNumber.label. TBD is that an issue? | ||
label(c::AbstractCategory) = error("method `label` not defined for type $(typeof(c))") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either we can separate Sectors.label
and LabelledNumber.label
functions, or come up with a different name for the label of a category. We could rename this one to category_label
to be more specific.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's too bad, because label is pretty much the standard term and it is short and sweet. (E.g. I checked the von Delft paper on SU(N) and they frequently use the term "label".) The only other names I've seen are in the category / topology / stat mech literature where they call the labels variously "simple objects", "anyon types", or "anyon sectors" and names like that. But of course those names are never used in the group theory literature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
category_label
is a sensible compromise. But I was liking how we weren't using the term category too much to intentionally be ambiguous about whether something might be a regular group.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could have both group_label
and category_label
, or not overload label
from LabelledNumbers
and have a private Sectors.label
function.
Having groups define group_label
and categories define category_label
seems ok to me, since I doubt that there will be some generic code that accepts either a group or a category and makes use of the label.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather avoid having both group_label
and category_label
, as they would play the same role and lead to code dupplicate. The name should stay internal and not exposed, so I think cagerory_label
is the best solution.
Codecov ReportAll modified and coverable lines are covered by tests ✅
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## main #1363 +/- ##
==========================================
+ Coverage 49.23% 57.49% +8.26%
==========================================
Files 110 114 +4
Lines 8320 8867 +547
==========================================
+ Hits 4096 5098 +1002
+ Misses 4224 3769 -455 ☔ View full report in Codecov by Sentry. |
function GradedAxes.tensor_product( | ||
c::C, g::GradedAxes.GradedUnitRange{Vector{LabelledNumbers.LabelledInteger{V,C}}} | ||
) where {V,C<:AbstractCategory} | ||
return c ⊗ g | ||
end | ||
|
||
function GradedAxes.tensor_product( | ||
g1::GradedAxes.GradedUnitRange{Vector{LabelledNumbers.LabelledInteger{V,C}}}, | ||
g2::GradedAxes.GradedUnitRange{Vector{LabelledNumbers.LabelledInteger{V,C}}}, | ||
) where {V,C<:AbstractCategory} | ||
return g1 ⊗ g2 | ||
end | ||
|
||
GradedAxes.fuse_labels(c1::AbstractCategory, c2::AbstractCategory) = c1 ⊗ c2 | ||
|
||
# =============== sum rules ==================== | ||
⊕(c1::C, c2::C) where {C<:AbstractCategory} = GradedAxes.gradedrange([c1 => 1, c2 => 1]) | ||
|
||
function ⊕( | ||
c::C, g::GradedAxes.GradedUnitRange{Vector{LabelledNumbers.LabelledInteger{V,C}}} | ||
) where {V<:Integer,C<:AbstractCategory} | ||
return GradedAxes.gradedrange([c => 1]) ⊕ g | ||
end | ||
|
||
function ⊕( | ||
g::GradedAxes.GradedUnitRange{Vector{LabelledNumbers.LabelledInteger{V,C}}}, c::C | ||
) where {V<:Integer,C<:AbstractCategory} | ||
return g ⊕ GradedAxes.gradedrange([c => 1]) | ||
end | ||
|
||
function ⊕( | ||
g1::GradedAxes.GradedUnitRange{Vector{LabelledNumbers.LabelledInteger{V,C}}}, | ||
g2::GradedAxes.GradedUnitRange{Vector{LabelledNumbers.LabelledInteger{V,C}}}, | ||
) where {V<:Integer,C<:AbstractCategory} | ||
return GradedAxes.chain(g1, g2) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all of these type signatures are too restrictive, and we can just use AbstractUnitRange
instead of GradedUnitRange
.
It may not make sense to direct sum certain AbstractUnitRange
objects with an AbstractCategory
, but I think we can think about a different way to catch that kind of issue, for example perhaps that is caught in chain
/axis_cat
, or we have an orthogonal concept of axis promotion, for example:
function ⊕(g::AbstractUnitRange c::AbstractCategory)
return ⊕(gradedaxis_promote(g, c)...)
end
function gradedaxis_promote(g::GradedUnitRange, c::AbstractCategory)
return (g, gradedrange([c => 1]))
end
function gradedaxis_promote(g::AbstractUnitRange, c::AbstractCategory)
return error("No promotion defined.")
end
That kind of promotion system is how Base Julia handles algebra between various number types. We probably want a lower level concept of a gradedaxis_promote_rule
that handles both:
gradedaxis_promote(g::GradedUnitRange, c::AbstractCategory)
gradedaxis_promote(c::AbstractCategory, g::GradedUnitRange)
in a single gradedaxis_promote_rule
, like how Julia has promote_type
which calls promote_rule
internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does make me wonder how often we need to direct sum a category onto a graded axis, so perhaps there is another way of thinking about this concept. I guess this is used in generic fusion code, where results of fusions need to be direct summed with each other to make the full space, but fusions can output either a category or a graded unit range?
If that is the case, it seems like one way to handle this would be to not define ⊕(g::GradedUnitRange c::AbstractCategory)
at all (which feels like a strange thing to define, from a generic coding perspective) and instead, in the fusion code, eagerly promote to a GradedUnitRange
before things get input into ⊕
.
So let's think about the code flow and the context for where these definitions are being used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I updated previous code by @emstoudenmire . We do not really need to direct sum spaces, at least not for the symmetric tensor network implementation I have in mind. However I think we can be slightly more ambitious and implement group theory in a generic way.
Anyway promoting looks like the way to go as it also be used for fusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks for the clarification. Agreed, many of the promotion rules should be the same between this code and fusion. I would lean toward removing ⊕
from this package for now. For the time being we can use axis_cat
as needed, and add back ⊕
later on as a nicer interface on top of axis_cat
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Finally promotion is mostly avoided by specializing according to SymmetryStyle
. The few cases left are deal with to_graded_axis
.
Regarding the question of the SU(2) types, I believe we had settled on the following plan
|
I made the requested changes: all explicit type comparison are replaced by dispatch. I propose conventions for |
I had a look at the failures in CI. They all come from julia 1.6, all tests pass with julia 1.10. Failures boil down to two cases: first a return type is not correctly inferred in one case, this is not a big deal. Second |
It's more verbose, but we could use julia> using Indexing
julia> getindices((; a=2, b=3, c=4), (; a=:a, b=:b))
(a = 2, b = 3) which works across Julia versions. We will likely drop support for Julia 1.6 at some point, but I would rather not do that here. |
We could wrap that functionality up into a nicer interface, maybe: subkeys(collection::NamedTuple, keys) = getindices(collection, (; (keys .=> keys)...))
subkeys(collection::Dict, keys) = getindices(collection, Dict(keys .=> keys)) to be used like: julia> subkeys((; a=2, b=3, c=4), (:a, :b))
(a = 2, b = 3)
julia> subkeys(Dict([:a => 2, :b => 3, :c => 4]), [:a, :b])
Dict{Symbol, Int64} with 2 entries:
:a => 2
:b => 3 which has the advantage over |
Named Category implementation calls Ordered Products, better to define and test Ordered Product first.
Thank you for the clues, I ended up using another way. I also removed a few |
This is a work in progress for a full implementation of non-abelian fusion rules in
Sectors
. It also contains several patches on other components ofSectors
. A core aspect is that the dependency order betweenGradedAxes
andSectors
has been reversed:Sectors
now depends onGradedAxes
.To do:
CategoryProduct
SymmetryStyle
trait with valuesAbelianGroup
,NonAbelianGroup
andNonGroupSymmetry
To be decided:
c1 ⊗ c2
: either always aGradedUnitRange
or aGradedUnitRange
or aCategory
depending onSymmetryStyle
SU2
andSU{2}
.Decisions:
c1 ⊗ c2
: return type depends onSymmetryStyle
SU2
withSU{2}
and try to have a half-integer interface specific toSU{2}
Long term: how to handle braiding for fermions and anyons.