From ed039bab16e4976443cf89713dbfd6e55d3b0980 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Tue, 9 Oct 2018 06:58:21 -0700 Subject: [PATCH 01/14] fusion algebras from weyl character rings --- src/sage/combinat/root_system/all.py | 3 +- .../combinat/root_system/weyl_characters.py | 84 +++++++++++++++++-- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py index 0f510bc9916..8ed7e596a17 100644 --- a/src/sage/combinat/root_system/all.py +++ b/src/sage/combinat/root_system/all.py @@ -19,7 +19,8 @@ 'ExtendedAffineWeylGroup') lazy_import('sage.combinat.root_system.coxeter_group', 'CoxeterGroup') lazy_import('sage.combinat.root_system.weyl_characters', ['WeylCharacterRing', - 'WeightRing']) + 'WeightRing', + 'FusionRing']) from .branching_rules import BranchingRule, branching_rule_from_plethysm, branching_rule lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials', 'NonSymmetricMacdonaldPolynomials') diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 14ffc542942..5bfd5887bb8 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -90,7 +90,7 @@ class WeylCharacterRing(CombinatorialFreeModule): https://doc.sagemath.org/html/en/thematic_tutorials/lie.html """ @staticmethod - def __classcall__(cls, ct, base_ring=ZZ, prefix=None, style="lattice"): + def __classcall__(cls, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): """ TESTS:: @@ -106,9 +106,9 @@ def __classcall__(cls, ct, base_ring=ZZ, prefix=None, style="lattice"): prefix = ct[0]+str(ct[1]) else: prefix = repr(ct) - return super(WeylCharacterRing, cls).__classcall__(cls, ct, base_ring=base_ring, prefix=prefix, style=style) + return super(WeylCharacterRing, cls).__classcall__(cls, ct, base_ring=base_ring, prefix=prefix, style=style, k=k) - def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice"): + def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): """ EXAMPLES:: @@ -126,8 +126,14 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice"): prefix = ct[0]+str(ct[1]) else: prefix = repr(ct) + if k is not None: + prefix = prefix + "%s"%k self._prefix = prefix self._style = style + self._k = k + if k is not None: + self._highest = self._space.highest_root() + self._hip = self._highest.inner_product(self._highest) if style == "coroots": self._word = self._space.weyl_group().long_element().reduced_word() # TODO: remove the Category.join once not needed anymore (bug in CombinatorialFreeModule) @@ -335,7 +341,11 @@ def _repr_(self): sage: WeylCharacterRing("A3") The Weyl Character Ring of Type A3 with Integer Ring coefficients """ - return "The Weyl Character Ring of Type {} with {} coefficients".format(self._cartan_type._repr_(compact=True), self._base_ring) + if self._k is None: + return "The Weyl Character Ring of Type {} with {} coefficients".format(self._cartan_type._repr_(compact=True), self._base_ring) + else: + return "The Fusion Ring of Type {} and level {} with {} coefficients".format(self._cartan_type._repr_(compact=True), self._k, self._base_ring) + def __call__(self, *args): """ @@ -414,6 +424,9 @@ def _element_constructor_(self, weight): weight = self._space.from_vector_notation(weight, style = self._style) if not weight.is_dominant_weight(): raise ValueError("{} is not a dominant element of the weight lattice".format(weight)) + if self._k is not None: + if self.level(weight) > self._k: + raise ValueError("{} has level greater than {}".format(weight, self._k)) return self.monomial(weight) def product_on_basis(self, a, b): @@ -507,8 +520,33 @@ def dot_reduce(self, a): ret -= (1+c)*alpha[i] done = False break + if self._k is not None: + l = self.level(ret) + k = self._k + if l > k: + if l == k+1: + return [0, self._space.zero()] + else: + epsilon = -epsilon + ret = self.affine_reflect(ret,k+1) + done = False return [epsilon, ret] + def affine_reflect(self, wt, k=0): + r""" + INPUT: + + - ``wt`` -- a weight + - ``k`` -- (optional) a positive integer + + Returns the reflection of wt in the hyperplane + perpendicular to the longest root `\theta`. + Optionally shifts by a multiple `k`of `\theta`. + """ + + coef = ZZ(2*wt.inner_product(self._highest)/self._hip) + return wt+(k-coef)*self._highest + def some_elements(self): """ Return some elements of ``self``. @@ -710,6 +748,13 @@ def irr_repr(self, hwv): """ return self._prefix+self._wt_repr(hwv) + def level(self, wt): + """ + Return the level of the weight, defined to be the value of + the weight on the coroot associated with the highest root. + """ + return ZZ(2*wt.inner_product(self._highest)/self._hip) + def _wt_repr(self, wt): """ Produce a representation of a vector in either coweight or @@ -1598,7 +1643,6 @@ def __init__(self, parent, prefix): category = AlgebrasWithBasis(self._base_ring) CombinatorialFreeModule.__init__(self, self._base_ring, self._space, category = category) - def _repr_(self): """ EXAMPLES:: @@ -2037,3 +2081,33 @@ def demazure_lusztig(self, i, v): except Exception: raise ValueError("unknown index {}".format(i)) +def FusionRing(ct, k, base_ring=ZZ, prefix=None, style="coroots"): + r""" + INPUT: + + - ``ct`` -- the Cartan type of a simple (finite-dimensional) Lie algebra + - ``k`` -- a nonnegative integer + + Returns the Fusion Ring (Verlinde Algebra) of level k. See: + + * J. Fuchs, Fusion Rules for Conformal Field Theory. arXiv:hep-th/9306162 + * Walton, Mark A. Fusion rules in Wess-Zumino-Witten models. Nuclear Phys. B 340 (1990). + * Feingold, Fusion rules for affine Kac-Moody algebras. Contemp. Math., 343. arXiv:math/0212387 + + This algebra has a basis indexed by the weights of level `\leq k`. It is implemented + as a variant of the WeylCharacterRing. + + EXAMPLES:: + + sage: A22=FusionRing("A2",2) + sage: [f1,f2]=A22.fundamental_weights() + sage: [m0,m1,m2,m3,m4,m5]=[A22(x) for x in [0*f1,2*f1,2*f2,f1+f2,f2,f1]] + sage: [m3*x for x in [m0,m1,m2,m3,m4,m5]] + [A22(1,1), + A22(0,1), + A22(1,0), + A22(0,0) + A22(1,1), + A22(0,1) + A22(2,0), + A22(1,0) + A22(0,2)] + """ + return WeylCharacterRing(ct, base_ring=base_ring, prefix=prefix, style=style, k=k) From 2b75fb534856524bf33bc9506b4e059fc86a27e0 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Tue, 9 Oct 2018 18:07:20 -0700 Subject: [PATCH 02/14] contragredient or conjugation map --- .../combinat/root_system/weyl_characters.py | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 5bfd5887bb8..ed20babcd8b 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -19,7 +19,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.functional import is_even from sage.rings.all import ZZ - +from sage.matrix.all import Matrix class WeylCharacterRing(CombinatorialFreeModule): r""" @@ -131,6 +131,7 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): self._prefix = prefix self._style = style self._k = k + self._opposition = ct.opposition_automorphism() if k is not None: self._highest = self._space.highest_root() self._hip = self._highest.inner_product(self._highest) @@ -755,6 +756,37 @@ def level(self, wt): """ return ZZ(2*wt.inner_product(self._highest)/self._hip) + def _dual_helper(self, wt): + """ + If `w_0` is the long Weyl group element and `wt` is an + element of the weight lattice, this returns `-w_0(wt)`. + """ + if self.cartan_type()[0] == 'A': + return self.space()([-x for x in reversed(wt.to_vector().list())]) + ret = 0 + alphacheck = self._space.simple_coroots() + fw = self._space.fundamental_weights() + for i in self._space.index_set(): + ret += wt.inner_product(alphacheck[i])*fw[self._opposition[i]] + return ret + + def dual(self, elt): + """ + The involution that replaces a representation with + its contragredient. (For Fusion rings, this is the + conjugation map.) + + EXAMPLES:: + + sage: A3=WeylCharacterRing("A3",style="coroots") + sage: A3(1,0,0)^2 + A3(0,1,0) + A3(2,0,0) + sage: A3.dual(A3(1,0,0)^2) + A3(0,1,0) + A3(0,0,2) + """ + d = elt.monomial_coefficients() + return sum(d[k]*self(self._dual_helper(k)) for k in d.keys()) + def _wt_repr(self, wt): """ Produce a representation of a vector in either coweight or From cada3b3a887c4ca30d82c13018ff92ca9a786199 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Tue, 9 Oct 2018 18:09:31 -0700 Subject: [PATCH 03/14] don't import Matrix --- src/sage/combinat/root_system/weyl_characters.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index ed20babcd8b..68f128d751b 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -19,7 +19,6 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.functional import is_even from sage.rings.all import ZZ -from sage.matrix.all import Matrix class WeylCharacterRing(CombinatorialFreeModule): r""" From e8dec301fbfe25ff72c521096267632512bb9b92 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Wed, 10 Oct 2018 09:54:01 -0700 Subject: [PATCH 04/14] bugfix: reducible cartan types have no opposition involution --- src/sage/combinat/root_system/weyl_characters.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 68f128d751b..f2f4c405237 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -130,7 +130,8 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): self._prefix = prefix self._style = style self._k = k - self._opposition = ct.opposition_automorphism() + if ct.is_atomic(): + self._opposition = ct.opposition_automorphism() if k is not None: self._highest = self._space.highest_root() self._hip = self._highest.inner_product(self._highest) @@ -760,7 +761,7 @@ def _dual_helper(self, wt): If `w_0` is the long Weyl group element and `wt` is an element of the weight lattice, this returns `-w_0(wt)`. """ - if self.cartan_type()[0] == 'A': + if self.cartan_type()[0] == 'A': # handled separately for GL(n) compatibility return self.space()([-x for x in reversed(wt.to_vector().list())]) ret = 0 alphacheck = self._space.simple_coroots() @@ -783,6 +784,8 @@ def dual(self, elt): sage: A3.dual(A3(1,0,0)^2) A3(0,1,0) + A3(0,0,2) """ + if not self.cartan_type().is_atomic(): + raise NotImplementedError("dual method is not implemented for reducible types") d = elt.monomial_coefficients() return sum(d[k]*self(self._dual_helper(k)) for k in d.keys()) From cda3cce4b7c34a13b20df4f61a74517c43d2aebf Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Wed, 10 Oct 2018 10:05:18 -0700 Subject: [PATCH 05/14] fusion_basis method --- .../combinat/root_system/weyl_characters.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index f2f4c405237..47b021f2ae0 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -17,6 +17,7 @@ from sage.combinat.root_system.root_system import RootSystem from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute +from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.misc.functional import is_even from sage.rings.all import ZZ @@ -756,6 +757,24 @@ def level(self, wt): """ return ZZ(2*wt.inner_product(self._highest)/self._hip) + def fusion_basis(self): + """ + For FusionRings, this method returns the finite canonical basis + as a list. + + EXAMPLES:: + sage: B22=FusionRing("B2",2) + sage: B22.fusion_basis() + [B22(0,0), B22(0,1), B22(1,0), B22(2,0), B22(1,1), B22(0,2)] + """ + if self._k is None: + raise ValueError("fusion_basis method is only available for FusionRings") + fw = self._space.fundamental_weights() + def next_level(wt): + return [wt + la for la in fw if self.level(wt + la) <= self._k] + B = RecursivelyEnumeratedSet([self._space.zero()], next_level) + return [self._element_constructor_(x) for x in B] + def _dual_helper(self, wt): """ If `w_0` is the long Weyl group element and `wt` is an From 0555717cee66f7ed9c706fbb77644f0f38ff8795 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Fri, 19 Oct 2018 14:55:44 -0700 Subject: [PATCH 06/14] FusionRing becomes a class --- .../combinat/root_system/weyl_characters.py | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 47b021f2ae0..78d7bde7b31 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -757,24 +757,6 @@ def level(self, wt): """ return ZZ(2*wt.inner_product(self._highest)/self._hip) - def fusion_basis(self): - """ - For FusionRings, this method returns the finite canonical basis - as a list. - - EXAMPLES:: - sage: B22=FusionRing("B2",2) - sage: B22.fusion_basis() - [B22(0,0), B22(0,1), B22(1,0), B22(2,0), B22(1,1), B22(0,2)] - """ - if self._k is None: - raise ValueError("fusion_basis method is only available for FusionRings") - fw = self._space.fundamental_weights() - def next_level(wt): - return [wt + la for la in fw if self.level(wt + la) <= self._k] - B = RecursivelyEnumeratedSet([self._space.zero()], next_level) - return [self._element_constructor_(x) for x in B] - def _dual_helper(self, wt): """ If `w_0` is the long Weyl group element and `wt` is an @@ -2134,7 +2116,7 @@ def demazure_lusztig(self, i, v): except Exception: raise ValueError("unknown index {}".format(i)) -def FusionRing(ct, k, base_ring=ZZ, prefix=None, style="coroots"): +class FusionRing(WeylCharacterRing): r""" INPUT: @@ -2163,4 +2145,30 @@ def FusionRing(ct, k, base_ring=ZZ, prefix=None, style="coroots"): A22(0,1) + A22(2,0), A22(1,0) + A22(0,2)] """ - return WeylCharacterRing(ct, base_ring=base_ring, prefix=prefix, style=style, k=k) + @staticmethod + def __classcall__(cls, ct, k, base_ring=ZZ, prefix=None, style="coroots"): + return super(FusionRing, cls).__classcall__(cls, ct, base_ring=base_ring, prefix=prefix, style=style, k=k) + + def fusion_basis(self): + """ + For FusionRings, this method returns the finite canonical basis + as a list. + + EXAMPLES:: + sage: B22=FusionRing("B2",2) + sage: B22.fusion_basis() + [B22(0,0), B22(0,1), B22(1,0), B22(2,0), B22(1,1), B22(0,2)] + """ + if self._k is None: + raise ValueError("fusion_basis method is only available for FusionRings") + fw = self._space.fundamental_weights() + def next_level(wt): + return [wt + la for la in fw if self.level(wt + la) <= self._k] + B = RecursivelyEnumeratedSet([self._space.zero()], next_level) + return [self._element_constructor_(x) for x in B] + + class Element(WeylCharacterRing.Element): + def fusion_weight(self): + if len(self.monomial_coefficients()) != 1: + raise ValueError("fusion weight is valid for basis elements only") + return self.leading_support() From d4166cc3bd9ad1bf50c571672ed8d8df5f52d2f0 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Sat, 20 Oct 2018 08:04:36 -0700 Subject: [PATCH 07/14] names of basis elements can be customized --- .../combinat/root_system/weyl_characters.py | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 78d7bde7b31..557502a7872 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -19,6 +19,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.misc.functional import is_even +from sage.misc.misc import inject_variable from sage.rings.all import ZZ class WeylCharacterRing(CombinatorialFreeModule): @@ -130,6 +131,7 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): prefix = prefix + "%s"%k self._prefix = prefix self._style = style + self._fusion_labels = None self._k = k if ct.is_atomic(): self._opposition = ct.opposition_automorphism() @@ -828,7 +830,10 @@ def _repr_term(self, t): sage: [G2._repr_term(x) for x in G2.fundamental_weights()] ['G2(1,0,-1)', 'G2(2,-1,-1)'] """ - return self.irr_repr(t) + if self._fusion_labels is not None: + return self._fusion_labels[t] + else: + return self.irr_repr(t) def cartan_type(self): """ @@ -2144,6 +2149,25 @@ class FusionRing(WeylCharacterRing): A22(0,0) + A22(1,1), A22(0,1) + A22(2,0), A22(1,0) + A22(0,2)] + + You may assign your own labels to the basis elements. In the next + example, we create the SO(5) fusion ring of level 2, check the + weights of the basis elements, then assign new labels to them + + EXAMPLES:: + + sage: B22=FusionRing("B2",2) + sage: B22.fusion_basis() + [B22(0,0), B22(0,1), B22(1,0), B22(2,0), B22(1,1), B22(0,2)] + sage: [x.fusion_weight() for x in B22.fusion_basis()] + [(0, 0), (1/2, 1/2), (1, 0), (2, 0), (3/2, 1/2), (1, 1)] + sage: B22.fusion_labels(['1','X','Y1','Z','Xp','Y2']) + sage: B22.fusion_basis() + [1, X, Y1, Z, Xp, Y2] + sage: X*Y1 + X + Xp + sage: Z*Z + 1 """ @staticmethod def __classcall__(cls, ct, k, base_ring=ZZ, prefix=None, style="coroots"): @@ -2155,9 +2179,9 @@ def fusion_basis(self): as a list. EXAMPLES:: - sage: B22=FusionRing("B2",2) - sage: B22.fusion_basis() - [B22(0,0), B22(0,1), B22(1,0), B22(2,0), B22(1,1), B22(0,2)] + sage: C22=FusionRing("C2",2) + sage: C22.fusion_basis() + [C22(0,0), C22(0,1), C22(1,0), C22(2,0), C22(0,2), C22(1,1)] """ if self._k is None: raise ValueError("fusion_basis method is only available for FusionRings") @@ -2167,6 +2191,35 @@ def next_level(wt): B = RecursivelyEnumeratedSet([self._space.zero()], next_level) return [self._element_constructor_(x) for x in B] + def fusion_labels(self, labels): + """ + INPUT: + + - ``labels`` -- a list of strings + + The length of the list ``labels`` must equal the + number of basis elements. These become the names of + the basis elements. + + EXAMPLES:: + + sage: A13=FusionRing("A1",3) + sage: A13.fusion_labels(['x0','x1','x2','x3']) + sage: fb = A13.fusion_basis(); fb + [x0, x1, x2, x3] + sage: Matrix([[x*y for y in A13.fusion_basis()] for x in A13.fusion_basis()]) + [ x0 x1 x2 x3] + [ x1 x0 + x2 x1 + x3 x2] + [ x2 x1 + x3 x0 + x2 x1] + [ x3 x2 x1 x0] + """ + d = {} + fb = self.fusion_basis() + for j in range(len(fb)): + d[fb[j].fusion_weight()]=labels[j] + inject_variable(labels[j],fb[j]) + self._fusion_labels = d + class Element(WeylCharacterRing.Element): def fusion_weight(self): if len(self.monomial_coefficients()) != 1: From 49ab394d606e05a71cf4113b789a5e5d26daff39 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 24 Oct 2018 12:56:01 +1000 Subject: [PATCH 08/14] Making an explicit basis for the fusion rings. --- .../combinat/root_system/weyl_characters.py | 89 ++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 557502a7872..f61b89d4397 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -127,8 +127,6 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): prefix = ct[0]+str(ct[1]) else: prefix = repr(ct) - if k is not None: - prefix = prefix + "%s"%k self._prefix = prefix self._style = style self._fusion_labels = None @@ -140,10 +138,21 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): self._hip = self._highest.inner_product(self._highest) if style == "coroots": self._word = self._space.weyl_group().long_element().reduced_word() + + # Set the basis + if k is not None: + self._prefix += str(k) + fw = self._space.fundamental_weights() + def next_level(wt): + return [wt + la for la in fw if self.level(wt + la) <= k] + B = list(RecursivelyEnumeratedSet([self._space.zero()], next_level)) + else: + B = self._space + # TODO: remove the Category.join once not needed anymore (bug in CombinatorialFreeModule) # TODO: use GradedAlgebrasWithBasis category = Category.join([AlgebrasWithBasis(base_ring), Algebras(base_ring).Subobjects()]) - CombinatorialFreeModule.__init__(self, base_ring, self._space, category = category) + CombinatorialFreeModule.__init__(self, base_ring, B, category=category) # Register the embedding of self into ambient as a coercion self.lift.register_as_coercion() @@ -831,6 +840,7 @@ def _repr_term(self, t): ['G2(1,0,-1)', 'G2(2,-1,-1)'] """ if self._fusion_labels is not None: + t = tuple([t.inner_product(x) for x in self.simple_coroots()]) return self._fusion_labels[t] else: return self.irr_repr(t) @@ -2139,7 +2149,7 @@ class FusionRing(WeylCharacterRing): EXAMPLES:: - sage: A22=FusionRing("A2",2) + sage: A22 = FusionRing("A2",2) sage: [f1,f2]=A22.fundamental_weights() sage: [m0,m1,m2,m3,m4,m5]=[A22(x) for x in [0*f1,2*f1,2*f2,f1+f2,f2,f1]] sage: [m3*x for x in [m0,m1,m2,m3,m4,m5]] @@ -2152,72 +2162,70 @@ class FusionRing(WeylCharacterRing): You may assign your own labels to the basis elements. In the next example, we create the SO(5) fusion ring of level 2, check the - weights of the basis elements, then assign new labels to them + weights of the basis elements, then assign new labels to them:: - EXAMPLES:: - - sage: B22=FusionRing("B2",2) - sage: B22.fusion_basis() + sage: B22 = FusionRing("B2",2) + sage: list(B22.basis()) [B22(0,0), B22(0,1), B22(1,0), B22(2,0), B22(1,1), B22(0,2)] - sage: [x.fusion_weight() for x in B22.fusion_basis()] + sage: [x.fusion_weight() for x in B22.basis()] [(0, 0), (1/2, 1/2), (1, 0), (2, 0), (3/2, 1/2), (1, 1)] sage: B22.fusion_labels(['1','X','Y1','Z','Xp','Y2']) - sage: B22.fusion_basis() + sage: list(B22.basis()) [1, X, Y1, Z, Xp, Y2] sage: X*Y1 X + Xp sage: Z*Z 1 + + sage: C22 = FusionRing("C2",2) + sage: list(C22.basis()) + [C22(0,0), C22(0,1), C22(1,0), C22(2,0), C22(0,2), C22(1,1)] """ @staticmethod def __classcall__(cls, ct, k, base_ring=ZZ, prefix=None, style="coroots"): return super(FusionRing, cls).__classcall__(cls, ct, base_ring=base_ring, prefix=prefix, style=style, k=k) - - def fusion_basis(self): - """ - For FusionRings, this method returns the finite canonical basis - as a list. - - EXAMPLES:: - sage: C22=FusionRing("C2",2) - sage: C22.fusion_basis() - [C22(0,0), C22(0,1), C22(1,0), C22(2,0), C22(0,2), C22(1,1)] - """ - if self._k is None: - raise ValueError("fusion_basis method is only available for FusionRings") - fw = self._space.fundamental_weights() - def next_level(wt): - return [wt + la for la in fw if self.level(wt + la) <= self._k] - B = RecursivelyEnumeratedSet([self._space.zero()], next_level) - return [self._element_constructor_(x) for x in B] - def fusion_labels(self, labels): - """ + def fusion_labels(self, labels=None): + r""" + Set the labels of the basis. + INPUT: - - ``labels`` -- a list of strings + - ``labels`` -- (default: ``None``) a list of strings The length of the list ``labels`` must equal the number of basis elements. These become the names of - the basis elements. + the basis elements. If ``labels`` is ``None``, then + this resets the labels to the default. EXAMPLES:: - sage: A13=FusionRing("A1",3) + sage: A13 = FusionRing("A1", 3) sage: A13.fusion_labels(['x0','x1','x2','x3']) - sage: fb = A13.fusion_basis(); fb + sage: fb = list(A13.basis()); fb [x0, x1, x2, x3] - sage: Matrix([[x*y for y in A13.fusion_basis()] for x in A13.fusion_basis()]) + sage: Matrix([[x*y for y in A13.basis()] for x in A13.basis()]) [ x0 x1 x2 x3] [ x1 x0 + x2 x1 + x3 x2] [ x2 x1 + x3 x0 + x2 x1] [ x3 x2 x1 x0] + + We reset the labels to the default:: + + sage: A13.fusion_labels() + sage: fb + [A13(0), A13(1), A13(2), A13(3)] """ + if labels is None: + self._fusion_labels = None + return d = {} - fb = self.fusion_basis() - for j in range(len(fb)): - d[fb[j].fusion_weight()]=labels[j] - inject_variable(labels[j],fb[j]) + fb = list(self.basis()) + for j,b in enumerate(fb): + wt = b.fusion_weight() + t = tuple([wt.inner_product(x) for x in self.simple_coroots()]) + d[t] = labels[j] + inject_variable(labels[j], b) self._fusion_labels = d class Element(WeylCharacterRing.Element): @@ -2225,3 +2233,4 @@ def fusion_weight(self): if len(self.monomial_coefficients()) != 1: raise ValueError("fusion weight is valid for basis elements only") return self.leading_support() + From ff9871683c0cb3c9b680493cf29f2d8017e25907 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Tue, 23 Oct 2018 22:45:17 -0700 Subject: [PATCH 09/14] make dual a method of the element, not the ring --- .../combinat/root_system/weyl_characters.py | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index f61b89d4397..59627370315 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -782,25 +782,6 @@ def _dual_helper(self, wt): ret += wt.inner_product(alphacheck[i])*fw[self._opposition[i]] return ret - def dual(self, elt): - """ - The involution that replaces a representation with - its contragredient. (For Fusion rings, this is the - conjugation map.) - - EXAMPLES:: - - sage: A3=WeylCharacterRing("A3",style="coroots") - sage: A3(1,0,0)^2 - A3(0,1,0) + A3(2,0,0) - sage: A3.dual(A3(1,0,0)^2) - A3(0,1,0) + A3(0,0,2) - """ - if not self.cartan_type().is_atomic(): - raise NotImplementedError("dual method is not implemented for reducible types") - d = elt.monomial_coefficients() - return sum(d[k]*self(self._dual_helper(k)) for k in d.keys()) - def _wt_repr(self, wt): """ Produce a representation of a vector in either coweight or @@ -1191,6 +1172,25 @@ def branch(self, S, rule="default"): """ return sage.combinat.root_system.branching_rules.branch_weyl_character(self, self.parent(), S, rule=rule) + def dual(self): + """ + The involution that replaces a representation with + its contragredient. (For Fusion rings, this is the + conjugation map.) + + EXAMPLES:: + + sage: A3=WeylCharacterRing("A3",style="coroots") + sage: A3(1,0,0)^2 + A3(0,1,0) + A3(2,0,0) + sage: (A3(1,0,0)^2).dual() + A3(0,1,0) + A3(0,0,2) + """ + if not self.parent().cartan_type().is_atomic(): + raise NotImplementedError("dual method is not implemented for reducible types") + d = self.monomial_coefficients() + return sum(d[k]*self.parent()._element_constructor_(self.parent()._dual_helper(k)) for k in d.keys()) + def __pow__(self, n): """ Return the nth power of self. From 02fb2383c474bc4f3f8c8d8a41b01c74555ca2b7 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Thu, 25 Oct 2018 07:54:30 -0700 Subject: [PATCH 10/14] added a few doctests --- .../combinat/root_system/weyl_characters.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 59627370315..1b4cfeb743f 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -553,10 +553,15 @@ def affine_reflect(self, wt, k=0): - ``k`` -- (optional) a positive integer Returns the reflection of wt in the hyperplane - perpendicular to the longest root `\theta`. - Optionally shifts by a multiple `k`of `\theta`. - """ + `\theta`. Optionally shifts by a multiple `k`of `\theta`. + EXAMPLES:: + sage: B22=FusionRing("B2",2) + sage: fw = B22.fundamental_weights(); fw + Finite family {1: (1, 0), 2: (1/2, 1/2)} + sage: [B22.affine_reflect(x,2) for x in fw] + [(2, 1), (3/2, 3/2)] + """ coef = ZZ(2*wt.inner_product(self._highest)/self._hip) return wt+(k-coef)*self._highest @@ -765,6 +770,12 @@ def level(self, wt): """ Return the level of the weight, defined to be the value of the weight on the coroot associated with the highest root. + + EXAMPLES:: + sage: R = FusionRing("F4",2); [R.level(x) for x in R.fundamental_weights()] + [2, 3, 2, 1] + sage: [CartanType("F4~").dual().a()[x] for x in [1..4]] + [2, 3, 2, 1] """ return ZZ(2*wt.inner_product(self._highest)/self._hip) @@ -2139,10 +2150,11 @@ class FusionRing(WeylCharacterRing): - ``k`` -- a nonnegative integer Returns the Fusion Ring (Verlinde Algebra) of level k. See: - + * J. Fuchs, Fusion Rules for Conformal Field Theory. arXiv:hep-th/9306162 * Walton, Mark A. Fusion rules in Wess-Zumino-Witten models. Nuclear Phys. B 340 (1990). * Feingold, Fusion rules for affine Kac-Moody algebras. Contemp. Math., 343. arXiv:math/0212387 + * Di Francesco, Mathiew and Senechal, Conformal Field Theory, Chapter 16. This algebra has a basis indexed by the weights of level `\leq k`. It is implemented as a variant of the WeylCharacterRing. From 6736b8c8196d11167d44fc647668380781391581 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Thu, 25 Oct 2018 13:09:38 -0700 Subject: [PATCH 11/14] fusion_weight element is made a method of WeylCharacterRing Elements and renamed highest_weight. --- .../combinat/root_system/weyl_characters.py | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 1b4cfeb743f..ff9e3fd0147 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -1202,6 +1202,23 @@ def dual(self): d = self.monomial_coefficients() return sum(d[k]*self.parent()._element_constructor_(self.parent()._dual_helper(k)) for k in d.keys()) + def highest_weight(self): + """ + This method is only available for basis elements. Returns the + parametrizing dominant weight of an irreducible character or + simple element of a FusionRing. + + Examples:: + + sage: G2=WeylCharacterRing("G2",style="coroots") + sage: [x.highest_weight() for x in [G2(1,0),G2(0,1)]] + [(1, 0, -1), (2, -1, -1)] + + """ + if len(self.monomial_coefficients()) != 1: + raise ValueError("fusion weight is valid for basis elements only") + return self.leading_support() + def __pow__(self, n): """ Return the nth power of self. @@ -2179,7 +2196,7 @@ class FusionRing(WeylCharacterRing): sage: B22 = FusionRing("B2",2) sage: list(B22.basis()) [B22(0,0), B22(0,1), B22(1,0), B22(2,0), B22(1,1), B22(0,2)] - sage: [x.fusion_weight() for x in B22.basis()] + sage: [x.highest_weight() for x in B22.basis()] [(0, 0), (1/2, 1/2), (1, 0), (2, 0), (3/2, 1/2), (1, 1)] sage: B22.fusion_labels(['1','X','Y1','Z','Xp','Y2']) sage: list(B22.basis()) @@ -2234,15 +2251,9 @@ def fusion_labels(self, labels=None): d = {} fb = list(self.basis()) for j,b in enumerate(fb): - wt = b.fusion_weight() + wt = b.highest_weight() t = tuple([wt.inner_product(x) for x in self.simple_coroots()]) d[t] = labels[j] inject_variable(labels[j], b) self._fusion_labels = d - class Element(WeylCharacterRing.Element): - def fusion_weight(self): - if len(self.monomial_coefficients()) != 1: - raise ValueError("fusion weight is valid for basis elements only") - return self.leading_support() - From d18b3d8ad4a449c221d7ec1648216297ae17c2cf Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Thu, 25 Oct 2018 13:50:24 -0700 Subject: [PATCH 12/14] doctest for _dual_helper --- src/sage/combinat/root_system/weyl_characters.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index ff9e3fd0147..f414ed55c4d 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -133,7 +133,6 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): self._k = k if ct.is_atomic(): self._opposition = ct.opposition_automorphism() - if k is not None: self._highest = self._space.highest_root() self._hip = self._highest.inner_product(self._highest) if style == "coroots": @@ -556,6 +555,7 @@ def affine_reflect(self, wt, k=0): `\theta`. Optionally shifts by a multiple `k`of `\theta`. EXAMPLES:: + sage: B22=FusionRing("B2",2) sage: fw = B22.fundamental_weights(); fw Finite family {1: (1, 0), 2: (1/2, 1/2)} @@ -772,6 +772,7 @@ def level(self, wt): the weight on the coroot associated with the highest root. EXAMPLES:: + sage: R = FusionRing("F4",2); [R.level(x) for x in R.fundamental_weights()] [2, 3, 2, 1] sage: [CartanType("F4~").dual().a()[x] for x in [1..4]] @@ -783,6 +784,12 @@ def _dual_helper(self, wt): """ If `w_0` is the long Weyl group element and `wt` is an element of the weight lattice, this returns `-w_0(wt)`. + + EXAMPLES:: + + sage: A3=WeylCharacterRing("A3") + sage: [A3._dual_helper(x) for x in A3.fundamental_weights()] + [(0, 0, 0, -1), (0, 0, -1, -1), (0, -1, -1, -1)] """ if self.cartan_type()[0] == 'A': # handled separately for GL(n) compatibility return self.space()([-x for x in reversed(wt.to_vector().list())]) From 102b00b855ae5c641f741ced0134a84825a04085 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 26 Oct 2018 12:19:50 +1000 Subject: [PATCH 13/14] Added some doctets, fixed bug with some_elements, moved the refences to master ref file. --- src/doc/en/reference/references/index.rst | 15 ++++ .../combinat/root_system/weyl_characters.py | 81 ++++++++++++++----- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index ce4cc2b08f9..84edbc942a9 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -910,6 +910,10 @@ REFERENCES: .. [Dev2005] Devaney, Robert L. *An Introduction to Chaotic Dynamical Systems.* Boulder: Westview, 2005, 331. +.. [DFMS1996] Philipppe Di Francesco, Pierre Mathieu, and David Sénéchal. + *Conformal Field Theory*. Graduate Texts in Contemporary + Physics, Springer, 1996. + .. [DG1982] Louise Dolan and Michael Grady. *Conserved charges from self-duality*, Phys. Rev. D(3) **25** (1982), no. 6, 1587-1604. @@ -1126,6 +1130,10 @@ REFERENCES: .. [Fed2015] Federal Agency on Technical Regulation and Metrology (GOST), GOST R 34.12-2015, (2015) +.. [Feingold2004] Alex J. Feingold. *Fusion rules for affine Kac-Moody algebras*. + Contemp. Math., **343** (2004), pp. 53-96. + :arXiv:`math/0212387` + .. [Feu2009] \T. Feulner. The Automorphism Groups of Linear Codes and Canonical Representatives of Their Semilinear Isometry Classes. Advances in Mathematics of Communications 3 (4), @@ -1199,6 +1207,10 @@ REFERENCES: *Young Tableaux*. Cambridge University Press, 1997. +.. [Fuchs1994] \J. Fuchs. *Fusion Rules for Conformal Field Theory*. + Fortsch. Phys. **42** (1994), no. 1, pp. 1-48. + :doi:`10.1002/prop.2190420102`, :arXiv:`hep-th/9306162`. + .. [FY2004] Eva Maria Feichtner and Sergey Yuzvinsky. *Chow rings of toric varieties defined by atomic lattices*. Inventiones Mathematicae. **155** (2004), no. 3, pp. 515-536. @@ -3027,6 +3039,9 @@ REFERENCES: Math. Combin. Comput. **36** (2001), 95-118. http://www.info2.uqam.ca/~walsh_t/papers/Involutions%20paper.pdf +.. [Walton1990] Mark A. Walton. *Fusion rules in Wess-Zumino-Witten models*. + Nuclear Phys. B **340** (1990). + .. [Wam1999] van Wamelen, Paul. *Examples of genus two CM curves defined over the rationals*. Math. Comp. 68 (1999), no. 225, 307--320. diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index f414ed55c4d..0eaeae48efb 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -2168,39 +2168,34 @@ def demazure_lusztig(self, i, v): class FusionRing(WeylCharacterRing): r""" + Return the Fusion Ring (Verlinde Algebra) of level ``k``. + INPUT: - ``ct`` -- the Cartan type of a simple (finite-dimensional) Lie algebra - ``k`` -- a nonnegative integer - - Returns the Fusion Ring (Verlinde Algebra) of level k. See: - - * J. Fuchs, Fusion Rules for Conformal Field Theory. arXiv:hep-th/9306162 - * Walton, Mark A. Fusion rules in Wess-Zumino-Witten models. Nuclear Phys. B 340 (1990). - * Feingold, Fusion rules for affine Kac-Moody algebras. Contemp. Math., 343. arXiv:math/0212387 - * Di Francesco, Mathiew and Senechal, Conformal Field Theory, Chapter 16. - This algebra has a basis indexed by the weights of level `\leq k`. It is implemented - as a variant of the WeylCharacterRing. + This algebra has a basis indexed by the weights of level `\leq k`. + It is implemented as a variant of the :class:`WeylCharacterRing`. EXAMPLES:: sage: A22 = FusionRing("A2",2) - sage: [f1,f2]=A22.fundamental_weights() - sage: [m0,m1,m2,m3,m4,m5]=[A22(x) for x in [0*f1,2*f1,2*f2,f1+f2,f2,f1]] - sage: [m3*x for x in [m0,m1,m2,m3,m4,m5]] + sage: [f1, f2] = A22.fundamental_weights() + sage: M = [A22(x) for x in [0*f1, 2*f1, 2*f2, f1+f2, f2, f1]] + sage: [M[3] * x for x in M] [A22(1,1), - A22(0,1), - A22(1,0), - A22(0,0) + A22(1,1), - A22(0,1) + A22(2,0), - A22(1,0) + A22(0,2)] + A22(0,1), + A22(1,0), + A22(0,0) + A22(1,1), + A22(0,1) + A22(2,0), + A22(1,0) + A22(0,2)] You may assign your own labels to the basis elements. In the next - example, we create the SO(5) fusion ring of level 2, check the + example, we create the `SO(5)` fusion ring of level `2`, check the weights of the basis elements, then assign new labels to them:: - sage: B22 = FusionRing("B2",2) + sage: B22 = FusionRing("B2", 2) sage: list(B22.basis()) [B22(0,0), B22(0,1), B22(1,0), B22(2,0), B22(1,1), B22(0,2)] sage: [x.highest_weight() for x in B22.basis()] @@ -2213,13 +2208,57 @@ class FusionRing(WeylCharacterRing): sage: Z*Z 1 - sage: C22 = FusionRing("C2",2) + sage: C22 = FusionRing("C2", 2) sage: list(C22.basis()) [C22(0,0), C22(0,1), C22(1,0), C22(2,0), C22(0,2), C22(1,1)] + + REFERENCES: + + - [DFMS1996]_ Chapter 16 + - [Feingold2004]_ + - [Fuchs1994]_ + - [Walton1990]_ """ @staticmethod def __classcall__(cls, ct, k, base_ring=ZZ, prefix=None, style="coroots"): - return super(FusionRing, cls).__classcall__(cls, ct, base_ring=base_ring, prefix=prefix, style=style, k=k) + """ + Normalize input to ensure a unique representation. + + TESTS:: + + sage: F1 = FusionRing('B3', 2) + sage: F2 = FusionRing(CartanType('B3'), QQ(2), ZZ) + sage: F3 = FusionRing(CartanType('B3'), int(2), style="coroots") + sage: F1 is F2 and F2 is F3 + True + + sage: A23 = FusionRing('A2', 3) + sage: TestSuite(A23).run() + + sage: B22 = FusionRing('B2', 2) + sage: TestSuite(B22).run() + + sage: C31 = FusionRing('C3', 1) + sage: TestSuite(C31).run() + + sage: D41 = FusionRing('D4', 1) + sage: TestSuite(D41).run() + """ + return super(FusionRing, cls).__classcall__(cls, ct, base_ring=base_ring, + prefix=prefix, style=style, k=k) + + def some_elements(self): + """ + Return some elements of ``self``. + + EXAMPLES:: + + sage: D41 = FusionRing('D4', 1) + sage: D41.some_elements() + [D41(1,0,0,0), D41(0,0,1,0), D41(0,0,0,1)] + """ + return [self.monomial(x) for x in self.fundamental_weights() + if self.level(x) <= self._k] def fusion_labels(self, labels=None): r""" From 7546a0d9c6496761ded1266fd6c423c85e2a1fa0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 28 Oct 2018 09:21:11 +1000 Subject: [PATCH 14/14] Test for reducibility rather than atomicness for dual. --- src/sage/combinat/root_system/weyl_characters.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 0eaeae48efb..36a552dd6ee 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -131,7 +131,7 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None): self._style = style self._fusion_labels = None self._k = k - if ct.is_atomic(): + if ct.is_irreducible(): self._opposition = ct.opposition_automorphism() self._highest = self._space.highest_root() self._hip = self._highest.inner_product(self._highest) @@ -1198,16 +1198,18 @@ def dual(self): EXAMPLES:: - sage: A3=WeylCharacterRing("A3",style="coroots") + sage: A3 = WeylCharacterRing("A3", style="coroots") sage: A3(1,0,0)^2 A3(0,1,0) + A3(2,0,0) sage: (A3(1,0,0)^2).dual() A3(0,1,0) + A3(0,0,2) """ - if not self.parent().cartan_type().is_atomic(): + if not self.parent().cartan_type().is_irreducible(): raise NotImplementedError("dual method is not implemented for reducible types") d = self.monomial_coefficients() - return sum(d[k]*self.parent()._element_constructor_(self.parent()._dual_helper(k)) for k in d.keys()) + WCR = self.parent() + return sum(d[k] * WCR._element_constructor_(self.parent()._dual_helper(k)) + for k in d) def highest_weight(self): """