Ticket #3664: trac_3664-1.patch
| File trac_3664-1.patch, 205.7 KB (added by mhansen, 5 years ago) |
|---|
-
sage/combinat/crystals/crystals.py
# HG changeset patch # User Nicolas M. Thiery <nthiery@users.sf.net> # Date 1218050423 18000 # Node ID db34e50d9e6c422bbec0f0f666e101d6c0e777b5 # Parent 29be632ff7bcefcb1b56903c58c550391c41dd6f Improvements / refactoring of root system code. diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/crystals/crystals.py
a b 145 145 EXAMPLES: 146 146 sage: C = CrystalOfLetters(['A', 5]) 147 147 sage: C.weight_lattice_realization() 148 Ambient lattice of the root system of type ['A', 5]148 Ambient space for the Root system of type ['A', 5] 149 149 """ 150 return self.cartan_type.root_system().ambient_ lattice()150 return self.cartan_type.root_system().ambient_space() 151 151 152 152 def Lambda(self): 153 153 """ -
sage/combinat/root_system/all.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/all.py
a b 1 1 from cartan_type import CartanType 2 from dynkin_diagram import dynkin_diagram2 from dynkin_diagram import DynkinDiagram, dynkin_diagram 3 3 from cartan_matrix import cartan_matrix 4 4 from coxeter_matrix import coxeter_matrix 5 5 from root_system import RootSystem, WeylDim -
new file sage/combinat/root_system/ambient_space.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/ambient_space.py
- + 1 from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement 2 from root_lattice_realization import RootLatticeRealizationElement 3 from weight_lattice_realization import WeightLatticeRealization 4 from sage.modules.free_module import FreeModule 5 from sage.rings.all import ZZ, QQ 6 from sage.modules.free_module_element import vector 7 8 class AmbientSpace(CombinatorialFreeModule, WeightLatticeRealization): 9 r""" 10 Abstract class for ambient spaces 11 12 Any implementation of this class should implement a class method 13 smallest_base_ring as described below, and a method dimension 14 working on a partially initialized instance with just root_system 15 as attribute. There is no safe default implementation for the later, 16 so none is provided. 17 """ 18 19 # FIXME: attribute or method? 20 def dimension(self): 21 """ 22 Returns the dimension of this ambient space 23 """ 24 raise NotImplementedError 25 26 @classmethod 27 def smallest_base_ring(cls): 28 """ 29 Returns the smallest ground ring over which the ambient space can be realized 30 """ 31 return QQ; 32 33 def __init__(self, root_system, base_ring): 34 """ 35 EXAMPLES: 36 sage: e = RootSystem(['A',3]).ambient_lattice() 37 sage: e == loads(dumps(e)) 38 True 39 """ 40 self.root_system = root_system 41 basis_name = "alphacheck" if root_system.dualSide else "alpha" 42 CombinatorialFreeModule.__init__(self, base_ring,\ 43 #range(1,self.dimension()+1),\ 44 range(0,self.dimension()),\ 45 element_class = AmbientSpaceElement,\ 46 prefix='e') 47 48 # FIXME: here for backward compatibility; 49 # Should we use dimension everywhere? 50 self.n = self.dimension() 51 52 def __repr__(self): 53 """ 54 TEST: 55 sage: RootSystem(['A',4]).ambient_lattice() 56 Ambient lattice for the Root system of type ['A', 4] 57 sage: RootSystem(['B',4]).ambient_space() 58 Ambient space for the Root system of type ['B', 4] 59 60 """ 61 if self.base_ring() == ZZ: 62 space = "lattice" 63 else: 64 space = "space" 65 return "Ambient "+space+" for the %s"%self.root_system 66 67 def __call__(self, v): 68 """ 69 TESTS: 70 sage: R = RootSystem(['A',4]).ambient_lattice() 71 sage: R([1,2,3,4,5]) 72 (1, 2, 3, 4, 5) 73 """ 74 # This adds coercion from a list 75 if isinstance(v, list) or isinstance(v, tuple): 76 K = self.base_ring() 77 return self._from_dict(dict([(i,K(v[i])) for i in range(len(v))])) 78 else: 79 return CombinatorialFreeModule.__call__(self, v) 80 81 # For backward compatibility 82 def _term(self, i): 83 self.term(i) 84 85 def __getitem__(self,i): 86 """ 87 Note that indexing starts at 1. 88 89 EXAMPLES: 90 sage: e = RootSystem(['A',2]).ambient_lattice() 91 sage: e[1] 92 (1, 0, 0) 93 """ 94 return self.term(i-1) 95 96 def coroot_lattice(self): 97 return self 98 99 def simple_coroot(self, i): 100 r""" 101 Returns the i-th simple coroot, as an element of this space 102 103 EXAMPLE: 104 sage: R = RootSystem(["A",3]) 105 sage: L = R.ambient_lattice () 106 sage: L.simple_coroot(1) 107 (1, -1, 0, 0) 108 sage: L.simple_coroot(2) 109 (0, 1, -1, 0) 110 sage: L.simple_coroot(3) 111 (0, 0, 1, -1) 112 """ 113 return self.simple_root(i).associated_coroot() 114 115 def reflection(self, root, coroot=None): 116 # TODO: get rid of this as one can use the generic implementation 117 # (i.e. scalar and associated coroot are implemented) 118 return lambda v: v-2*root.inner_product(v)/root.inner_product(root)*root 119 120 def _term(self, i): 121 """ 122 Note that indexing starts at 0. 123 124 EXAMPLES: 125 sage: e = RootSystem(['A',2]).ambient_lattice() 126 sage: e._term(0) 127 (1, 0, 0) 128 """ 129 return self.term(i) 130 131 def __cmp__(self, other): 132 """ 133 EXAMPLES: 134 sage: e1 = RootSystem(['A',3]).ambient_lattice() 135 sage: e2 = RootSystem(['B',3]).ambient_lattice() 136 sage: e1 == e1 137 True 138 sage: e1 == e2 139 False 140 """ 141 if self.__class__ != other.__class__: 142 return cmp(self.__class__, other.__class__) 143 if self.root_system != other.root_system: 144 return cmp(self.root_system, other.root_system) 145 return 0 146 147 class AmbientSpaceElement(CombinatorialFreeModuleElement, RootLatticeRealizationElement): 148 149 # For backward compatibility 150 def __repr__(self): 151 return str(self.to_vector()) 152 153 def inner_product(self, lambdacheck): 154 """ 155 The scalar product with elements of the coroot lattice 156 embedded in the ambient space 157 """ 158 assert(lambdacheck.parent() == self.parent()) 159 return sum((c*self[t] for (t,c) in lambdacheck), 160 self.parent().base_ring().zero_element()) 161 162 scalar = inner_product 163 dot_product = inner_product 164 165 def associated_coroot(self): 166 # FIXME: make it work over ZZ! 167 return self * (2/self.inner_product(self)) 168 -
sage/combinat/root_system/cartan_matrix.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/cartan_matrix.py
a b 15 15 # 16 16 # http://www.gnu.org/licenses/ 17 17 #***************************************************************************** 18 from dynkin_diagram import dynkin_diagram_as_function19 18 import cartan_type 20 19 from sage.matrix.all import MatrixSpace 21 20 from sage.rings.all import ZZ 22 23 def cartan_matrix_as_function(t):24 """25 Returns a function that represents the Cartan matrix26 of type t.27 28 EXAMPLES:29 sage: from sage.combinat.root_system.cartan_matrix import cartan_matrix_as_function30 sage: f = cartan_matrix_as_function(['A',4])31 sage: matrix([[f(i,j) for j in range(1,5)] for i in range(1,5)])32 [ 2 -1 0 0]33 [-1 2 -1 0]34 [ 0 -1 2 -1]35 [ 0 0 -1 2]36 """37 ct = cartan_type.CartanType(t)38 f = dynkin_diagram_as_function(ct)39 cmf = lambda i,j: 2 if i == j else -f(j,i)40 return cmf41 21 42 22 def cartan_matrix(t): 43 23 """ … … 54 34 [-1 2 -1 0 0 0] 55 35 [ 0 -1 2 -1 0 0] 56 36 [ 0 0 -1 2 -1 0] 57 [ 0 0 0 -1 2 - 2]58 [ 0 0 0 0 - 12]37 [ 0 0 0 -1 2 -1] 38 [ 0 0 0 0 -2 2] 59 39 sage: cartan_matrix(['C', 4]) 60 40 [ 2 -1 0 0] 61 41 [-1 2 -1 0] 62 [ 0 -1 2 - 1]63 [ 0 0 - 22]42 [ 0 -1 2 -2] 43 [ 0 0 -1 2] 64 44 sage: cartan_matrix(['D', 6]) 65 45 [ 2 -1 0 0 0 0] 66 46 [-1 2 -1 0 0 0] … … 68 48 [ 0 0 -1 2 -1 -1] 69 49 [ 0 0 0 -1 2 0] 70 50 [ 0 0 0 -1 0 2] 51 sage: cartan_matrix(['E',6]) 52 [ 2 0 -1 0 0 0] 53 [ 0 2 0 -1 0 0] 54 [-1 0 2 -1 0 0] 55 [ 0 -1 -1 2 -1 0] 56 [ 0 0 0 -1 2 -1] 57 [ 0 0 0 0 -1 2] 58 sage: cartan_matrix(['E',7]) 59 [ 2 0 -1 0 0 0 0] 60 [ 0 2 0 -1 0 0 0] 61 [-1 0 2 -1 0 0 0] 62 [ 0 -1 -1 2 -1 0 0] 63 [ 0 0 0 -1 2 -1 0] 64 [ 0 0 0 0 -1 2 -1] 65 [ 0 0 0 0 0 -1 2] 71 66 sage: cartan_matrix(['E', 8]) 72 67 [ 2 0 -1 0 0 0 0 0] 73 68 [ 0 2 0 -1 0 0 0 0] … … 79 74 [ 0 0 0 0 0 0 -1 2] 80 75 sage: cartan_matrix(['F', 4]) 81 76 [ 2 -1 0 0] 82 [-1 2 -2 0] 77 [-1 2 -1 0] 78 [ 0 -2 2 -1] 79 [ 0 0 -1 2] 80 81 This is different from MuPAD-Combinat, due to different node convention? 82 83 sage: cartan_matrix(['G', 2]) 84 [ 2 -3] 85 [-1 2] 86 sage: cartan_matrix(['A', 3, 1]) 87 [ 2 -1 0 -1] 88 [-1 2 -1 0] 83 89 [ 0 -1 2 -1] 90 [-1 0 -1 2] 91 sage: cartan_matrix(['B', 3, 1]) 92 [ 2 0 -1 0] 93 [ 0 2 -1 0] 94 [-1 -1 2 -1] 95 [ 0 0 -2 2] 96 sage: cartan_matrix(['C', 3, 1]) 97 [ 2 -1 0 0] 98 [-2 2 -1 0] 99 [ 0 -1 2 -2] 84 100 [ 0 0 -1 2] 85 sage: cartan_matrix(['G', 2]) 86 [ 2 -1] 87 [-3 2] 88 101 sage: cartan_matrix(['D', 4, 1]) 102 [ 2 0 -1 0 0] 103 [ 0 2 -1 0 0] 104 [-1 -1 2 -1 -1] 105 [ 0 0 -1 2 0] 106 [ 0 0 -1 0 2] 107 sage: cartan_matrix(['E', 6, 1]) 108 [ 2 0 -1 0 0 0 0] 109 [ 0 2 0 -1 0 0 0] 110 [-1 0 2 0 -1 0 0] 111 [ 0 -1 0 2 -1 0 0] 112 [ 0 0 -1 -1 2 -1 0] 113 [ 0 0 0 0 -1 2 -1] 114 [ 0 0 0 0 0 -1 2] 115 sage: cartan_matrix(['E', 7, 1]) 116 [ 2 -1 0 0 0 0 0 0] 117 [-1 2 0 -1 0 0 0 0] 118 [ 0 0 2 0 -1 0 0 0] 119 [ 0 -1 0 2 -1 0 0 0] 120 [ 0 0 -1 -1 2 -1 0 0] 121 [ 0 0 0 0 -1 2 -1 0] 122 [ 0 0 0 0 0 -1 2 -1] 123 [ 0 0 0 0 0 0 -1 2] 124 sage: cartan_matrix(['E', 8, 1]) 125 [ 2 0 0 0 0 0 0 0 -1] 126 [ 0 2 0 -1 0 0 0 0 0] 127 [ 0 0 2 0 -1 0 0 0 0] 128 [ 0 -1 0 2 -1 0 0 0 0] 129 [ 0 0 -1 -1 2 -1 0 0 0] 130 [ 0 0 0 0 -1 2 -1 0 0] 131 [ 0 0 0 0 0 -1 2 -1 0] 132 [ 0 0 0 0 0 0 -1 2 -1] 133 [-1 0 0 0 0 0 0 -1 2] 134 sage: cartan_matrix(['F', 4, 1]) 135 [ 2 -1 0 0 0] 136 [-1 2 -1 0 0] 137 [ 0 -1 2 -1 0] 138 [ 0 0 -2 2 -1] 139 [ 0 0 0 -1 2] 140 sage: cartan_matrix(['G', 2, 1]) 141 [ 2 0 -1] 142 [ 0 2 -3] 143 [-1 -1 2] 89 144 """ 90 ct = cartan_type.CartanType(t)91 index_set = ct.index_set()92 cmf = cartan_matrix_as_function(ct)145 t = cartan_type.CartanType(t) 146 dynkin_diagram = t.dynkin_diagram() 147 index_set = t.index_set() 93 148 MS = MatrixSpace(ZZ, len(index_set), sparse=True) 94 149 m = MS(0) 95 150 for i in range(len(index_set)): 96 151 for j in range(len(index_set)): 97 m[i,j] = cmf(index_set[i],index_set[j])152 m[i,j] = dynkin_diagram[index_set[i],index_set[j]] 98 153 return m -
sage/combinat/root_system/cartan_type.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/cartan_type.py
a b 15 15 # 16 16 # http://www.gnu.org/licenses/ 17 17 #***************************************************************************** 18 import sage.combinat.root_system.root_system as root_system 18 #import sage.combinat.root_system.root_system as root_system 19 from sage.combinat import root_system 19 20 from cartan_matrix import cartan_matrix 21 from sage.rings.all import ZZ 20 22 21 def CartanType(t): 23 # TODO: 24 # Get rid of almost all runtype type checking by extending the class hierarchy with: 25 # - type_relabel.CartanType (in type_relabel module, together with relabelled AmbientSpace) 26 # - CartanType_crystalographic 27 # - CartanType_simply_laced 28 # - type_A.CartanType (in the type_A module) 29 # - ... 30 # - CartanType_untwisted_affine 31 # - type_A_affine.CartanType 32 # - type_BC_affine.CartanType 33 # ... 34 # Implement the Kac conventions by relabeling/dual/... of the above 35 # Implement coxeter diagrams for non crystalographic 36 # Implement dual ambient space 37 38 39 class CartanTypeFactory: 40 # Intention: we want simultaneously CartanType to be a factory for 41 # the various subtypes of CartanType_abstract, as in: 42 # CartanType(["A",4,1]) 43 # and to behaves as a "module" for some extra utilities: 44 # CartanType.samples() 45 # 46 # Implementation: CartanType is the unique instance of this class 47 # CartanTypeFactory. Is there a better/more standard way to do it? 48 49 def __call__(self, *args): 22 50 """ 23 51 Returns an object corresponding to the Cartan type t. 52 INPUT: 53 [letter, rank] 54 where letter is one of 'A','B','C','D','E','F','G' and rank 55 is the rank. An alternative string notation is allowed. 56 A third optional parameter is permitted for affine 57 types. Reducible types may be entered by giving a list of 58 irreducible types or by a single string 24 59 25 60 EXAMPLES: 26 61 sage: CartanType(['A',4]) 27 62 ['A', 4] 63 sage: CartanType("A4") 64 ['A', 4] 65 sage: CartanType(['A',2],['B',2]) 66 A2xB2 67 sage: CartanType(['A',2],['B',2]).is_reducible() 68 True 69 sage: CartanType("A2xB2") 70 A2xB2 71 sage: CartanType("A2","B2") == CartanType("A2xB2") 72 True 73 sage: CartanType(['A',4,1]) 74 ['A', 4, 1] 75 sage: CartanType(['A',4,1]).is_affine() 76 True 28 77 """ 29 if isinstance(t, CartanType_simple): 78 if len(args) == 1: 79 t = args[0] 80 else: 81 t = args 82 if isinstance(t, CartanType_abstract): 30 83 return t 31 else:32 return CartanType_simple(t)33 84 34 class CartanType_simple: 35 def __init__(self, t): 85 if type(t)==str: 86 if "x" in t: 87 return root_system.type_reducible.CartanType([CartanType(u) for u in t.split("x")]) 88 else: 89 return CartanType([t[0], eval(t[1:])]) 90 91 t = list(t) 92 93 if type(t[0]) == str and t[1] in ZZ: 94 if len(t) == 2: 95 return CartanType_simple_finite(t) 96 elif len(t) == 3: 97 return CartanType_simple_affine(t) 98 99 return root_system.type_reducible.CartanType([ CartanType(subt) for subt in t ]) 100 101 def samples(self, finite=False, affine=False, crystalographic=False): 102 """ 103 Returns a sample of the implemented cartan types 104 105 With finite=True resp. affine=True, one can restrict to finite 106 resp. affine only cartan types 107 108 EXAMPLES: 109 sage: CartanType.samples(finite=True) 110 [['A', 1], ['A', 5], ['B', 5], ['C', 5], ['D', 5], ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4]] 111 112 sage: CartanType.samples(affine=True) 113 [['A', 1, 1], ['A', 5, 1], ['B', 5, 1], ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['A', 2, 2], ['A', 10, 2], ['A', 9, 2], ['D', 5, 2], ['D', 4, 3], ['E', 6, 2]] 114 115 sage: CartanType.samples() 116 [['A', 1], ['A', 5], ['B', 5], ['C', 5], ['D', 5], ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4], ['A', 1, 1], ['A', 5, 1], ['B', 5, 1], ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['A', 2, 2], ['A', 10, 2], ['A', 9, 2], ['D', 5, 2], ['D', 4, 3], ['E', 6, 2]] 117 sage: CartanType.samples(crystalographic=True) 118 [['A', 1], ['A', 5], ['B', 5], ['C', 5], ['D', 5], ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['A', 1, 1], ['A', 5, 1], ['B', 5, 1], ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['A', 2, 2], ['A', 10, 2], ['A', 9, 2], ['D', 5, 2], ['D', 4, 3], ['E', 6, 2]] 119 """ 120 if crystalographic: 121 return [ t for t in CartanType.samples(finite=finite, affine=affine) if t.is_crystalographic() ] 122 if finite: 123 return([CartanType(t) for t in [["A", 1], ["A", 5], ["B", 5], ["C", 5], ["D", 5], 124 ["E", 6], ["E", 7], ["E", 8], 125 ["F", 4], 126 ["G", 2], 127 ["I", 5], 128 ["H", 3], ["H", 4]]]) 129 elif affine: 130 return([t.affine() for t in CartanType.samples(finite=True, crystalographic=True)] + 131 [CartanType(t) for t in [["A", 2, 2], ["A", 10, 2], ["A", 9, 2], 132 ["D", 5, 2], 133 ["D", 4, 3], 134 ["E", 6, 2]]]); 135 else: 136 return CartanType.samples(finite=True) + CartanType.samples(affine=True) 137 138 CartanType = CartanTypeFactory() 139 140 class CartanType_abstract: 141 r""" 142 Abstract class for cartan types 143 144 Subclasses should implement: 145 146 type() 147 dynkin_diagram() 148 cartan_matrix() 149 is_finite() 150 is_affine() 151 is_irreducible() 152 """ 153 154 def type(self): 155 r""" 156 Returns the type of self, or None if unknown 36 157 """ 37 EXAMPLES: 38 sage: ct = CartanType(['A',4]) 39 sage: ct == loads(dumps(ct)) 40 True 41 """ 42 self.t = t 43 44 self.letter = t[0] 45 self.n = t[1] 46 47 if len(t) > 2: 48 self.affine = t[2] 49 else: 50 self.affine = None 51 52 def __hash__(self): 53 """ 54 EXAMPLES: 55 sage: ct = CartanType(['A',2]) 56 sage: hash(ct) #random 57 -5684143898951441983 58 """ 59 return hash( (self.letter,self.n,self.affine) ) 60 61 62 def __repr__(self): 63 """ 64 TESTS: 65 sage: ct = CartanType(['A',3]) 66 sage: repr(ct) 67 "['A', 3]" 68 """ 69 if self.affine is None: 70 return "['%s', %s]"%(self.letter, self.n) 71 else: 72 return "['%s', %s, %s]"%(self.letter, self.n, self.affine) 73 74 def __getitem__(self, x): 75 """ 76 EXAMPLES: 77 sage: t = CartanType(['A', 3, 1]) 78 sage: t[0] 79 'A' 80 sage: t[1] 81 3 82 sage: t[2] 83 1 84 sage: t[3] 85 Traceback (most recent call last): 86 ... 87 IndexError: list index out of range 88 """ 89 return self.t[x] 90 91 def __cmp__(self, other): 92 """ 93 EXAMPLES: 94 sage: ct1 = CartanType(['A',4]) 95 sage: ct2 = CartanType(['A',4]) 96 sage: ct3 = CartanType(['A',5]) 97 sage: ct1 == ct2 98 True 99 sage: ct1 != ct3 100 True 101 """ 102 if other.__class__ != self.__class__: 103 return cmp(self.__class__, other.__class__) 104 105 if other.letter != self.letter: 106 return cmp(self.letter, other.letter) 107 if other.affine != self.affine: 108 return cmp(self.affine, other.affine) 109 if other.n != self.n: 110 return cmp(self.n, other.n) 111 112 return 0 113 114 115 def __len__(self): 116 """ 117 EXAMPLES: 118 sage: len(CartanType(['A',4])) 119 2 120 sage: len(CartanType(['A',4,1])) 121 3 122 """ 123 if self.affine: 124 return 3 125 else: 126 return 2 127 128 def is_finite(self): 129 """ 130 Returns True if self is finite. 131 132 EXAMPLES: 133 sage: CartanType(['A',4]).is_finite() 134 True 135 sage: CartanType(['A',4,1]).is_finite() 136 False 137 """ 138 if self.affine is not None: 139 return False 140 141 if self.letter in ['A', 'B', 'C', 'D', 'I']: 142 return True 143 144 if self.letter == 'E': 145 return self.n <= 8 146 147 if self.letter == 'F': 148 return self.n <= 4 149 150 if self.letter == 'G': 151 return self.n <= 2 152 153 def is_affine(self): 154 """ 155 Returns True if self is affine. 156 157 EXAMPLES: 158 sage: CartanType(['A', 3]).is_affine() 159 False 160 sage: CartanType(['A', 3, 1]).is_affine() 161 True 162 """ 163 return self.affine is not None 164 158 return None 165 159 166 160 def rank(self): 167 161 """ … … 174 168 sage: CartanType(['I', 8]).rank() 175 169 2 176 170 """ 177 if self.is_affine(): 178 if self.affine == 3 and self.letter == 'D': 179 return self.n-1 180 elif self.affine == 2 and self.letter == 'A': 181 ## FIXME: check in the literature what should be the 182 ## appropriate definition for rank 183 return int(self.n+1)/2 184 else: 185 return self.n 186 else: 187 if self.letter == "I": 188 return 2 189 else: 190 return self.n 171 raise notImplementedError 172 173 def dual(self): 174 """ 175 Returns the dual cartan type, possibly just as a formal dual 176 177 EXAMPLES: 178 sage: CartanType(['A',3]).dual() 179 ['A', 3] 180 sage: CartanType(['D',4]).dual() 181 ['D', 4] 182 sage: CartanType(['E',8]).dual() 183 ['E', 8] 184 sage: CartanType(['B',3]).dual() 185 ['C', 3] 186 sage: CartanType(['C',2]).dual() 187 ['B', 2] 188 """ 189 return root_system.type_dual.CartanType(self) 190 191 def type_string(self): 192 r""" 193 Returns a string suitable for type-specific code dispatch 194 195 EXAMPLES: (TODO!) 196 """ 197 return "type_None" 198 199 def is_reducible(self): 200 """ 201 Report whether the root system is reducible (i.e. not simple), 202 that is whether it can be factored as a product of root 203 systems. 204 205 EXAMPLES: 206 sage: CartanType("A2xB3").is_reducible() 207 True 208 sage: CartanType(['A',2]).is_reducible() 209 False 210 """ 211 return not self.is_irreducible() 212 213 def is_irreducible(self): 214 """ 215 Report whether this Cartan type is irreducible (i.e. simple) 216 217 """ 218 raise NotImplementedError 219 220 def is_finite(self): 221 """ 222 Returns whether this Cartan type is finite. 223 224 EXAMPLES: 225 sage: CartanType(['A',4]).is_finite() 226 True 227 sage: CartanType(['A',4,1]).is_finite() 228 False 229 """ 230 raise NotImplementedError 231 232 def is_affine(self): 233 """ 234 Returns whether self is affine. 235 236 EXAMPLES: 237 sage: CartanType(['A', 3]).is_affine() 238 False 239 sage: CartanType(['A', 3, 1]).is_affine() 240 True 241 """ 242 raise NotImplementedError 243 244 def is_crystalographic(self): 245 """ 246 Returns whether this Cartan type is simple laced 247 248 EXAMPLES: 249 sage: [ [t, t.is_crystalographic() ] for t in CartanType.samples(finite=True) ] 250 [[['A', 1], True], [['A', 5], True], 251 [['B', 5], True], [['C', 5], True], [['D', 5], True], 252 [['E', 6], True], [['E', 7], True], [['E', 8], True], 253 [['F', 4], True], [['G', 2], True], 254 [['I', 5], False], [['H', 3], False], [['H', 4], False]] 255 256 TESTS: 257 sage: all(t.is_crystalographic() for t in CartanType.samples(affine=True)) 258 True 259 """ 260 raise NotImplementedError 261 262 def is_simple_laced(self): 263 """ 264 Returns whether this Cartan type is simple laced 265 266 EXAMPLES: 267 sage: [ [t, t.is_simply_laced() ] for t in CartanType.samples() ] 268 [[['A', 1], True], [['A', 5], True], 269 [['B', 5], False], [['C', 5], False], [['D', 5], True], 270 [['E', 6], True], [['E', 7], True], [['E', 8], True], 271 [['F', 4], False], [['G', 2], False], [['I', 5], False], [['H', 3], False], [['H', 4], False], 272 [['A', 1, 1], False], [['A', 5, 1], True], 273 [['B', 5, 1], False], [['C', 5, 1], False], [['D', 5, 1], True], 274 [['E', 6, 1], True], [['E', 7, 1], True], [['E', 8, 1], True], 275 [['F', 4, 1], False], [['G', 2, 1], False], 276 [['A', 2, 2], False], [['A', 10, 2], False], [['A', 9, 2], False], [['D', 5, 2], False], [['D', 4, 3], False], [['E', 6, 2], False]] 277 """ 278 raise NotImplementedError 191 279 192 280 def index_set(self): 193 281 """ … … 213 301 sage: CartanType(['A',4]).root_system() 214 302 Root system of type ['A', 4] 215 303 """ 216 return root_system.RootSystem(self) 304 return root_system.root_system.RootSystem(self) 305 306 # Maybe we want a separate class for affine 307 308 class CartanType_simple(CartanType_abstract): 309 """ 310 TESTS: 311 sage: ct1 = CartanType(['A',4]) 312 sage: ct2 = CartanType(['A',4]) 313 sage: ct3 = CartanType(['A',5]) 314 sage: ct1 == ct2 315 True 316 sage: ct1 != ct3 317 True 318 """ 319 320 def __hash__(self): 321 """ 322 EXAMPLES: 323 sage: ct = CartanType(['A',2]) 324 sage: hash(ct) #random 325 -5684143898951441983 326 """ 327 return hash(str(self)) 328 329 def __getitem__(self, x): 330 """ 331 EXAMPLES: 332 sage: t = CartanType(['A', 3, 1]) 333 sage: t[0] 334 'A' 335 sage: t[1] 336 3 337 sage: t[2] 338 1 339 sage: t[3] 340 Traceback (most recent call last): 341 ... 342 IndexError: list index out of range 343 """ 344 return self.t[x] 345 346 def is_irreducible(self): 347 return True 348 349 def dynkin_diagram(self): 350 """ 351 Returns the Dynkin diagram associated with self. 352 353 EXAMPLES: 354 sage: CartanType(['A',4]).dynkin_diagram() 355 Dynkin diagram of type ['A', 4] 356 """ 357 return root_system.dynkin_diagram.DynkinDiagram(self) 217 358 218 359 def cartan_matrix(self): 219 360 """ … … 227 368 [ 0 0 -1 2] 228 369 229 370 """ 230 return cartan_matrix(self)371 return root_system.cartan_matrix.cartan_matrix(self) 231 372 232 373 def type(self): 233 374 """ … … 236 377 EXAMPLES: 237 378 sage: CartanType(['A', 4]).type() 238 379 'A' 380 sage: CartanType(['A', 4, 1]).type() 381 'A' 239 382 """ 240 383 return self.letter 384 385 def type_string(self): 386 """ 387 Returns a string suitable for type-specific code dispatch 388 389 EXAMPLES: 390 sage: CartanType(['A', 4]).type_string() 391 'type_A' 392 sage: CartanType(['A', 4, 1]).type_string() 393 'type_A_affine' 394 """ 395 if self.is_affine(): 396 return "type_%s_affine"%self.letter 397 else: 398 return "type_%s"%self.letter 399 400 def dual(self): 401 if self.type() in ["A", "D", "E"]: 402 return self 403 else: 404 return CartanType_abstract.dual(self) 405 406 def is_irreducible(self): 407 """ 408 Report that this Cartan type is irreducible. 409 """ 410 return True 411 412 class CartanType_simple_finite(CartanType_simple): 413 r""" 414 A class for finite simple Cartan types 415 """ 416 417 def __init__(self, t): 418 """ 419 EXAMPLES: 420 sage: ct = CartanType(['A',4]) 421 sage: ct == loads(dumps(ct)) 422 True 423 """ 424 assert(len(t) == 2) 425 assert(t[0] in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']) 426 assert(t[1] in ZZ and t[1] >= 0) 427 if t[0] in ['B', 'C']: 428 assert(t[1] >= 2) 429 if t[0] == 'D': 430 assert(t[1] >= 3) 431 if t[0] == 'E': 432 assert(t[1] <= 8) 433 if t[0] == 'F': 434 assert(t[1] <= 4) 435 if t[0] == 'G': 436 assert(t[1] <= 2) 437 if t[0] == 'H': 438 assert(t[1] <= 4) 439 440 self.t = t 441 self.letter = t[0] 442 self.n = t[1] 443 444 445 def __repr__(self): 446 """ 447 TESTS: 448 sage: ct = CartanType(['A',3]) 449 sage: repr(ct) 450 "['A', 3]" 451 """ 452 return "['%s', %s]"%(self.letter, self.n) 453 454 def __len__(self): 455 """ 456 EXAMPLES: 457 sage: len(CartanType(['A',4])) 458 2 459 """ 460 return 2 461 462 def __cmp__(self, other): 463 if other.__class__ != self.__class__: 464 return cmp(self.__class__, other.__class__) 465 if other.letter != self.letter: 466 return cmp(self.letter, other.letter) 467 return cmp(self.n, other.n) 468 469 def rank(self): 470 if self.letter == "I": 471 return 2 472 else: 473 return self.n 474 def is_finite(self): 475 return True 476 477 def is_affine(self): 478 return False 479 480 def is_crystalographic(self): 481 return self.letter in ["A", "B", "C", "D", "E", "F", "G"] 482 483 def is_simply_laced(self): 484 return self.letter in ["A", "D", "E"] 485 486 def affine(self): 487 """ 488 Returns the corresponding untwisted affine Cartan type 489 490 EXAMPLES: 491 sage: CartanType(['A',3]).affine() 492 ['A', 3, 1] 493 """ 494 return CartanType([self.letter, self.n, 1]) 495 496 def dual(self): 497 if self.type() == "B": 498 return CartanType(["C",self.n]) 499 elif self.type() == "C": 500 return CartanType(["B",self.n]) 501 else: 502 return CartanType_simple.dual(self) 503 504 ########################################################################## 505 class CartanType_simple_affine(CartanType_simple): 506 r""" 507 A class for affine simple Cartan types 508 """ 509 510 def __init__(self, t): 511 """ 512 EXAMPLES: 513 sage: ct = CartanType(['A',4]) 514 sage: ct == loads(dumps(ct)) 515 True 516 """ 517 assert(len(t) == 3) 518 assert(t[0] in ['A', 'B', 'C', 'D', 'E', 'F', 'G']) 519 assert(t[1] in ZZ and t[1] >= 1) 520 assert(t[2] in [1,2,3]) 521 if t[0] in ['B', 'C']: 522 assert(t[1] >= 2) 523 if t[0] == 'D': 524 assert(t[1] >= 4) 525 if t[0] == 'E': 526 assert(t[1] <= 8) 527 if t[0] == 'F': 528 assert(t[1] <= 4) 529 if t[0] == 'G': 530 assert(t[1] <= 2) 531 if t[2] == 3: 532 assert(t[0] == "D") 533 assert(t[1] == 4) 534 if t[2] == 2: 535 assert(t[0] in ['A', 'D', 'E']) 536 if t[0] == 'E': 537 assert(t[1] == 6) 538 539 self.t = t 540 self.letter = t[0] 541 self.n = t[1] 542 self.affine = t[2] 543 544 def __repr__(self): 545 """ 546 TESTS: 547 sage: ct = CartanType(['A',3, 1]) 548 sage: repr(ct) 549 "['A', 3, 1]" 550 """ 551 return "['%s', %s, %s]"%(self.letter, self.n, self.affine) 552 553 def __cmp__(self, other): 554 c = CartanType_simple_finite.cmp(self, other) 555 if c != 0: 556 return c 557 else: 558 return cmp(self.affine, other.affine) 559 560 def __len__(self): 561 """ 562 EXAMPLES: 563 sage: len(CartanType(['A',4,1])) 564 3 565 """ 566 return 3 567 568 def rank(self): 569 if self.affine == 3 and self.letter == 'D': 570 return self.n-1 571 elif self.affine == 2 and self.letter == 'A': 572 ## FIXME: check in the literature what should be the 573 ## appropriate definition for rank 574 return int(self.n+1)/2 575 else: 576 return self.n 577 578 def is_finite(self): 579 return False 580 581 def is_affine(self): 582 return True 583 584 def is_crystalographic(self): 585 return True 586 587 def is_simply_laced(self): 588 if self.affine != 1: 589 return False 590 if self.letter == "A": 591 return self.n > 1 592 return self.letter in ["D", "E"] 593 594 def classical(self): 595 r""" 596 Returns the classical Cartan type associated with self (which should be affine) 597 598 Caveat: only implemented for untwisted 599 600 EXAMPLES: 601 sage: CartanType(['A', 3, 1]).classical() 602 ['A', 3] 603 sage: CartanType(['B', 3, 1]).classical() 604 ['B', 3] 605 """ 606 607 if self.affine == 1: 608 return CartanType([self.letter,self.n]) 609 else: 610 raise notImplementedError -
sage/combinat/root_system/coxeter_matrix.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/coxeter_matrix.py
a b 16 16 # http://www.gnu.org/licenses/ 17 17 #***************************************************************************** 18 18 from cartan_type import CartanType 19 from dynkin_diagram import dynkin_diagram_as_function20 19 from sage.matrix.all import MatrixSpace 21 20 from sage.rings.all import ZZ 22 21 … … 33 32 [2 3 1 3] 34 33 [2 2 3 1] 35 34 """ 36 ct = CartanType(t) 37 f = dynkin_diagram_as_function(ct) 35 a = CartanType(t).dynkin_diagram() 36 scalarproducts_to_order = { 0: 2, 1: 3, 2: 4, 3: 7 37 # 4 should be infinity 38 } 38 39 39 if ct.letter == "G": 40 coxeter = lambda i,j: 1 if i == j else max(f(j,i), f(i,j))+4 41 else: 42 coxeter = lambda i,j: 1 if i == j else max(f(j,i), f(i,j))+2 43 44 return coxeter 40 return lambda i,j: 1 if i == j else scalarproducts_to_order[a[i,j]*a[j,i]] 45 41 46 42 47 43 def coxeter_matrix(t): -
sage/combinat/root_system/dynkin_diagram.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/dynkin_diagram.py
a b 16 16 # http://www.gnu.org/licenses/ 17 17 #***************************************************************************** 18 18 from sage.graphs.all import DiGraph 19 from cartan_type import CartanType, CartanType_abstract 20 from cartan_matrix import cartan_matrix 21 import cartan_type 22 from root_system import RootSystem 19 23 24 def DynkinDiagram(*args): 25 """ 26 INPUT: 27 ct -- A Cartan Type 28 Returns a Dynkin diagram for type ct. 29 30 The edge multiplicities are encoded as edge labels. This uses the 31 convention in Kac / Fulton Harris Representation theory wikipedia 32 http://en.wikipedia.org/wiki/Dynkin_diagram, that is for i != j: 33 34 j -k-> i <==> a_ij = -k <==> -scalar(coroot[i], root[j]) = k 35 <==> multiple arrows point from the longer root to the shorter one 36 37 TODO: say something about the node labelling conventions. 38 39 EXAMPLES: 40 sage: DynkinDiagram(['A', 4]) 41 Dynkin diagram of type ['A', 4] 42 sage: DynkinDiagram(['A',1],['A',1]) 43 Dynkin diagram of type A1xA1 44 sage: R = RootSystem("A2xB2xF4") 45 sage: DynkinDiagram(R) 46 Dynkin diagram of type A2xB2xF4 47 """ 48 if len(args) == 1: 49 t = args[0] 50 else: 51 t = CartanType(args) 52 53 if isinstance(t, RootSystem): 54 ct = t.cartan_type() 55 else: 56 ct = CartanType(t) 57 if ct.is_reducible(): 58 function = globals()["type_reducible"] 59 else: 60 letter = ct[0].lower() 61 affine = "" 62 ct = CartanType(ct) 63 if ct.is_affine(): 64 affine = "_affine" 65 function = globals()["type_"+letter+affine] 66 try: 67 return function(ct) 68 except KeyError: 69 raise TypeError, "Dynkin diagram data not yet hardcoded for type %s"%t 70 71 def dynkin_diagram(t): 72 """ 73 Deprecated; please use DynkinDiagram 74 """ 75 return DynkinDiagram(t) 76 77 78 class DynkinDiagram_class(DiGraph, CartanType_abstract): 79 def __init__(self, t): 80 DiGraph.__init__(self) 81 self._cartan_type = t 82 83 def __repr__(self): 84 """ 85 EXAMPLES: 86 sage: DynkinDiagram(['A',3]) 87 Dynkin diagram of type ['A', 3] 88 """ 89 if self._cartan_type is None: 90 return "Dynkin diagram of rank %s"%self.rank() 91 else: 92 return "Dynkin diagram of type %s"%self._cartan_type 93 94 def add_edge(self, i, j, label=1): 95 DiGraph.add_edge(self, i, j, label) 96 if not self.has_edge(j,i): 97 self.add_edge(j,i,1) 98 99 def index_set(self): 100 """ 101 EXAMPLES: 102 sage: DynkinDiagram(['C',3]).index_set() 103 [1, 2, 3] 104 sage: DynkinDiagram("A2","B2","F4").index_set() 105 [1, 2, 3, 4, 5, 6, 7, 8] 106 """ 107 return self.vertices() 108 109 def cartan_type(self): 110 """ 111 EXAMPLES: 112 sage: DynkinDiagram("A2","B2","F4").cartan_type() 113 A2xB2xF4 114 """ 115 return self._cartan_type 116 117 def rank(self): 118 r""" 119 returns the index set for this Dynkin diagram 120 121 EXAMPLES: 122 """ 123 return self.num_verts() 124 125 def dynkin_diagram(self): 126 return self 127 128 def cartan_matrix(self): 129 r""" 130 returns the Cartan matrix for this Dynkin diagram 131 132 EXAMPLES: 133 sage: DynkinDiagram(['C',3]).cartan_matrix() 134 [ 2 -1 0] 135 [-1 2 -2] 136 [ 0 -1 2] 137 """ 138 return cartan_matrix(self) 139 140 def dual(self): 141 r""" 142 Returns the dual Dynkin diagram, obtained by reversing all edges. 143 144 EXAMPLES: 145 sage: D = DynkinDiagram(['C',3]) 146 sage: D.edges() 147 [(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)] 148 sage: D.dual() 149 Dynkin diagram of type ['B', 3] 150 sage: D.dual().edges() 151 [(1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1)] 152 sage: D.dual() == DynkinDiagram(['B',3]) 153 True 154 155 TESTS: 156 sage: D = DynkinDiagram(['A',0]); D 157 Dynkin diagram of type ['A', 0] 158 sage: D.edges() 159 [] 160 sage: D.dual() 161 Dynkin diagram of type ['A', 0] 162 sage: D.dual().edges() 163 [] 164 sage: D = DynkinDiagram(['A',1]) 165 sage: D.edges() 166 [] 167 sage: D.dual() 168 Dynkin diagram of type ['A', 1] 169 sage: D.dual().edges() 170 [] 171 172 """ 173 result = DynkinDiagram_class(None) 174 result.add_vertices(self.vertices()) 175 for source, target, label in self.edges(): 176 result.add_edge(target, source, label) 177 result._cartan_type = self._cartan_type.dual() if not self._cartan_type is None else None 178 return result 179 180 def __getitem__(self, i): 181 """ 182 With a tuple (i,j) as argument, returns the scalar product $\langle 183 \alpha^\vee_i, \alpha_j\rangle$. 184 185 Otherwise, behaves as the usual DiGraph.__getitem__ 186 187 EXAMPLES: 188 We use the $C_4$ dynkin diagram as a cartan matrix: 189 sage: g = DynkinDiagram(['C',4]) 190 sage: matrix([[g[i,j] for j in range(1,5)] for i in range(1,5)]) 191 [ 2 -1 0 0] 192 [-1 2 -1 0] 193 [ 0 -1 2 -2] 194 [ 0 0 -1 2] 195 196 The neighbors of a node can still be obtained in the usual way: 197 sage: [g[i] for i in range(1,5)] 198 [[2], [1, 3], [2, 4], [3]] 199 """ 200 if not isinstance(i, tuple): 201 return DiGraph.__getitem__(self,i) 202 [i,j] = i 203 if i == j: 204 return 2 205 elif self.has_edge(j, i): 206 return -self.edge_label(j, i) 207 else: 208 return 0 209 210 def column(self, j): 211 """ 212 Returns the $j$-th column $(a_{i,j})_i$ of the Cartan matrix 213 corresponding to this Dynkin diagram, as a container (or iterator) 214 of tuples (i, a_{i,j}) 215 216 EXAMPLES: 217 sage: g = DynkinDiagram(["B",4]) 218 sage: [ (i,a) for (i,a) in g.column(3) ] 219 [(3, 2), (2, -1), (4, -2)] 220 221 Caveat: broken in sage < 3.0.3 222 """ 223 return [(j,2)] + [(i,-m) for (j1, i, m) in self.outgoing_edges(j)] 224 225 def row(self, i): 226 """ 227 Returns the $i$-th row $(a_{i,j})_j$ of the Cartan matrix 228 corresponding to this Dynkin diagram, as a container (or iterator) 229 of tuples (j, a_{i,j}) 230 231 EXAMPLES: 232 sage: g = DynkinDiagram(["C",4]) 233 sage: [ (i,a) for (i,a) in g.row(3) ] 234 [(3, 2), (2, -1), (4, -2)] 235 """ 236 return [(i,2)] + [(j,-m) for (j, i1, m) in self.incoming_edges(i)] 237 20 238 def precheck(t, letter=None, length=None, affine=None, n_ge=None, n=None): 21 239 """ 22 240 EXAMPLES: … … 52 270 if len(t) != length: 53 271 raise ValueError, "len(t) must be = %s"%length 54 272 55 56 273 if affine is not None: 57 274 try: 58 275 if t[2] != affine: … … 68 285 if t[1] != n: 69 286 raise ValueError, "t[1] must be = %s"%n 70 287 288 ############################################################################## 289 # Everything below is type by type hardcoded data. It probably should be moved 290 # into the type_... files 291 ############################################################################## 292 293 71 294 def type_a(t): 72 295 """ 73 296 Returns the graph corresponding to the Dynkin diagram … … 76 299 EXAMPLES: 77 300 sage: from sage.combinat.root_system.dynkin_diagram import type_a 78 301 sage: ct = CartanType(['A',3]) 79 sage: a = type_a(ct); a80 Multi-digraph on 3 vertices302 sage: a = type_a(ct); a 303 Dynkin diagram of type ['A', 3] 81 304 sage: e = a.edges(); e.sort(); e 82 [(1, 2, None), (2, 1, None), (2, 3, None), (3, 2, None)]305 [(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 1)] 83 306 307 TEST: 308 sage: a = DynkinDiagram(['A',1]) 309 sage: a 310 Dynkin diagram of type ['A', 1] 311 sage: a.vertices(), a.edges() 312 ([1], []) 84 313 """ 85 314 precheck(t, letter="A", length=2) 86 315 n = t[1] 87 g = DiGraph(multiedges=True) 316 g = DynkinDiagram_class(t) 317 g.add_vertices(t.index_set()) 88 318 for i in range(1, n): 89 319 g.add_edge(i, i+1) 90 g.add_edge(i+1, i)91 92 320 return g 93 321 94 322 def type_a_affine(t): 95 323 """ 96 Returns the DiGraph corresponding to the Dynkin diagram 97 of affine type A. 324 Returns the extended Dynkin diagram for affine type A. 98 325 99 326 EXAMPLES: 100 327 sage: from sage.combinat.root_system.dynkin_diagram import type_a_affine 101 328 sage: ct = CartanType(['A',3,1]) 102 329 sage: a = type_a_affine(ct); a 103 Multi-digraph on 4 vertices330 Dynkin diagram of type ['A', 3, 1] 104 331 sage: e = a.edges(); e.sort(); e 105 [(0, 1, None),106 (0, 3, None),107 (1, 0, None),108 (1, 2, None),109 (2, 1, None),110 (2, 3, None),111 (3, 0, None),112 (3, 2, None)]332 [(0, 1, 1), 333 (0, 3, 1), 334 (1, 0, 1), 335 (1, 2, 1), 336 (2, 1, 1), 337 (2, 3, 1), 338 (3, 0, 1), 339 (3, 2, 1)] 113 340 """ 114 341 precheck(t, letter="A", length=3, affine=1) 115 342 n = t[1] 116 g = type_a(['A', n]) 117 343 g = DynkinDiagram_class(t) 344 g.add_vertices(t.index_set()) 345 for i in range(1, n): 346 g.add_edge(i, i+1) 118 347 g.add_edge(0, 1) 119 g.add_edge(1, 0)120 348 g.add_edge(0, n) 121 g.add_edge(n, 0)122 349 123 350 return g 124 351 125 352 def type_b(t): 126 353 """ 127 Returns the DiGraph corresponding to the Dynkin diagram 128 of type B. 354 Returns a Dynkin diagram for type B. 129 355 130 356 EXAMPLES: 131 sage: from sage.combinat.root_system.dynkin_diagram import type_b 132 sage: ct = CartanType(['B',3]) 133 sage: b = type_b(ct);b 134 Multi-digraph on 3 vertices 135 sage: e = b.edges(); e.sort(); e 136 [(1, 2, None), (2, 1, None), (2, 3, None), (3, 2, None), (3, 2, None)] 137 357 sage: from sage.combinat.root_system.dynkin_diagram import type_b 358 sage: ct = CartanType(['B',3]) 359 sage: b = type_b(ct);b 360 Dynkin diagram of type ['B', 3] 361 sage: e = b.edges(); e.sort(); e 362 [(1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1)] 138 363 139 364 """ 140 365 precheck(t, letter='B', length=2, n_ge=2) 141 366 n = t[1] 142 g = type_a(['A', n]) 143 g.add_edge(n, n-1) 367 g = DynkinDiagram_class(t) 368 g.add_vertices(t.index_set()) 369 for i in range(1, n): 370 g.add_edge(i, i+1) 371 g.set_edge_label(n-1, n, 2) 144 372 return g 373 374 def type_b_affine(t): 375 """ 376 Returns the extended Dynkin diagram for affine type B. 377 378 EXAMPLES: 379 sage: DynkinDiagram(['B',3,1]).edges() 380 [(0, 2, 1), (1, 2, 1), (2, 0, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1)] 145 381 382 """ 383 precheck(t, letter='B', length=3, affine=1) 384 n = t[1] 385 g = DynkinDiagram_class(t) 386 g.add_vertices(t.index_set()) 387 for i in range(1, n): 388 g.add_edge(i, i+1) 389 g.set_edge_label(n-1, n, 2) 390 g.add_edge(0,2) 391 return g 146 392 147 393 def type_c(t): 148 394 """ 149 Returns the DiGraph corresponding to the Dynkin diagram 150 of type C. 395 Returns a Dynkin diagram for type C. 151 396 152 397 EXAMPLES: 153 398 sage: from sage.combinat.root_system.dynkin_diagram import type_c 154 399 sage: ct = CartanType(['C',3]) 155 sage: c = type_c(ct); c156 Multi-digraph on 3 vertices400 sage: c = type_c(ct); c 401 Dynkin diagram of type ['C', 3] 157 402 sage: e = c.edges(); e.sort(); e 158 [(1, 2, None), (2, 1, None), (2, 3, None), (2, 3, None), (3, 2, None)]403 [(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)] 159 404 160 405 """ 161 406 precheck(t, letter='C', length=2, n_ge=2) 162 407 n = t[1] 163 g = type_a(['A', n]) 164 g.add_edge(n-1,n) 408 g = DynkinDiagram_class(t) 409 g.add_vertices(t.index_set()) 410 for i in range(1, n): 411 g.add_edge(i, i+1) 412 g.set_edge_label(n,n-1,2) 165 413 return g 166 414 167 415 def type_c_affine(t): 168 416 """ 169 Returns the DiGraph corresponding to the Dynkin diagram 170 of affine type C. 417 Returns the extended Dynkin diagram for affine type C. 171 418 172 419 EXAMPLES: 173 420 sage: from sage.combinat.root_system.dynkin_diagram import type_c_affine 174 421 sage: ct = CartanType(['C',3,1]) 175 422 sage: c = type_c_affine(ct);c 176 Multi-digraph on 4 vertices423 Dynkin diagram of type ['C', 3, 1] 177 424 sage: e = c.edges(); e.sort(); e 178 [(0, 1, None), 179 (0, 1, None), 180 (1, 0, None), 181 (1, 2, None), 182 (2, 1, None), 183 (2, 3, None), 184 (2, 3, None), 185 (3, 2, None)] 425 [(0, 1, 2), (1, 0, 1), (1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)] 186 426 187 427 """ 188 428 precheck(t, letter='C', length=3, affine=1) 189 429 n = t[1] 190 g = type_c(['C', n]) 191 g.add_edge(0,1) 192 g.add_edge(0,1) 193 g.add_edge(1,0) 430 g = DynkinDiagram_class(t) 431 g.add_vertices(t.index_set()) 432 for i in range(1, n): 433 g.add_edge(i, i+1) 434 g.set_edge_label(n,n-1,2) 435 g.add_edge(0,1,1) 436 g.add_edge(0,1,2) 194 437 return g 195 438 196 439 def type_d(t): 197 440 """ 198 Returns the DiGraph corresponding to the Dynkin diagram 199 of type D. 441 Returns a Dynkin diagram for type D. 200 442 201 443 EXAMPLES: 202 444 sage: from sage.combinat.root_system.dynkin_diagram import type_d 203 sage: ct = CartanType(['D', 3])445 sage: ct = CartanType(['D',4]) 204 446 sage: d = type_d(ct);d 205 Multi-digraph on 3 vertices447 Dynkin diagram of type ['D', 4] 206 448 sage: e = d.edges(); e.sort(); e 207 [(1, 2, None), (1, 3, None), (2, 1, None), (3, 1, None)]449 [(1, 2, 1), (2, 1, 1), (2, 3, 1), (2, 4, 1), (3, 2, 1), (4, 2, 1)] 208 450 209 451 """ 210 452 precheck(t, letter="D", length=2, n_ge=3) 211 453 n = t[1] 212 g = type_a(['A', n-1]) 454 455 g = DynkinDiagram_class(t) 456 g.add_vertices(t.index_set()) 457 for i in range(1, n-1): 458 g.add_edge(i, i+1) 213 459 g.add_edge(n-2,n) 214 g.add_edge(n, n-2)215 460 return g 216 461 217 462 def type_d_affine(t): 218 463 """ 219 Returns the DiGraph corresponding to the Dynkin diagram 220 of type D. 464 Returns the extended Dynkin diagram for affine type D. 221 465 222 466 EXAMPLES: 223 sage: from sage.combinat.root_system.dynkin_diagram import type_d_affine224 sage: ct = CartanType(['D',3,1])225 sage: d = type_d_affine(ct);d226 Multi-digraph on 4 vertices227 sage: e = d.edges(); e.sort(); e228 [(0, 2, None),229 (1, 2, None),230 (1, 3, None),231 (2, 0, None),232 (2, 1, None),233 (3, 1, None)]467 sage: DynkinDiagram(CartanType(['D', 4, 1])) 468 Dynkin diagram of type ['D', 4, 1] 469 sage: DynkinDiagram(CartanType(['D', 4, 1])).edges() 470 [(0, 2, 1), 471 (1, 2, 1), 472 (2, 0, 1), 473 (2, 1, 1), 474 (2, 3, 1), 475 (2, 4, 1), 476 (3, 2, 1), 477 (4, 2, 1)] 234 478 235 479 """ 236 480 precheck(t, letter="D", length=3, affine=1) 237 481 n = t[1] 238 g = type_d(['D', n]) 482 g = DynkinDiagram_class(t) 483 g.add_vertices(t.index_set()) 484 for i in range(1, n-1): 485 g.add_edge(i, i+1) 486 g.add_edge(n-2,n) 239 487 g.add_edge(0,2) 240 g.add_edge(2,0)241 488 return g 242 489 243 490 def type_e(t): 244 491 """ 245 Returns the DiGraph corresponding to the Dynkin diagram 246 of type E. 492 Returns a Dynkin diagram for type E. 247 493 248 494 EXAMPLES: 249 495 sage: from sage.combinat.root_system.dynkin_diagram import type_e 250 496 sage: ct = CartanType(['E',6]) 251 497 sage: e = type_e(ct);e 252 Multi-digraph on 6 vertices498 Dynkin diagram of type ['E', 6] 253 499 sage: edges = e.edges(); edges.sort(); edges 254 [(1, 3, None), 255 (2, 4, None), 256 (3, 1, None), 257 (3, 4, None), 258 (4, 2, None), 259 (4, 3, None), 260 (4, 5, None), 261 (5, 4, None), 262 (5, 6, None), 263 (6, 5, None)] 500 [(1, 3, 1), (2, 4, 1), (3, 1, 1), (3, 4, 1), (4, 2, 1), (4, 3, 1), (4, 5, 1), (5, 4, 1), (5, 6, 1), (6, 5, 1)] 264 501 265 502 """ 266 503 precheck(t, letter="E", length=2, n_ge=3) 267 504 n = t[1] 268 g = D iGraph(multiedges=True)505 g = DynkinDiagram_class(t) 269 506 g.add_edge(1,3) 270 g.add_edge(3,1)271 507 g.add_edge(2,4) 272 g.add_edge(4,2)273 508 for i in range(3,n): 274 509 g.add_edge(i, i+1) 275 g.add_edge(i+1, i) 510 return g 511 512 def type_e_affine(t): 513 """ 514 Returns the extended Dynkin diagram for affine type E. 515 516 EXAMPLES: 517 sage: from sage.combinat.root_system.dynkin_diagram import type_e_affine 518 sage: e = DynkinDiagram(['E', 6, 1]) 519 sage: edges = e.edges(); edges.sort(); edges 520 [(0, 2, 1), 521 (1, 3, 1), 522 (2, 0, 1), 523 (2, 4, 1), 524 (3, 1, 1), 525 (3, 4, 1), 526 (4, 2, 1), 527 (4, 3, 1), 528 (4, 5, 1), 529 (5, 4, 1), 530 (5, 6, 1), 531 (6, 5, 1)] 532 533 """ 534 precheck(t, letter="E", length=3, affine=1) 535 n = t[1] 536 g = DynkinDiagram_class(t) 537 g.add_edge(1,3) 538 g.add_edge(2,4) 539 for i in range(3,n): 540 g.add_edge(i, i+1) 541 if n == 6: 542 g.add_edge(0, 2) 543 elif n == 7: 544 g.add_edge(0, 1) 545 elif n == 8: 546 g.add_edge(0, 8) 547 else: 548 raise ValueError, "Invalid Cartan Type for Type E affine" 276 549 return g 277 550 278 551 def type_f(t): 279 552 """ 280 Returns the DiGraph corresponding to the Dynkin diagram 281 of type F. 553 Returns a Dynkin diagram for type F. 282 554 283 555 EXAMPLES: 284 556 sage: from sage.combinat.root_system.dynkin_diagram import type_f 285 557 sage: ct = CartanType(['F',4]) 286 558 sage: f = type_f(ct);f 287 Multi-digraph on 4 vertices559 Dynkin diagram of type ['F', 4] 288 560 sage: e = f.edges(); e.sort(); e 289 [(1, 2, None), 290 (2, 1, None), 291 (2, 3, None), 292 (3, 2, None), 293 (3, 2, None), 294 (3, 4, None), 295 (4, 3, None)] 561 [(1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1), (3, 4, 1), (4, 3, 1)] 296 562 297 563 """ 298 564 precheck(t, letter='F', length=2, n=4) 299 g = D iGraph(multiedges=True)565 g = DynkinDiagram_class(t) 300 566 for i in range(1, 4): 301 567 g.add_edge(i, i+1) 302 g.add_edge(i+1, i) 303 g.add_edge(3,2) 568 g.set_edge_label(2,3,2) 569 return g 570 571 def type_f_affine(t): 572 """ 573 Returns the extended Dynkin diagram for affine type F. 574 575 EXAMPLES: 576 sage: f = DynkinDiagram(['F', 4, 1]) 577 sage: edges = f.edges(); edges.sort(); edges 578 [(0, 1, 1), (1, 0, 1), (1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1), (3, 4, 1), (4, 3, 1)] 579 580 """ 581 precheck(t, letter="F", length=3, affine=1) 582 g = DynkinDiagram_class(t) 583 for i in range(1, 4): 584 g.add_edge(i, i+1) 585 g.set_edge_label(2,3,2) 586 g.add_edge(0, 1) 304 587 return g 305 588 306 589 def type_g(t): 307 590 """ 308 Returns the DiGraph corresponding to the Dynkin diagram 309 of type G. 591 Returns a Dynkin diagram for type G. 310 592 311 593 EXAMPLES: 312 594 sage: from sage.combinat.root_system.dynkin_diagram import type_g 313 595 sage: ct = CartanType(['G',2]) 314 596 sage: g = type_g(ct);g 315 Multi-digraph on 2 vertices597 Dynkin diagram of type ['G', 2] 316 598 sage: e = g.edges(); e.sort(); e 317 [(1, 2, None), (1, 2, None), (1, 2, None), (2, 1, None)]599 [(1, 2, 1), (2, 1, 3)] 318 600 319 601 """ 320 602 precheck(t, letter='G', length=2, n=2) 321 g = DiGraph(multiedges=True) 322 for _ in range(3): 323 g.add_edge(1,2) 324 g.add_edge(2,1) 603 g = DynkinDiagram_class(t) 604 g.add_edge(1,2) 605 g.set_edge_label(2,1,3) 325 606 return g 326 607 327 def dynkin_diagram(t):608 def type_g_affine(t): 328 609 """ 329 Returns a DiGraph corresponding to the Dynkin diagram of 330 type t. 610 Returns the extended Dynkin diagram for type G. 331 611 332 612 EXAMPLES: 333 sage: from sage.combinat.root_system.dynkin_diagram import dynkin_diagram 334 sage: dynkin_diagram(['A', 4]) 335 Multi-digraph on 4 vertices 613 sage: from sage.combinat.root_system.dynkin_diagram import type_g_affine 614 sage: ct = CartanType(['G',2,1]) 615 sage: g = type_g_affine(ct); g 616 Dynkin diagram of type ['G', 2, 1] 617 sage: e = g.edges(); e.sort(); e 618 [(0, 2, 1), (1, 2, 1), (2, 0, 1), (2, 1, 3)] 336 619 337 620 """ 338 import cartan_type 339 f = "type_" 340 letter = t[0].lower() 341 affine = "" 342 ct = cartan_type.CartanType(t) 343 if ct.is_affine(): 344 affine = "_affine" 621 precheck(t, letter="G", length=3, affine=1) 622 g = DynkinDiagram_class(t) 623 g.add_edge(1, 2) 624 g.set_edge_label(2,1,3) 625 g.add_edge(0, 2) 626 return g 345 627 346 function = globals()[f+letter+affine] 347 try: 348 return function(t) 349 except KeyError: 350 raise TypeError, "Dynkin diagram data not yet hardcoded for type %s"%t 628 def type_reducible(t): 629 """ 630 Returns a Dynkin diagram for type reducible. 631 EXAMPLES: 632 sage: t = CartanType("A2xB2xF4") 633 sage: dd = DynkinDiagram(t); dd 634 Dynkin diagram of type A2xB2xF4 635 sage: dd.edges() 636 [(1, 2, 1), (2, 1, 1), (3, 4, 2), (4, 3, 1), (5, 6, 1), (6, 5, 1), (6, 7, 2), (7, 6, 1), (7, 8, 1), (8, 7, 1)] 351 637 352 353 354 def dynkin_diagram_as_function(t):355 638 """ 356 Returns a function corresponding to the Dynkin diagram of 357 type t. 358 359 EXAMPLES: 360 sage: from sage.combinat.root_system.dynkin_diagram import dynkin_diagram_as_function 361 sage: f = dynkin_diagram_as_function(['A',4]) 362 sage: f(1,1) 363 -2 364 """ 365 d = dynkin_diagram(t) 366 f = lambda i,j: -2 if i == j else ( len(filter(lambda x: x[1] == j, d.outgoing_edges(i))) if d.has_edge(i,j) else 0) 367 368 return f 639 g = DynkinDiagram_class(t) 640 g.add_vertices(t.index_set()) 641 for i in range(len(t._types)): 642 for [e1, e2, l] in DynkinDiagram(t._types[i]).edges(): 643 shift = t._rshifts[i] 644 g.add_edge(e1+shift, e2+shift, label=l) 645 return g 646 647 -
new file sage/combinat/root_system/root_lattice_realization.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/root_lattice_realization.py
- + 1 #***************************************************************************** 2 # Copyright (C) 2007 Nicolas M. Thiery <nthiery at users.sf.net> 3 # 4 # Distributed under the terms of the GNU General Public License (GPL) 5 # 6 # This code is distributed in the hope that it will be useful, 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 # General Public License for more details. 10 # 11 # The full text of the GPL is available at: 12 # 13 # http://www.gnu.org/licenses/ 14 #***************************************************************************** 15 from sage.combinat.family import Family 16 17 class RootLatticeRealization: 18 19 def index_set(self): 20 return self.root_system.index_set() 21 22 def dynkin_diagram(self): 23 return self.root_system.dynkin_diagram() 24 25 ########################################################################## 26 # checks 27 ########################################################################## 28 29 def check(self): 30 alpha = self.simple_roots() 31 alphacheck = self.simple_coroots() 32 dynkin_diagram = self.dynkin_diagram() 33 for i in self.index_set(): 34 for j in self.index_set(): 35 assert(alpha[j].scalar(alphacheck[i]) == dynkin_diagram[i,j]) 36 37 ########################################################################## 38 # highest root 39 ########################################################################## 40 41 def highest_root(self): 42 """ 43 Returns the highest root (for an irreducible finite root system) 44 45 EXAMPLES: 46 sage: RootSystem(['A',4]).ambient_space().highest_root() 47 (1, 0, 0, 0, -1) 48 49 sage: RootSystem(['E',6]).weight_space().highest_root() 50 Lambda[2] 51 52 """ 53 assert(self.root_system.is_finite()) 54 assert(self.root_system.is_irreducible()) 55 return self.a_long_simple_root().to_positive_chamber() 56 57 def a_long_simple_root(self): 58 """ 59 Returns a long simple root, corresponding to the highest outgoing edge 60 in the Dynkin diagram. 61 62 Caveat: This depends on a direct identification between dynkin diagram 63 nodes and the simple roots, which is not yet valid in the ambient space 64 65 Caveat: this may be break in affine type A_2n^(2) 66 67 Caveat: meaningful/broken for non irreducible? 68 69 TODO: implement DynkinDiagram.vertices_by_length as in 70 MuPAD-Combinat, and use it here 71 72 TESTS: 73 sage: X=RootSystem(['A',1]).weight_space() 74 sage: X.a_long_simple_root() 75 2*Lambda[1] 76 sage: X=RootSystem(['A',5]).weight_space() 77 sage: X.a_long_simple_root() 78 2*Lambda[1] - Lambda[2] 79 """ 80 if self.dynkin_diagram().rank() == 1: 81 return self.simple_roots()[self.index_set()[0]] 82 longest=self.dynkin_diagram().outgoing_edges()[0] 83 for j in self.dynkin_diagram().outgoing_edges(): 84 if j[2]>longest[2]: 85 longest=j 86 return self.simple_roots()[longest[0]] 87 88 89 ########################################################################## 90 # simple roots 91 ########################################################################## 92 93 def simple_root(self, i): 94 """ 95 Returns the $i$-th simple root 96 """ 97 raise NotImplementedError 98 99 def simple_roots(self): 100 """ 101 Returns the family $(\alpha_i)_{i\in I}$ of the simple roots 102 """ 103 if not hasattr(self,"_simple_roots"): 104 self._simple_roots = Family(self.index_set(), self.simple_root, name = "alpha") 105 return self._simple_roots 106 107 def alpha(self): 108 """ 109 Returns the family $(\alpha_i)_{i\in I}$ of the simple roots, 110 with the extra feature that, for simple irreducible root 111 systems, $\alpha_0$ yields the opposite of the highest root. 112 """ 113 if self.root_system.is_finite() and self.root_system.is_irreducible(): 114 return Family(self.index_set(), self.simple_root, \ 115 hidden_keys = [0], hidden_function = lambda i: self.highest_root()) 116 else: 117 return self.simple_roots() 118 119 ########################################################################## 120 # roots 121 ########################################################################## 122 123 def roots(self): 124 """ 125 Returns the roots of self. 126 127 EXAMPLES: 128 sage: RootSystem(['A',2]).ambient_lattice().roots() 129 [(1, -1, 0), (1, 0, -1), (0, 1, -1), (-1, 1, 0), (-1, 0, 1), (0, -1, 1)] 130 """ 131 return self.positive_roots() + self.negative_roots() 132 133 ########################################################################## 134 # coroots 135 ########################################################################## 136 137 def coroot_lattice(self): 138 return self.root_system.coroot_lattice() 139 140 def simple_coroot(self, i): 141 return self.coroot_lattice().simple_root(i) 142 143 def simple_coroots(self): 144 """ 145 Returns the family $(\alpha^\vee_i)_{i\in I}$ of the simple coroots 146 """ 147 if not hasattr(self,"cache_simple_coroots"): 148 self.cache_simple_coroots = Family(self.index_set(), self.simple_coroot, name = "alphacheck") 149 return self.cache_simple_coroots 150 151 def alphacheck(self): 152 # TODO: remember 153 """ 154 Returns the family $(\alpha^\vee_i)_{i\in I}$ of the simple 155 coroots, with the extra feature that for simple irreducible 156 root systems, $\alpha^\vee_0$ yields the coroot associated to 157 the opposite of the highest root (caveat: this is usually not 158 the highest coroot!) 159 """ 160 if self.root_system.is_finite() and self.root_system.is_irreducible(): 161 return Family(self.index_set(), self.simple_coroot, \ 162 hidden_keys = [0], hidden_function = lambda i: self.cohighest_root()) 163 else: 164 return self.simple_roots() 165 166 def cohighest_root(self): 167 # TODO: remember AND DOCUMENT 168 return self.highest_root.associated_coroot() 169 170 def associated_coroot(self, root): 171 """ 172 Returns the coroot associated to this root 173 EXAMPLES: 174 TODO 175 """ 176 assert(root in self.roots() != False) 177 raise NotImplementedError() 178 179 ########################################################################## 180 # reflections 181 ########################################################################## 182 183 def reflection(self, root, coroot=None): 184 """ 185 Returns the reflection along the root, and across the 186 hyperplane define by coroot, as a function from 187 self to self. 188 189 EXAMPLES: 190 sage: space = RootSystem(['A',2]).weight_lattice() 191 sage: x=space.simple_roots()[1] 192 sage: y=space.simple_coroots()[1] 193 sage: s = space.reflection(x,y) 194 sage: x 195 2*Lambda[1] - Lambda[2] 196 sage: s(x) 197 -2*Lambda[1] + Lambda[2] 198 sage: s(-x) 199 2*Lambda[1] - Lambda[2] 200 """ 201 if coroot is None: 202 coroot = root.associated_coroot() 203 return lambda v: v - v.scalar(coroot) * root 204 205 def simple_reflection(self, i): 206 # TODO: remember 207 """ 208 Returns the $i^{th}$ simple reflection, as a function from 209 self to self. 210 211 INPUT: 212 i -- i is in self's index set 213 214 EXAMPLES: 215 sage: space = RootSystem(['A',2]).ambient_lattice() 216 sage: s = space.simple_reflection(1) 217 sage: x = space.simple_roots()[1] 218 sage: x 219 (1, -1, 0) 220 sage: s(x) 221 (-1, 1, 0) 222 """ 223 return self.reflection(self.simple_root(i), self.simple_coroot(i)) 224 225 def simple_reflections(self): 226 # TODO: cache 227 """ 228 Returns the family $(s_i)_{i\in I}$ of the simple reflections 229 of this root system 230 231 EXAMPLES: 232 TODO 233 """ 234 return self.alpha().zip(self.reflection, self.alphacheck(), name = "s") 235 236 s = simple_reflections 237 238 ########################################################################## 239 # projections 240 ########################################################################## 241 242 def projection(self, root, coroot=None, to_negative=True): 243 """ 244 Returns the projection along the root, and across the 245 hyperplane define by coroot, as a function $\pi$ from self to 246 self. $\pi$ is a half-linear map which stabilizes the negative 247 half space, and acts by reflection on the positive half space. 248 249 If to_negative is False, then this project onto the positive 250 half space instead. 251 252 EXAMPLES: 253 sage: space = RootSystem(['A',2]).weight_lattice() 254 sage: x=space.simple_roots()[1] 255 sage: y=space.simple_coroots()[1] 256 sage: pi = space.projection(x,y) 257 sage: x 258 2*Lambda[1] - Lambda[2] 259 sage: pi(x) 260 -2*Lambda[1] + Lambda[2] 261 sage: pi(-x) 262 -2*Lambda[1] + Lambda[2] 263 sage: pi = space.projection(x,y,False) 264 sage: pi(-x) 265 2*Lambda[1] - Lambda[2] 266 """ 267 if coroot is None: 268 coroot = root.associated_coroot() 269 def projection(v): 270 if ((v.scalar(coroot) > 0) == to_negative): 271 return v - v.scalar(coroot) * root 272 else: 273 return v 274 return projection 275 276 def simple_projection(self, i, to_negative=True): 277 # TODO: remember 278 """ 279 Returns the projection along the $i^{th}$ simple root, and across the 280 hyperplane define by the $i^{th}$ simple coroot, as a function from 281 self to self. 282 283 INPUT: 284 i -- i is in self's index set 285 286 EXAMPLES: 287 sage: space = RootSystem(['A',2]).weight_lattice() 288 sage: x = space.simple_roots()[1] 289 sage: pi = space.simple_projection(1) 290 sage: x 291 2*Lambda[1] - Lambda[2] 292 sage: pi(x) 293 -2*Lambda[1] + Lambda[2] 294 sage: pi(-x) 295 -2*Lambda[1] + Lambda[2] 296 sage: pi = space.simple_projection(1,False) 297 sage: pi(-x) 298 2*Lambda[1] - Lambda[2] 299 """ 300 return self.projection(self.simple_root(i), self.simple_coroot(i), to_negative) 301 302 def simple_projections(self): 303 # TODO: cache 304 """ 305 Returns the family $(s_i)_{i\in I}$ of the simple projections 306 of this root system 307 308 EXAMPLES: 309 TODO 310 """ 311 return self.alpha().zip(self.projection, self.alphacheck(), name = "pi") 312 313 pi = simple_projections 314 315 ########################################################################## 316 # Weyl group 317 ########################################################################## 318 319 def weyl_group(self): 320 """ 321 Returns the Weyl group associated to self. 322 323 EXAMPLES: 324 sage: e = RootSystem(['F',4]).ambient_space() 325 sage: e.weyl_group() 326 The Weyl Group of type ['F', 4] 327 """ 328 from sage.combinat.root_system.weyl_group import WeylGroup 329 # FIXME: should return the Weyl group acting on that particular 330 # root lattice realization 331 # return WeylGroup(self) 332 return WeylGroup(self.root_system.cartan_type()) 333 334 class RootLatticeRealizationElement: 335 336 def scalar(self, lambdacheck): 337 """ 338 The natural pairing between this and the coroot lattice. 339 """ 340 raise NotImplementedError 341 342 343 def simple_reflection(self, i): 344 """ 345 The image of self by the $i$-th simple reflection 346 """ 347 # Subclasses should optimize whenever possible! 348 return self.parent().simple_reflections()[i](self) 349 350 ########################################################################## 351 # Descents 352 ########################################################################## 353 354 def has_descent(self, i, positive=False): 355 """ 356 Test if self has a descent at position $i$, that is if self is 357 on the strict negative side of the $i$-th simple reflection 358 hyperplane. 359 360 If positive if True, tests if it is on the strict positive 361 side instead. 362 363 EXAMPLES: 364 sage: space=RootSystem(['A',5]).weight_space() 365 sage: alpha=RootSystem(['A',5]).weight_space().simple_roots() 366 sage: [alpha[i].has_descent(1) for i in space.index_set()] 367 [False, True, False, False, False] 368 sage: [(-alpha[i]).has_descent(1) for i in space.index_set()] 369 [True, False, False, False, False] 370 sage: [alpha[i].has_descent(1, True) for i in space.index_set()] 371 [True, False, False, False, False] 372 sage: [(-alpha[i]).has_descent(1, True) for i in space.index_set()] 373 [False, True, False, False, False] 374 sage: (alpha[1]+alpha[2]+alpha[4]).has_descent(3) 375 True 376 sage: (alpha[1]+alpha[2]+alpha[4]).has_descent(1) 377 False 378 sage: (alpha[1]+alpha[2]+alpha[4]).has_descent(1, True) 379 True 380 """ 381 s = self.scalar(self.parent().simple_coroots()[i]) 382 if positive: 383 return s > 0 384 else: 385 return s < 0 386 387 def first_descent(self, index_set=None, positive=False): 388 """ 389 Returns the first descent of pt 390 391 One can use the index_set option to restrict to the parabolic 392 subgroup indexed by index_set. 393 394 EXAMPLES: 395 sage: space=RootSystem(['A',5]).weight_space() 396 sage: alpha=space.simple_roots() 397 sage: (alpha[1]+alpha[2]+alpha[4]).first_descent() 398 3 399 sage: (alpha[1]+alpha[2]+alpha[4]).first_descent([1,2,5]) 400 5 401 sage: (alpha[1]+alpha[2]+alpha[4]).first_descent([1,2,5,3,4]) 402 5 403 """ 404 if index_set == None: 405 index_set = self.parent().index_set() 406 for i in index_set: 407 if self.has_descent(i, positive): 408 return i 409 return None 410 411 def descents(self, index_set=None, positive=False): 412 """ 413 Returns the descents of pt 414 415 EXAMPLES: 416 sage: space=RootSystem(['A',5]).weight_space() 417 sage: alpha=space.simple_roots() 418 sage: (alpha[1]+alpha[2]+alpha[4]).descents() 419 [3, 5] 420 """ 421 if index_set==None: 422 index_set=self.parent().index_set() 423 return [ i for i in index_set if self.has_descent(i, positive) ] 424 425 def to_positive_chamber(self, index_set = None, positive = True): 426 """ 427 Returns the unique element of the orbit of pt in the positive 428 chamber. 429 430 With the index_set optional parameter, this is done with 431 respect to the corresponding parbolic subgroup 432 433 With positive = False, returns the unique element in the 434 negative chamber instead 435 436 437 EXAMPLES: 438 sage: space=RootSystem(['A',5]).weight_space() 439 sage: alpha=RootSystem(['A',5]).weight_space().simple_roots() 440 sage: alpha[1].to_positive_chamber() 441 Lambda[1] + Lambda[5] 442 sage: alpha[1].to_positive_chamber([1,2]) 443 Lambda[1] + Lambda[2] - Lambda[3] 444 """ 445 if index_set==None: 446 index_set=self.parent().index_set() 447 while True: 448 # The first index where it is *not* yet on the positive side 449 i = self.first_descent(index_set, positive=not positive) 450 if i is None: 451 return self 452 else: 453 self = self.simple_reflection(i) 454 455 def is_dominant(self, index_set = None, positive = True): 456 """ 457 Returns whether self is dominant. 458 459 With positive = False, returns whether self is antidominant 460 461 INPUT: 462 v -- an element of the lattice 463 464 EXAMPLES: 465 sage: L = RootSystem(['A',2]).ambient_lattice() 466 sage: Lambda = L.fundamental_weights() 467 sage: [x.is_dominant() for x in Lambda] 468 [True, True] 469 sage: [x.is_dominant(positive=False) for x in Lambda] 470 [False, False] 471 sage: (Lambda[1]-Lambda[2]).is_dominant() 472 False 473 sage: (-Lambda[1]+Lambda[2]).is_dominant() 474 False 475 sage: (Lambda[1]-Lambda[2]).is_dominant([1]) 476 True 477 sage: (Lambda[1]-Lambda[2]).is_dominant([2]) 478 False 479 sage: [x.is_dominant() for x in L.roots()] 480 [False, True, False, False, False, False] 481 sage: [x.is_dominant(positive=False) for x in L.roots()] 482 [False, False, False, False, True, False] 483 """ 484 return self.first_descent(index_set, not positive) is None -
new file sage/combinat/root_system/root_space.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/root_space.py
- + 1 #***************************************************************************** 2 # Copyright (C) 2007 Nicolas M. Thiery <nthiery at users.sf.net> 3 # 4 # Distributed under the terms of the GNU General Public License (GPL) 5 # 6 # This code is distributed in the hope that it will be useful, 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 # General Public License for more details. 10 # 11 # The full text of the GPL is available at: 12 # 13 # http://www.gnu.org/licenses/ 14 #***************************************************************************** 15 16 from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement 17 from root_lattice_realization import RootLatticeRealization, RootLatticeRealizationElement 18 from sage.rings.all import ZZ 19 20 21 class RootSpace(CombinatorialFreeModule, RootLatticeRealization): 22 23 def __init__(self, root_system, base_ring): 24 self.root_system = root_system 25 basis_name = "alphacheck" if root_system.dualSide else "alpha" 26 CombinatorialFreeModule.__init__(self, base_ring,\ 27 root_system.index_set(),\ 28 element_class = RootSpaceElement,\ 29 prefix=basis_name) 30 # This would be more efficient, but this is not used intensively, 31 # and we would have to be careful with pickling: 32 # self.simple_root = self.basis().__getitem__ 33 34 def simple_root(self, i): 35 return self.basis()[i] 36 37 def __repr__(self): 38 """ 39 TEST: 40 sage: RootSystem(['A',4]).root_lattice() 41 The root lattice of the Root system of type ['A', 4] 42 sage: RootSystem(['B',4]).root_space() 43 The root space over the Rational Field of the Root system of type ['B', 4] 44 sage: RootSystem(['A',4]).coroot_lattice() 45 The coroot lattice of the Root system of type ['A', 4] 46 sage: RootSystem(['B',4]).coroot_space() 47 The coroot space over the Rational Field of the Root system of type ['B', 4] 48 49 """ 50 return "The %s"%self.root_system.dualString+\ 51 ("root lattice " if self.base_ring() == ZZ else "root space over the %s "%self.base_ring())+\ 52 "of the %s"%(self.root_system.dual if self.root_system.dualSide else self.root_system) 53 54 simple_roots = CombinatorialFreeModule.basis 55 56 57 class RootSpaceElement(CombinatorialFreeModuleElement, RootLatticeRealizationElement): 58 59 def scalar(self, lambdacheck): 60 """ 61 The scalar product between the root lattice and 62 the coroot lattice. 63 """ 64 zero = self.parent().base_ring().zero_element() 65 cartan_matrix = self.parent().dynkin_diagram() 66 return sum( (sum( (lambdacheck[i]*s for (i,s) in cartan_matrix.column(j)), zero) * c 67 for (j,c) in self), zero) 68 -
sage/combinat/root_system/root_system.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/root_system.py
a b 4 4 #***************************************************************************** 5 5 # Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>, 6 6 # Justin Walker <justin at mac.com> 7 # Nicolas M. Thiery <nthiery at users.sf.net> 7 8 # 8 9 # Distributed under the terms of the GNU General Public License (GPL) 9 10 # … … 16 17 # 17 18 # http://www.gnu.org/licenses/ 18 19 #***************************************************************************** 19 import cartan_type 20 from sage.modules.free_module import FreeModule 21 from sage.rings.all import ZZ 22 from sage.misc.misc import prod 20 # Design largely inspired from MuPAD-Combinat 23 21 24 def RootSystem(t): 25 """ 22 from cartan_type import CartanType 23 from sage.rings.all import ZZ, QQ 24 from sage import combinat 25 from root_space import RootSpace 26 from weight_space import WeightSpace 27 import type_A 28 import type_B 29 import type_C 30 import type_D 31 import type_E 32 import type_F 33 import type_G 34 import type_dual 35 import type_reducible 36 import type_None 37 38 class RootSystem: 39 r""" 26 40 Returns the root system associated to the Cartan type t. 27 41 28 42 EXAMPLES: 29 sage: RootSystem(['A',3]) 30 Root system of type ['A', 3] 43 We construct the root system for type $B_3$ 44 45 sage: R=RootSystem(['B',3]); R 46 Root system of type ['B', 3] 47 48 R models the root system abstractly. It comes equipped with 49 various realizations of the root and weight lattices, where all 50 computation take place. Let us play first with the root lattice. 51 52 sage: space = R.root_lattice() 53 sage: space 54 The root lattice of the Root system of type ['B', 3] 55 56 It is the free \ZZ module $\bigoplus_i \ZZ.\alpha_i$ spanned by 57 the simple roots: 58 59 sage: space.base_ring() 60 Integer Ring 61 sage: list(space.basis()) 62 [alpha[1], alpha[2], alpha[3]] 63 64 Let us do some computations with the simple roots: 65 66 sage: alpha = space.simple_roots() 67 sage: alpha[1] + alpha[2] 68 alpha[1] + alpha[2] 69 70 There is a canonical pairing between the root lattice and the 71 coroot lattice: 72 sage: R.coroot_lattice() 73 The coroot lattice of the Root system of type ['B', 3] 74 75 We construct the simple coroots, and do some computations (see 76 comments about duality below for some caveat). 77 sage: alphacheck = space.simple_coroots() 78 sage: list(alphacheck) 79 [alphacheck[1], alphacheck[2], alphacheck[3]] 80 81 82 We can carry over the same computations in any of the other 83 realizations of the root lattice, like the root space 84 $\bigoplus_i \QQ.\alpha_i$, the weight lattice $\bigoplus_i 85 \ZZ.\Lambda_i$, the weight space $\bigoplus_i \QQ.\Lambda_i$. 86 For example: 87 88 sage: space = R.weight_space() 89 sage: space 90 The weight space over the Rational Field of the Root system of type ['B', 3] 91 92 sage: space.base_ring() 93 Rational Field 94 sage: list(space.basis()) 95 [Lambda[1], Lambda[2], Lambda[3]] 96 97 sage: alpha = space.simple_roots() 98 sage: alpha[1] + alpha[2] 99 Lambda[1] + Lambda[2] - 2*Lambda[3] 100 101 The fundamental weights are the dual basis of the coroots: 102 103 sage: Lambda = space.fundamental_weights() 104 sage: Lambda[1] 105 Lambda[1] 106 107 sage: alphacheck = space.simple_coroots() 108 sage: list(alphacheck) 109 [alphacheck[1], alphacheck[2], alphacheck[3]] 110 111 sage: [Lambda[i].scalar(alphacheck[1]) for i in space.index_set()] 112 [1, 0, 0] 113 sage: [Lambda[i].scalar(alphacheck[2]) for i in space.index_set()] 114 [0, 1, 0] 115 sage: [Lambda[i].scalar(alphacheck[3]) for i in space.index_set()] 116 [0, 0, 1] 117 118 Let us us use the simple reflections. In the weight space, they 119 work as in the \emph{number game}: firing the node $i$ on an 120 element x adds $c$ times the simple root $\alpha_i$, where $c$ 121 is the coefficient of $i$ in $x$: 122 123 sage: s = space.simple_reflections() 124 sage: Lambda[1].simple_reflection(1) 125 -Lambda[1] + Lambda[2] 126 sage: Lambda[2].simple_reflection(1) 127 Lambda[2] 128 sage: Lambda[3].simple_reflection(1) 129 Lambda[3] 130 sage: (-2*Lambda[1] + Lambda[2] + Lambda[3]).simple_reflection(1) 131 2*Lambda[1] - Lambda[2] + Lambda[3] 132 133 It can be convenient to manipulate the simple reflections 134 themselves: 135 136 sage: s = space.simple_reflections() 137 sage: s[1](Lambda[1]) 138 -Lambda[1] + Lambda[2] 139 sage: s[1](Lambda[2]) 140 Lambda[2] 141 sage: s[1](Lambda[3]) 142 Lambda[3] 143 144 The root system may also come equipped with an ambient space, 145 that is a simultaneous realization of the weight lattice and the 146 coroot lattice in an euclidean vector space. This is implemented 147 on a type by type basis, and is not always available. When the 148 coefficients permit it, this is also available as an ambient 149 lattice. 150 151 TODO: Demo: signed permutations realization of type B 152 153 154 155 The root system is aware of its dual root system: 156 sage: R.dual 157 Dual of root system of type ['B', 3] 158 159 R.dual is really the root system of type $C_3$: 160 sage: R.dual.cartan_type() 161 ['C', 3] 162 163 And the coroot lattice that we have been manipulating before is 164 really implemented as the root lattice of the dual root system: 165 166 sage: R.dual.root_lattice() 167 The coroot lattice of the Root system of type ['B', 3] 168 169 In particular, the coroots for the root lattice are in fact the 170 roots of the coroot lattice: 171 172 sage: list(R.root_lattice().simple_coroots()) 173 [alphacheck[1], alphacheck[2], alphacheck[3]] 174 sage: list(R.coroot_lattice().simple_roots()) 175 [alphacheck[1], alphacheck[2], alphacheck[3]] 176 sage: list(R.dual.root_lattice().simple_roots()) 177 [alphacheck[1], alphacheck[2], alphacheck[3]] 178 179 The coweight lattice and space are defined similarly. Note 180 that, to limit confusion, all the output have been tweaked 181 appropriately. 182 183 184 TESTS: 185 186 sage: R = RootSystem(['C',3]) 187 sage: R == loads(dumps(R)) 188 True 189 sage: L = R.ambient_space() 190 sage: s = L.simple_reflections() 191 sage: s = L.simple_projections() # todo: not implemented 192 sage: L == loads(dumps(L)) 193 True 194 sage: L = R.root_space() 195 sage: s = L.simple_reflections() 196 sage: L == loads(dumps(L)) 197 True 198 199 sage: for T in CartanType.samples(finite=True,crystalographic=True): 200 ... RootSystem(T).check() 31 201 """ 32 ct = cartan_type.CartanType(t) 33 if not ct.affine: 34 typ = ct.type() 35 if typ == "A": 36 return RootSystem_a(ct) 37 elif typ == "B": 38 return RootSystem_b(ct) 39 elif typ == "C": 40 return RootSystem_c(ct) 41 elif typ == "D": 42 return RootSystem_d(ct) 43 elif typ == "E": 44 return RootSystem_e(ct) 45 elif typ == "F": 46 return RootSystem_f(ct) 47 elif typ == "G": 48 return RootSystem_g(ct) 49 else: 50 return RootSystem_generic(ct) 202 203 def check(self): 204 self.root_lattice().check() 205 self.root_space ().check() 206 self.weight_lattice().check() 207 self.weight_space().check() 208 if not self.ambient_lattice() is None: 209 self.ambient_lattice().check() 210 if not self.ambient_space() is None: 211 self.ambient_space().check() 51 212 52 class RootSystem_generic: 53 def __init__(self, ct): 213 def __init__(self, cartan_type, asDualOf=None): 54 214 """ 55 215 TESTS: 56 216 sage: R = RootSystem(['A',3]) 57 sage: loads(dumps(R))217 sage: R 58 218 Root system of type ['A', 3] 59 219 """ 60 self.ct = ct 220 self._cartan_type = CartanType(cartan_type) 221 222 # Get the python module containing type-specific information, 223 # if it exists 224 self.tools = getattr(combinat.root_system, 225 self._cartan_type.type_string(), 226 combinat.root_system.type_None); 227 228 # Duality 229 # The root system can be defined as dual of another root system. This will 230 # only affects the pretty printing 231 if asDualOf == None: 232 self.dual = RootSystem(self._cartan_type.dual(), asDualOf=self); 233 self.dualSide = False 234 self.dualString = "" 235 else: 236 self.dual = asDualOf 237 self.dualSide = True 238 self.dualString = "co" 61 239 62 240 def __repr__(self): 63 241 """ … … 65 243 sage: RootSystem(['A',3]) 66 244 Root system of type ['A', 3] 67 245 """ 68 return "Root system of type %s"%self.ct 246 if self.dualSide: 247 return "Dual of root system of type %s"%self.dual.cartan_type() 248 else: 249 return "Root system of type %s"%self.cartan_type() 69 250 70 251 def cartan_type(self): 71 252 """ … … 76 257 sage: R.cartan_type() 77 258 ['A', 3] 78 259 """ 79 return self. ct260 return self._cartan_type 80 261 262 # TODO: remember 263 def dynkin_diagram(self): 264 """ 265 Returns the Dynkin diagram of the root system. 266 267 EXAMPLES: 268 sage: R = RootSystem(['A',3]) 269 sage: R.dynkin_diagram() 270 Dynkin diagram of type ['A', 3] 271 """ 272 return self.cartan_type().dynkin_diagram() 273 274 # TODO: remember 81 275 def cartan_matrix(self): 82 276 """ 83 277 EXAMPLES: … … 96 290 """ 97 291 return self.cartan_type().index_set() 98 292 293 def is_finite(self): 294 # TODO: remember 295 return self.cartan_type().is_finite() 296 297 def is_irreducible(self): 298 # TODO: remember 299 return self.cartan_type().is_irreducible() 300 99 301 def __cmp__(self, other): 100 302 """ 101 303 EXAMPLES: … … 108 310 """ 109 311 if self.__class__ != other.__class__: 110 312 return cmp(self.__class__, other.__class__) 111 if self. ct != other.ct:112 return cmp(self. ct, other.ct)313 if self._cartan_type != other._cartan_type: 314 return cmp(self._cartan_type, other._cartan_type) 113 315 return 0 316 317 318 def root_lattice(self): 319 return self.root_space(ZZ) 320 321 def root_space(self, base_ring = QQ): 322 return RootSpace(self, base_ring) 323 324 def coroot_lattice(self): 325 return self.dual.root_lattice() 114 326 115 class RootSystem_a(RootSystem_generic): 327 def coroot_space(self, base_ring = QQ): 328 return self.dual.root_space(base_ring) 329 330 331 def weight_lattice(self): 332 return self.weight_space(ZZ) 333 334 def weight_space(self, base_ring = QQ): 335 return WeightSpace(self, base_ring) 336 337 def coweight_lattice(self): 338 return self.dual.weight_lattice() 339 340 def coweight_space(self, base_ring = QQ): 341 return self.dual.weight_space(base_ring) 342 343 116 344 def ambient_lattice(self): 117 """ 345 r""" 346 Returns the usual ambient lattice for this root_system, if it 347 exists and is implemented, and None otherwise. This is a 348 Z-module, endowed with its canonical euclidean scalar product, 349 which embeds simultaneously the root lattice and the coroot 350 lattice (what about the weight lattice?) 351 118 352 EXAMPLES: 119 353 sage: RootSystem(['A',4]).ambient_lattice() 120 Ambient lattice of the root system of type ['A', 4] 354 Ambient lattice for the Root system of type ['A', 4] 355 356 sage: RootSystem(['B',4]).ambient_lattice() 357 sage: RootSystem(['C',4]).ambient_lattice() 358 sage: RootSystem(['D',4]).ambient_lattice() 359 sage: RootSystem(['E',6]).ambient_lattice() 360 sage: RootSystem(['F',4]).ambient_lattice() 361 sage: RootSystem(['G',2]).ambient_lattice() 121 362 """ 122 return AmbientLattice_a(self.ct)363 return self.ambient_space(ZZ) 123 364 124 class RootSystem_b(RootSystem_generic): 125 def ambient_lattice(self): 365 def ambient_space(self, base_ring=QQ): 126 366 """ 127 EXAMPLES: 128 sage: RootSystem(['B',4]).ambient_lattice() 129 Ambient lattice of the root system of type ['B', 4] 130 """ 131 return AmbientLattice_b(self.ct) 132 133 class RootSystem_c(RootSystem_generic): 134 def ambient_lattice(self): 135 """ 136 EXAMPLES: 137 sage: RootSystem(['C',4]).ambient_lattice() 138 Ambient lattice of the root system of type ['C', 4] 139 """ 140 return AmbientLattice_c(self.ct) 141 142 class RootSystem_d(RootSystem_generic): 143 def ambient_lattice(self): 144 """ 145 EXAMPLES: 146 sage: RootSystem(['D',4]).ambient_lattice() 147 Ambient lattice of the root system of type ['D', 4] 148 """ 149 return AmbientLattice_d(self.ct) 150 151 class RootSystem_e(RootSystem_generic): 152 def ambient_lattice(self): 153 """ 154 EXAMPLES: 155 sage: RootSystem(['E',6]).ambient_lattice() 156 Ambient lattice of the root system of type ['E', 6] 157 """ 158 return AmbientLattice_e(self.ct) 159 160 class RootSystem_f(RootSystem_generic): 161 def ambient_lattice(self): 162 """ 163 EXAMPLES: 164 sage: RootSystem(['F',4]).ambient_lattice() 165 Ambient lattice of the root system of type ['F', 4] 166 """ 167 return AmbientLattice_f(self.ct) 168 169 class RootSystem_g(RootSystem_generic): 170 def ambient_lattice(self): 171 """ 172 EXAMPLES: 173 sage: RootSystem(['G',2]).ambient_lattice() 174 Ambient lattice of the root system of type ['G', 2] 175 """ 176 return AmbientLattice_g(self.ct) 177 178 179 180 class WeightLatticeRealization_class: 181 # Should this be a method or an attribute? 182 # same question for the roots, ... 183 def rho(self): 184 """ 185 EXAMPLES: 186 sage: RootSystem(['A',3]).ambient_lattice().rho() 187 (3, 2, 1, 0) 188 """ 189 return sum(self.fundamental_weights()) 190 191 # Should it be a method of highest_weight? 192 def weyl_dimension(self, highest_weight): 193 """ 194 EXAMPLES: 195 sage: hwv = vector([2,1,0,0]) 196 sage: RootSystem(['A',3]).ambient_lattice().weyl_dimension(hwv) 197 20 198 """ 199 # Should assert(highest_weight.is_dominant()) 200 rho = self.rho() 201 n = prod([(rho+highest_weight).dot_product(x) for x in self.positive_roots()]) 202 d = prod([ rho.dot_product(x) for x in self.positive_roots()]) 203 return n/d 204 205 def highest_root(self): 206 """ 207 EXAMPLES: 208 sage: RootSystem(['E',6]).ambient_lattice().highest_root() 209 (1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2) 210 """ 211 for alp in self.positive_roots(): 212 if all(not(alp+bet in self.positive_roots()) for bet in self.positive_roots()): 213 return alp 214 215 def simple_reflection(self, i, v): 216 """ 217 Returns the $i^{th}$ simple reflection applied to v, an element 218 of the lattice. 219 220 INPUT: 221 i -- i is in self's index set 222 v -- an element of the lattice 223 224 EXAMPLES: 225 sage: e = RootSystem(['A',2]).ambient_lattice() 226 sage: v = e.simple_roots()[0] 227 sage: e.simple_reflection(1, v) 228 (-1, 1, 0) 229 """ 230 alpha = self.simple_roots()[i-1] 231 return v-2*alpha.inner_product(v)/alpha.inner_product(alpha)*alpha 232 233 def weyl_group(self): 234 """ 235 Returns the Weyl group associated to self. 236 237 EXAMPLES: 238 sage: e = RootSystem(['F',4]).ambient_lattice() 239 sage: e.weyl_group() 240 The Weyl Group of type ['F', 4] 241 """ 242 from sage.combinat.root_system.weyl_group import WeylGroup 243 return WeylGroup(self.ct) 244 245 def is_dominant(self, v): 246 """ 247 Returns True if v is dominant. 248 249 INPUT: 250 v -- an element of the lattice 251 252 EXAMPLES: 253 sage: L = RootSystem(['A',2]).ambient_lattice() 254 sage: [L.is_dominant(x) for x in L.roots()] 255 [False, True, False, False, False, False] 256 """ 257 for alph in self.positive_roots(): 258 if v.inner_product(alph) < 0: 259 return False 260 return True 261 262 263 class AmbientLattice_generic(WeightLatticeRealization_class): 264 def __init__(self, ct): 265 """ 266 EXAMPLES: 267 sage: e = RootSystem(['A',3]).ambient_lattice() 268 sage: e == loads(dumps(e)) 269 True 270 """ 271 if not hasattr(self, 'n'): 272 self.n = ct.rank() 273 self.ct = ct 274 self._free_module = FreeModule(ZZ, self.n) 275 276 def __repr__(self): 277 """ 278 EXAMPLES: 279 sage: RootSystem(['B',4]).ambient_lattice() 280 Ambient lattice of the root system of type ['B', 4] 281 282 """ 283 return "Ambient lattice of the root system of type %s"%self.ct 284 285 def __getitem__(self,i): 286 """ 287 Note that indexing starts at 1. 367 Returns the usual ambient space for this root_system, if it is 368 implemented, and None otherwise. This is a QQ-module, endowed 369 with its canonical euclidean scalar product, which embeds 370 simultaneously the root lattice and the coroot lattice (what 371 about the weight lattice?). An alternative base ring can be 372 provided as an option; it must contain the smallest ring over 373 which the ambient space can be defined (ZZ or QQ, depending on 374 the type). 288 375 289 376 EXAMPLES: 290 sage: e = RootSystem(['A',2]).ambient_lattice() 291 sage: e[1] 292 (1, 0, 0) 377 sage: RootSystem(['A',4]).ambient_space() 378 Ambient space for the Root system of type ['A', 4] 379 380 sage: RootSystem(['B',4]).ambient_space() 381 Ambient space for the Root system of type ['B', 4] 382 383 sage: RootSystem(['C',4]).ambient_space() 384 Ambient space for the Root system of type ['C', 4] 385 386 sage: RootSystem(['D',4]).ambient_space() 387 Ambient space for the Root system of type ['D', 4] 388 389 sage: RootSystem(['E',6]).ambient_space() 390 Ambient space for the Root system of type ['E', 6] 391 392 sage: RootSystem(['F',4]).ambient_space() 393 Ambient space for the Root system of type ['F', 4] 394 395 sage: RootSystem(['G',2]).ambient_space() 396 Ambient space for the Root system of type ['G', 2] 293 397 """ 294 return self._term(i-1) 295 296 def roots(self): 297 """ 298 Returns the roots of self. 299 300 EXAMPLES: 301 sage: RootSystem(['A',2]).ambient_lattice().roots() 302 [(1, -1, 0), (1, 0, -1), (0, 1, -1), (-1, 1, 0), (-1, 0, 1), (0, -1, 1)] 303 """ 304 return self.positive_roots() + self.negative_roots() 305 306 def _term(self, i): 307 """ 308 Note that indexing starts at 0. 309 310 EXAMPLES: 311 sage: e = RootSystem(['A',2]).ambient_lattice() 312 sage: e._term(0) 313 (1, 0, 0) 314 """ 315 return self._free_module.gen(i) 316 317 def __cmp__(self, other): 318 """ 319 EXAMPLES: 320 sage: e1 = RootSystem(['A',3]).ambient_lattice() 321 sage: e2 = RootSystem(['B',3]).ambient_lattice() 322 sage: e1 == e1 323 True 324 sage: e1 == e2 325 False 326 """ 327 if self.__class__ != other.__class__: 328 return cmp(self.__class__, other.__class__) 329 if self.ct != other.ct: 330 return cmp(self.ct, other.ct) 331 return 0 398 # Intention: check that the ambient_space is implemented and that 399 # base_ring contains the smallest base ring for this ambient space 400 if not self.tools.__dict__.has_key("ambient_space") or \ 401 (base_ring == ZZ and self.tools.ambient_space.smallest_base_ring() == QQ): 402 return None 403 else: 404 return self.tools.ambient_space(self, base_ring) 332 405 333 class AmbientLattice_a(AmbientLattice_generic):334 def __init__(self, ct):335 """336 EXAMPLES:337 sage: e = RootSystem(['A',3]).ambient_lattice()338 sage: e.n339 4340 """341 self.n = ct.rank()+1342 AmbientLattice_generic.__init__(self, ct)343 344 def root(self, i, j):345 """346 Note that indexing starts at 0.347 348 EXAMPLES:349 sage: e = RootSystem(['A',3]).ambient_lattice()350 sage: e.root(0,1)351 (1, -1, 0, 0)352 """353 return self._term(i) - self._term(j)354 355 def simple_roots(self):356 """357 EXAMPLES:358 sage: e = CartanType(['A',3]).root_system().ambient_lattice()359 sage: e.simple_roots()360 [(1, -1, 0, 0), (0, 1, -1, 0), (0, 0, 1, -1)]361 """362 return [ self.root(i, i+1) for i in range(self.n-1) ]363 364 def negative_roots(self):365 """366 EXAMPLES:367 sage: e = CartanType(['A',3]).root_system().ambient_lattice()368 sage: e.negative_roots()369 [(-1, 1, 0, 0),370 (-1, 0, 1, 0),371 (-1, 0, 0, 1),372 (0, -1, 1, 0),373 (0, -1, 0, 1),374 (0, 0, -1, 1)]375 """376 res = []377 for j in range(self.n-1):378 for i in range(j+1,self.n):379 res.append( self.root(i,j) )380 return res381 382 def positive_roots(self):383 """384 EXAMPLES:385 sage: e = CartanType(['A',3]).root_system().ambient_lattice()386 sage: e.positive_roots()387 [(1, -1, 0, 0),388 (1, 0, -1, 0),389 (0, 1, -1, 0),390 (1, 0, 0, -1),391 (0, 1, 0, -1),392 (0, 0, 1, -1)]393 394 """395 res = []396 for j in range(self.n):397 for i in range(j):398 res.append( self.root(i,j) )399 return res400 401 def highest_root(self):402 """403 EXAMPLE:404 sage: e = CartanType(['A',3]).root_system().ambient_lattice()405 sage: e.highest_root()406 (1, 0, 0, -1)407 """408 return self.root(0,self.n-1)409 410 def fundamental_weights(self):411 """412 EXAMPLES:413 sage: e = CartanType(['A',3]).root_system().ambient_lattice()414 sage: e.fundamental_weights()415 [(1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0)]416 417 """418 return [ sum([self._term(j) for j in range(i+1)]) for i in range(self.n-1)]419 420 class AmbientLattice_b(AmbientLattice_generic):421 def root(self, i, j):422 """423 Note that indexing starts at 0.424 425 EXAMPLES:426 sage: e = RootSystem(['B',3]).ambient_lattice()427 sage: e.root(0,1)428 (1, -1, 0)429 430 """431 return self._term(i) - self._term(j)432 433 def simple_roots(self):434 """435 EXAMPLES:436 sage: e = RootSystem(['B',4]).ambient_lattice()437 sage: e.simple_roots()438 [(1, -1, 0, 0), (0, 1, -1, 0), (0, 0, 1, -1), (0, 0, 0, 1)]439 sage: e.positive_roots()440 [(1, -1, 0, 0),441 (1, 1, 0, 0),442 (1, 0, -1, 0),443 (1, 0, 1, 0),444 (1, 0, 0, -1),445 (1, 0, 0, 1),446 (0, 1, -1, 0),447 (0, 1, 1, 0),448 (0, 1, 0, -1),449 (0, 1, 0, 1),450 (0, 0, 1, -1),451 (0, 0, 1, 1),452 (1, 0, 0, 0),453 (0, 1, 0, 0),454 (0, 0, 1, 0),455 (0, 0, 0, 1)]456 sage: e.fundamental_weights()457 [(1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0), (1/2, 1/2, 1/2, 1/2)]458 459 """460 return [ self.root(i,i+1) for i in range(self.n-1) ] + [ self._term(self.n-1) ]461 462 def negative_roots(self):463 """464 EXAMPLES:465 sage: RootSystem(['B',3]).ambient_lattice().negative_roots()466 [(-1, 1, 0),467 (-1, -1, 0),468 (-1, 0, 1),469 (-1, 0, -1),470 (0, -1, 1),471 (0, -1, -1),472 (-1, 0, 0),473 (0, -1, 0),474 (0, 0, -1)]475 476 """477 return [ -a for a in self.positive_roots()]478 479 480 def positive_roots(self):481 """482 EXAMPLES:483 sage: RootSystem(['B',3]).ambient_lattice().positive_roots()484 [(1, -1, 0),485 (1, 1, 0),486 (1, 0, -1),487 (1, 0, 1),488 (0, 1, -1),489 (0, 1, 1),490 (1, 0, 0),491 (0, 1, 0),492 (0, 0, 1)]493 494 """495 res = []496 for i in range(self.n-1):497 for j in range(i+1,self.n):498 res.append(self._term(i) - self._term(j))499 res.append(self._term(i) + self._term(j))500 for i in range(self.n):501 res.append(self._term(i))502 return res503 504 def fundamental_weights(self):505 """506 EXAMPLES:507 sage: RootSystem(['B',3]).ambient_lattice().fundamental_weights()508 [(1, 0, 0), (1, 1, 0), (1/2, 1/2, 1/2)]509 510 """511 return [ sum(self._term(j) for j in range(i+1)) for i in range(self.n-1)]\512 + [ sum( self._term(j) for j in range(self.n) ) / 2 ]513 514 515 class AmbientLattice_c(AmbientLattice_generic):516 def root(self, i, j, p1, p2):517 """518 Note that indexing starts at 0.519 520 EXAMPLES:521 sage: e = RootSystem(['C',3]).ambient_lattice()522 sage: e.root(0, 1, 1, 1)523 (-1, -1, 0)524 """525 return (-1)**p1 * self._term(i) + (-1)**p2 * self._term(j)526 527 def simple_roots(self):528 """529 EXAMPLES:530 sage: RootSystem(['C',3]).ambient_lattice().simple_roots()531 [(1, -1, 0), (0, 1, -1), (0, 0, 2)]532 533 """534 return [ self.root(i, i+1,0,1) for i in range(self.n-1) ] + [self.root(self.n-1, self.n-1, 0, 0)]535 536 def positive_roots(self):537 """538 EXAMPLES:539 sage: RootSystem(['C',3]).ambient_lattice().positive_roots()540 [(1, 1, 0),541 (1, 0, 1),542 (0, 1, 1),543 (1, -1, 0),544 (1, 0, -1),545 (0, 1, -1),546 (2, 0, 0),547 (0, 2, 0),548 (0, 0, 2)]549 """550 res = []551 for p in [0,1]:552 for j in range(self.n):553 res.extend([self.root(i,j,0,p) for i in range(j)])554 res.extend([self.root(i,i,0,0) for i in range(self.n)])555 return res556 557 def negative_roots(self):558 """559 EXAMPLES:560 sage: RootSystem(['C',3]).ambient_lattice().negative_roots()561 [(-1, 1, 0),562 (-1, 0, 1),563 (0, -1, 1),564 (-1, -1, 0),565 (-1, 0, -1),566 (0, -1, -1),567 (-2, 0, 0),568 (0, -2, 0),569 (0, 0, -2)]570 """571 res = []572 for p in [0,1]:573 for j in range(self.n):574 res.extend( [self.root(i,j,1,p) for i in range(j) ] )575 res.extend( [ self.root(i,i,1,1) for i in range(self.n) ] )576 return res577 578 579 def fundamental_weights(self):580 """581 EXAMPLES:582 sage: RootSystem(['C',3]).ambient_lattice().fundamental_weights()583 [(1, 0, 0), (1, 1, 0), (1, 1, 1)]584 """585 return [ sum(self._term(j) for j in range(i+1)) for i in range(self.n)]586 587 588 class AmbientLattice_d(AmbientLattice_generic):589 def root(self, i, j, p1, p2):590 """591 Note that indexing starts at 0.592 593 EXAMPLES:594 sage: e = RootSystem(['D',3]).ambient_lattice()595 sage: e.root(0, 1, 1, 1)596 (-1, -1, 0)597 sage: e.root(0, 0, 1, 1)598 (-1, 0, 0)599 600 """601 if i != j:602 return (-1)**p1 * self._term(i) + (-1)**p2 * self._term(j)603 else:604 return (-1)**p1 * self._term(i)605 606 def simple_roots(self):607 """608 EXAMPLES:609 sage: RootSystem(['D',4]).ambient_lattice().simple_roots()610 [(1, -1, 0, 0), (0, 1, -1, 0), (0, 0, 1, -1), (0, 0, 1, 1)]611 612 """613 return [ self.root(i, i+1, 0, 1) for i in range(self.n-1) ] + [self.root(self.n-2, self.n-1, 0, 0)]614 615 def positive_roots(self):616 """617 EXAMPLES:618 sage: RootSystem(['D',4]).ambient_lattice().positive_roots()619 [(1, 1, 0, 0),620 (1, 0, 1, 0),621 (0, 1, 1, 0),622 (1, 0, 0, 1),623 (0, 1, 0, 1),624 (0, 0, 1, 1),625 (1, -1, 0, 0),626 (1, 0, -1, 0),627 (0, 1, -1, 0),628 (1, 0, 0, -1),629 (0, 1, 0, -1),630 (0, 0, 1, -1)]631 632 """633 res = []634 for p in [0,1]:635 for j in range(self.n):636 res.extend([self.root(i,j,0,p) for i in range(j)])637 return res638 639 def negative_roots(self):640 """641 EXAMPLES:642 sage: RootSystem(['D',4]).ambient_lattice().negative_roots()643 [(-1, 1, 0, 0),644 (-1, 0, 1, 0),645 (0, -1, 1, 0),646 (-1, 0, 0, 1),647 (0, -1, 0, 1),648 (0, 0, -1, 1),649 (-1, -1, 0, 0),650 (-1, 0, -1, 0),651 (0, -1, -1, 0),652 (-1, 0, 0, -1),653 (0, -1, 0, -1),654 (0, 0, -1, -1)]655 656 """657 res = []658 for p in [0,1]:659 for j in range(self.n):660 res.extend([self.root(i,j,1,p) for i in range(j)])661 return res662 663 664 def fundamental_weights(self):665 """666 EXAMPLES:667 sage: RootSystem(['D',4]).ambient_lattice().fundamental_weights()668 [(1, 0, 0, 0), (1, 1, 0, 0), (1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2)]669 670 """671 return [ sum(self._term(j) for j in range(i+1)) for i in range(self.n-2)]+\672 [ sum(self._term(j) for j in range(self.n-1))/2-self._term(self.n-1)/2]+\673 [ sum(self._term(j) for j in range(self.n))/2 ]674 675 676 class AmbientLattice_e(AmbientLattice_generic):677 """678 The lattice behind E6, E7, or E8. The computations are based on Bourbaki,679 Groupes et Algebres de Lie, Ch. 4,5,6 (planche V-VII).680 """681 def __init__(self, ct):682 """683 Create the ambient lattice for the root system for E6, E7, E8.684 Specify the Base, i.e., the simple roots w.r. to the canonical685 basis for $R^8$.686 687 EXAMPLES:688 sage: e = RootSystem(['E',6]).ambient_lattice()689 sage: e == loads(dumps(e))690 True691 sage: [e.weyl_dimension(v) for v in e.fundamental_weights()]692 [27, 78, 351, 2925, 351, 27]693 sage: e = RootSystem(['E',7]).ambient_lattice()694 sage: [e.weyl_dimension(v) for v in e.fundamental_weights()]695 [133, 912, 8645, 365750, 27664, 1539, 56]696 sage: e = RootSystem(['E',8]).ambient_lattice()697 sage: [e.weyl_dimension(v) for v in e.fundamental_weights()]698 [3875, 147250, 6696000, 6899079264, 146325270, 2450240, 30380, 248]699 """700 v = ZZ(1)/ZZ(2)701 self.n = 8 # We're always in R^8, but not always the whole space.702 self.rank = ct.n703 AmbientLattice_generic.__init__(self, ct)704 if ct.n == 6:705 self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)),706 self.root(0,1),707 self.root(0,1,p1=1),708 self.root(1,2,p1=1),709 self.root(2,3,p1=1),710 self.root(3,4,p1=1)]711 elif ct.n == 7:712 self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)),713 self.root(0,1),714 self.root(0,1,p1=1),715 self.root(1,2,p1=1),716 self.root(2,3,p1=1),717 self.root(3,4,p1=1),718 self.root(4,5,p1=1)]719 elif ct.n == 8:720 self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)),721 self.root(0,1),722 self.root(0,1,p1=1),723 self.root(1,2,p1=1),724 self.root(2,3,p1=1),725 self.root(3,4,p1=1),726 self.root(4,5,p1=1),727 self.root(5,6,p1=1)]728 else:729 raise NotImplementedError, "Type \'E\' root systems only come in flavors 6, 7, 8. Please make another choice"730 731 def root(self, i1, i2=None, i3=None, i4=None, i5=None, i6=None, i7=None, i8=None, p1=0, p2=0, p3=0, p4=0, p5=0, p6=0, p7=0, p8=0):732 """733 Compute an element of the underlying lattice, using the specified elements of734 the standard basis, with signs dictated by the corresponding 'pi' arguments.735 We rely on the caller to provide the correct arguments.736 This is typically used to generate roots, although the generated elements737 need not be roots themselves.738 We assume that if one of the indices is not given, the rest are not as well.739 This should work for E6, E7, E8.740 741 EXAMPLES:742 sage: E6 = RootSystem(['E',6])743 sage: LE6 = E6.ambient_lattice()744 sage: [ LE6.root(i,j,p3=1) for i in xrange(LE6.n) for j in xrange(i+1,LE6.n) ]745 [(1, 1, 0, 0, 0, 0, 0, 0), (1, 0, 1, 0, 0, 0, 0, 0), (1, 0, 0, 1, 0, 0, 0, 0), (1, 0, 0, 0, 1, 0, 0, 0), (1, 0, 0, 0, 0, 1, 0, 0), (1, 0, 0, 0, 0, 0, 1, 0), (1, 0, 0, 0, 0, 0, 0, 1), (0, 1, 1, 0, 0, 0, 0, 0), (0, 1, 0, 1, 0, 0, 0, 0), (0, 1, 0, 0, 1, 0, 0, 0), (0, 1, 0, 0, 0, 1, 0, 0), (0, 1, 0, 0, 0, 0, 1, 0), (0, 1, 0, 0, 0, 0, 0, 1), (0, 0, 1, 1, 0, 0, 0, 0), (0, 0, 1, 0, 1, 0, 0, 0), (0, 0, 1, 0, 0, 1, 0, 0), (0, 0, 1, 0, 0, 0, 1, 0), (0, 0, 1, 0, 0, 0, 0, 1), (0, 0, 0, 1, 1, 0, 0, 0), (0, 0, 0, 1, 0, 1, 0, 0), (0, 0, 0, 1, 0, 0, 1, 0), (0, 0, 0, 1, 0, 0, 0, 1), (0, 0, 0, 0, 1, 1, 0, 0), (0, 0, 0, 0, 1, 0, 1, 0), (0, 0, 0, 0, 1, 0, 0, 1), (0, 0, 0, 0, 0, 1, 1, 0), (0, 0, 0, 0, 0, 1, 0, 1), (0, 0, 0, 0, 0, 0, 1, 1)]746 """747 if i1 == i2 or i2 == None:748 return (-1)**p1*self._term(i1)749 if i3 == None:750 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)751 if i4 == None:752 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)753 if i5 == None:754 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)755 if i6 == None:756 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)+(-1)**p5*self._term(i5)757 if i7 == None:758 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)+(-1)**p5*self._term(i5)+(-1)**p6*self._term(i6)759 if i8 == None:760 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)+(-1)**p5*self._term(i5)+(-1)**p6*self._term(i6)+(-1)**p7*self._term(i7)761 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)+(-1)**p5*self._term(i5)+(-1)**p6*self._term(i6)+(-1)**p7*self._term(i7)+(-1)**p8*self._term(i8)762 763 def simple_roots(self):764 """765 There are computed as what Bourbaki calls the Base:766 a1 = e2-e3, a2 = e3-e4, a3 = e4, a4 = 1/2*(e1-e2-e3-e4)767 EXAMPLES:768 sage: LE6 = RootSystem(['E',6]).ambient_lattice()769 sage: LE6.simple_roots()770 [(1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (1, 1, 0, 0, 0, 0, 0, 0), (-1, 1, 0, 0, 0, 0, 0, 0), (0, -1, 1, 0, 0, 0, 0, 0), (0, 0, -1, 1, 0, 0, 0, 0), (0, 0, 0, -1, 1, 0, 0, 0)]771 """772 return self.Base773 774 def negative_roots(self):775 """776 The negative postive roots.777 EXAMPLES:778 sage: LE6 = RootSystem(['E',6]).ambient_lattice()779 sage: LE6.negative_roots()780 [(-1, -1, 0, 0, 0, 0, 0, 0), (-1, 0, -1, 0, 0, 0, 0, 0), (-1, 0, 0, -1, 0, 0, 0, 0), (-1, 0, 0, 0, -1, 0, 0, 0), (0, -1, -1, 0, 0, 0, 0, 0), (0, -1, 0, -1, 0, 0, 0, 0), (0, -1, 0, 0, -1, 0, 0, 0), (0, 0, -1, -1, 0, 0, 0, 0), (0, 0, -1, 0, -1, 0, 0, 0), (0, 0, 0, -1, -1, 0, 0, 0), (1, -1, 0, 0, 0, 0, 0, 0), (1, 0, -1, 0, 0, 0, 0, 0), (1, 0, 0, -1, 0, 0, 0, 0), (1, 0, 0, 0, -1, 0, 0, 0), (0, 1, -1, 0, 0, 0, 0, 0), (0, 1, 0, -1, 0, 0, 0, 0), (0, 1, 0, 0, -1, 0, 0, 0), (0, 0, 1, -1, 0, 0, 0, 0), (0, 0, 1, 0, -1, 0, 0, 0), (0, 0, 0, 1, -1, 0, 0, 0), (-1/2, -1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (1/2, -1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (1/2, -1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2)]781 """782 return [ -a for a in self.positive_roots()]783 784 def positive_roots(self):785 """786 These are the roots positive w.r. to lexicographic ordering of the787 basis elements (e1<...<e4).788 EXAMPLES:789 sage: LE6 = RootSystem(['E',6]).ambient_lattice()790 sage: LE6.positive_roots()791 [(1, 1, 0, 0, 0, 0, 0, 0), (1, 0, 1, 0, 0, 0, 0, 0), (1, 0, 0, 1, 0, 0, 0, 0), (1, 0, 0, 0, 1, 0, 0, 0), (0, 1, 1, 0, 0, 0, 0, 0), (0, 1, 0, 1, 0, 0, 0, 0), (0, 1, 0, 0, 1, 0, 0, 0), (0, 0, 1, 1, 0, 0, 0, 0), (0, 0, 1, 0, 1, 0, 0, 0), (0, 0, 0, 1, 1, 0, 0, 0), (-1, 1, 0, 0, 0, 0, 0, 0), (-1, 0, 1, 0, 0, 0, 0, 0), (-1, 0, 0, 1, 0, 0, 0, 0), (-1, 0, 0, 0, 1, 0, 0, 0), (0, -1, 1, 0, 0, 0, 0, 0), (0, -1, 0, 1, 0, 0, 0, 0), (0, -1, 0, 0, 1, 0, 0, 0), (0, 0, -1, 1, 0, 0, 0, 0), (0, 0, -1, 0, 1, 0, 0, 0), (0, 0, 0, -1, 1, 0, 0, 0), (1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (1/2, 1/2, 1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (1/2, 1/2, -1/2, 1/2, -1/2, -1/2, -1/2, 1/2), (1/2, 1/2, -1/2, -1/2, 1/2, -1/2, -1/2, 1/2), (1/2, -1/2, 1/2, 1/2, -1/2, -1/2, -1/2, 1/2), (1/2, -1/2, 1/2, -1/2, 1/2, -1/2, -1/2, 1/2), (1/2, -1/2, -1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, 1/2, 1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, -1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, 1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, -1/2, 1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, -1/2, -1/2, 1/2, -1/2, -1/2, 1/2)]792 sage: LE6.rho()793 (0, 1, 2, 3, 4, -4, -4, 4)794 sage: E8=RootSystem(['E',8])795 sage: LE8=E8.ambient_lattice()796 sage: LE8.negative_roots()797 [(-1, -1, 0, 0, 0, 0, 0, 0), (-1, 0, -1, 0, 0, 0, 0, 0), (-1, 0, 0, -1, 0, 0, 0, 0), (-1, 0, 0, 0, -1, 0, 0, 0), (-1, 0, 0, 0, 0, -1, 0, 0), (-1, 0, 0, 0, 0, 0, -1, 0), (-1, 0, 0, 0, 0, 0, 0, -1), (0, -1, -1, 0, 0, 0, 0, 0), (0, -1, 0, -1, 0, 0, 0, 0), (0, -1, 0, 0, -1, 0, 0, 0), (0, -1, 0, 0, 0, -1, 0, 0), (0, -1, 0, 0, 0, 0, -1, 0), (0, -1, 0, 0, 0, 0, 0, -1), (0, 0, -1, -1, 0, 0, 0, 0), (0, 0, -1, 0, -1, 0, 0, 0), (0, 0, -1, 0, 0, -1, 0, 0), (0, 0, -1, 0, 0, 0, -1, 0), (0, 0, -1, 0, 0, 0, 0, -1), (0, 0, 0, -1, -1, 0, 0, 0), (0, 0, 0, -1, 0, -1, 0, 0), (0, 0, 0, -1, 0, 0, -1, 0), (0, 0, 0, -1, 0, 0, 0, -1), (0, 0, 0, 0, -1, -1, 0, 0), (0, 0, 0, 0, -1, 0, -1, 0), (0, 0, 0, 0, -1, 0, 0, -1), (0, 0, 0, 0, 0, -1, -1, 0), (0, 0, 0, 0, 0, -1, 0, -1), (0, 0, 0, 0, 0, 0, -1, -1), (1, -1, 0, 0, 0, 0, 0, 0), (1, 0, -1, 0, 0, 0, 0, 0), (1, 0, 0, -1, 0, 0, 0, 0), (1, 0, 0, 0, -1, 0, 0, 0), (1, 0, 0, 0, 0, -1, 0, 0), (1, 0, 0, 0, 0, 0, -1, 0), (1, 0, 0, 0, 0, 0, 0, -1), (0, 1, -1, 0, 0, 0, 0, 0), (0, 1, 0, -1, 0, 0, 0, 0), (0, 1, 0, 0, -1, 0, 0, 0), (0, 1, 0, 0, 0, -1, 0, 0), (0, 1, 0, 0, 0, 0, -1, 0), (0, 1, 0, 0, 0, 0, 0, -1), (0, 0, 1, -1, 0, 0, 0, 0), (0, 0, 1, 0, -1, 0, 0, 0), (0, 0, 1, 0, 0, -1, 0, 0), (0, 0, 1, 0, 0, 0, -1, 0), (0, 0, 1, 0, 0, 0, 0, -1), (0, 0, 0, 1, -1, 0, 0, 0), (0, 0, 0, 1, 0, -1, 0, 0), (0, 0, 0, 1, 0, 0, -1, 0), (0, 0, 0, 1, 0, 0, 0, -1), (0, 0, 0, 0, 1, -1, 0, 0), (0, 0, 0, 0, 1, 0, -1, 0), (0, 0, 0, 0, 1, 0, 0, -1), (0, 0, 0, 0, 0, 1, -1, 0), (0, 0, 0, 0, 0, 1, 0, -1), (0, 0, 0, 0, 0, 0, 1, -1), (-1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, -1/2, -1/2, 1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, -1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, -1/2, 1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, 1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, -1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, -1/2, 1/2, -1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, 1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, -1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, 1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, -1/2, -1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, -1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, 1/2, -1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, -1/2, -1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, 1/2, -1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, -1/2, -1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, 1/2, -1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2, -1/2), (1/2, -1/2, -1/2, -1/2, -1/2, 1/2, -1/2, -1/2), (1/2, -1/2, -1/2, -1/2, 1/2, -1/2, -1/2, -1/2), (1/2, -1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2, -1/2, -1/2, -1/2, -1/2), (1/2, -1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2, 1/2, -1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2, -1/2), (1/2, -1/2, 1/2, -1/2, -1/2, -1/2, -1/2, -1/2), (1/2, -1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (1/2, -1/2, 1/2, -1/2, 1/2, -1/2, 1/2, -1/2), (1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2, -1/2), (1/2, -1/2, 1/2, 1/2, -1/2, -1/2, 1/2, -1/2), (1/2, -1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2), (1/2, -1/2, 1/2, 1/2, 1/2, -1/2, -1/2, -1/2), (1/2, -1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2), (1/2, 1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, -1/2, 1/2, -1/2, 1/2, -1/2), (1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2, -1/2), (1/2, 1/2, -1/2, 1/2, -1/2, -1/2, 1/2, -1/2), (1/2, 1/2, -1/2, 1/2, -1/2, 1/2, -1/2, -1/2), (1/2, 1/2, -1/2, 1/2, 1/2, -1/2, -1/2, -1/2), (1/2, 1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, -1/2, -1/2, -1/2, 1/2, -1/2), (1/2, 1/2, 1/2, -1/2, -1/2, 1/2, -1/2, -1/2), (1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2, -1/2), (1/2, 1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, -1/2, -1/2, -1/2, -1/2), (1/2, 1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, 1/2, -1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2)]798 sage: LE8.rho()799 (0, 1, 2, 3, 4, 5, 6, 23)800 """801 v = ZZ(1)/ZZ(2)802 # Note that803 if not hasattr(self, 'PosRoots'):804 if self.rank == 6:805 self.PosRoots = ( [ self.root(i,j) for i in xrange(self.rank-1) for j in xrange(i+1,self.rank-1) ] +806 [ self.root(i,j,p1=1) for i in xrange(self.rank-1) for j in xrange(i+1,self.rank-1) ] +807 [ v*(self.root(7)-self.root(6)-self.root(5)+self.root(0,1,2,3,4,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5))808 for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] if (p1+p2+p3+p4+p5)%2 == 0 ])809 elif self.rank == 7:810 self.PosRoots = ( [ self.root(i,j) for i in xrange(self.rank-1) for j in xrange(i+1,self.rank-1) ] +811 [ self.root(i,j,p1=1) for i in xrange(self.rank-1) for j in xrange(i+1,self.rank-1) ] +812 [ self.root(6,7,p1=1) ] +813 [ v*(self.root(7)-self.root(6)+self.root(0,1,2,3,4,5,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5,p6=p6))814 for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] if (p1+p2+p3+p4+p5+p6)%2 == 1 ])815 elif self.rank == 8:816 self.PosRoots = ( [ self.root(i,j) for i in xrange(self.rank) for j in xrange(i+1,self.rank) ] +817 [ self.root(i,j,p1=1) for i in xrange(self.rank) for j in xrange(i+1,self.rank) ] +818 [ v*(self.root(7)+self.root(0,1,2,3,4,5,6,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5,p6=p6,p7=p7))819 for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] for p7 in [0,1] if (p1+p2+p3+p4+p5+p6+p7)%2 == 0 ])820 821 return self.PosRoots822 823 def fundamental_weights(self):824 """825 EXAMPLES:826 sage: LE6 = RootSystem(['E',6]).ambient_lattice()827 sage: LE6.fundamental_weights()828 [(0, 0, 0, 0, 0, -2/3, -2/3, 2/3), (1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, 1/2, 1/2, 1/2, -5/6, -5/6, 5/6), (0, 0, 1, 1, 1, -1, -1, 1), (0, 0, 0, 1, 1, -2/3, -2/3, 2/3), (0, 0, 0, 0, 1, -1/3, -1/3, 1/3)]829 """830 v2 = ZZ(1)/ZZ(2)831 v3 = ZZ(1)/ZZ(3)832 if self.rank == 6:833 return [ 2*v3*self.root(7,6,5,p2=1,p3=1),834 v2*self.root(0,1,2,3,4,5,6,7,p6=1,p7=1),835 5*v2*v3*self.root(7,6,5,p2=1,p3=1)+v2*self.root(0,1,2,3,4,p1=1),836 self.root(2,3,4,5,6,7,p4=1,p5=1),837 2*v3*self.root(7,6,5,p2=1,p3=1)+self.root(3,4),838 v3*self.root(7,6,5,p2=1,p3=1)+self.root(4)]839 elif self.rank == 7:840 return [ self.root(7,6,p2=1),841 v2*self.root(0,1,2,3,4,5)+self.root(6,7,p1=1),842 v2*(self.root(0,1,2,3,4,5,p1=1)+3*self.root(6,7,p1=1)),843 self.root(2,3,4,5)+2*self.root(6,7,p1=1),844 3*v2*self.root(6,7,p1=1)+self.root(3,4,5),845 self.root(4,5,6,7,p3=1),846 self.root(5)+v2*self.root(6,7,p1=1)]847 elif self.rank == 8:848 return [ 2*self.root(7),849 v2*(self.root(0,1,2,3,4,5,6)+5*self.root(7)),850 v2*(self.root(0,1,2,3,4,5,6,p1=1)+7*self.root(7)),851 self.root(2,3,4,5,6)+5*self.root(7),852 self.root(3,4,5,6)+4*self.root(7),853 self.root(4,5,6)+3*self.root(7),854 self.root(5,6)+2*self.root(7),855 self.root(6,7)]856 857 858 class AmbientLattice_f(AmbientLattice_generic):859 """860 The lattice behind F4. The computations are based on Bourbaki, Groupes et Algebres de Lie,861 Ch. 4,5,6 (planche VIII).862 """863 def __init__(self, ct):864 """865 Create the ambient lattice for the root system for F4.866 Specify the Base, i.e., the simple roots w.r. to the canonical867 basis for $R^4$.868 869 EXAMPLES:870 sage: e = RootSystem(['F',4]).ambient_lattice()871 sage: e == loads(dumps(e))872 True873 """874 v = ZZ(1)/ZZ(2)875 AmbientLattice_generic.__init__(self, ct)876 self.Base = [self.root(1,2,p2=1),877 self.root(2,3,p2=1),878 self.root(3),879 v*(self.root(0)-self.root(1)-self.root(2)-self.root(3))]880 881 def root(self, i, j=None, k=None, l=None, p1=0, p2=0, p3=0, p4=0):882 """883 Compute a root from base elements of the underlying lattice.884 The arguments specify the basis elements and the signs.885 Sadly, the base elements are indexed zero-based.886 We assume that if one of the indices is not given, the rest are not as well.887 888 EXAMPLES:889 sage: F4 = RootSystem(['F',4])890 sage: LF4 = F4.ambient_lattice()891 sage: [ LF4.root(i,j,p2=1) for i in xrange(LF4.n) for j in xrange(i+1,LF4.n) ]892 [(1, -1, 0, 0), (1, 0, -1, 0), (1, 0, 0, -1), (0, 1, -1, 0), (0, 1, 0, -1), (0, 0, 1, -1)]893 """894 if i == j or j == None:895 return (-1)**p1*self._term(i)896 if k == None:897 return (-1)**p1*self._term(i) + (-1)**p2*self._term(j)898 if l == None:899 return (-1)**p1*self._term(i) + (-1)**p2*self._term(j)+(-1)**p3*self._term(k)900 return (-1)**p1*self._term(i) + (-1)**p2*self._term(j)+(-1)**p3*self._term(k)+(-1)**p4*self._term(l)901 902 def simple_roots(self):903 """904 There are computed as what Bourbaki calls the Base:905 a1 = e2-e3, a2 = e3-e4, a3 = e4, a4 = 1/2*(e1-e2-e3-e4)906 907 EXAMPLES:908 sage: LF4 = RootSystem(['F',4]).ambient_lattice()909 sage: LF4.simple_roots()910 [(0, 1, -1, 0), (0, 0, 1, -1), (0, 0, 0, 1), (1/2, -1/2, -1/2, -1/2)]911 """912 return self.Base913 914 def negative_roots(self):915 """916 Returns the negative roots in self.917 918 EXAMPLES:919 sage: LF4 = RootSystem(['F',4]).ambient_lattice()920 sage: LF4.negative_roots()921 [(-1, 0, 0, 0), (0, -1, 0, 0), (0, 0, -1, 0), (0, 0, 0, -1), (-1, -1, 0, 0), (-1, 0, -1, 0), (-1, 0, 0, -1), (0, -1, -1, 0), (0, -1, 0, -1), (0, 0, -1, -1), (-1, 1, 0, 0), (-1, 0, 1, 0), (-1, 0, 0, 1), (0, -1, 1, 0), (0, -1, 0, 1), (0, 0, -1, 1), (-1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2), (-1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, 1/2), (-1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, 1/2)]922 """923 return [ -a for a in self.positive_roots()]924 925 def positive_roots(self):926 """927 These are the roots positive w.r. to lexicographic ordering of the928 basis elements (e1<...<e4).929 930 EXAMPLES:931 sage: LF4 = RootSystem(['F',4]).ambient_lattice()932 sage: LF4.positive_roots()933 [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (1, 1, 0, 0), (1, 0, 1, 0), (1, 0, 0, 1), (0, 1, 1, 0), (0, 1, 0, 1), (0, 0, 1, 1), (1, -1, 0, 0), (1, 0, -1, 0), (1, 0, 0, -1), (0, 1, -1, 0), (0, 1, 0, -1), (0, 0, 1, -1), (1/2, 1/2, 1/2, 1/2), (1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, 1/2), (1/2, 1/2, -1/2, -1/2), (1/2, -1/2, 1/2, 1/2), (1/2, -1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2), (1/2, -1/2, -1/2, -1/2)]934 sage: LF4.rho()935 (11/2, 5/2, 3/2, 1/2)936 """937 v = ZZ(1)/ZZ(2)938 if not hasattr(self, 'PosRoots'):939 self.PosRoots = ([ self._term(i) for i in xrange(self.n) ] +940 [ self.root(i,j,p2=0) for i in xrange(self.n) for j in xrange(i+1,self.n) ] +941 [ self.root(i,j,p2=1) for i in xrange(self.n) for j in xrange(i+1,self.n) ] +942 [ v*self.root(0,1,2,3,0,p2,p3,p4) for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] ])943 return self.PosRoots944 945 def fundamental_weights(self):946 """947 EXAMPLES:948 sage: LF4 = RootSystem(['F',4]).ambient_lattice()949 sage: LF4.fundamental_weights()950 [(1, 1, 0, 0), (2, 1, 1, 0), (3/2, 1/2, 1/2, 1/2), (1, 0, 0, 0)]951 """952 v = ZZ(1)/ZZ(2)953 return [ self._term(0)+self._term(1), 2*self._term(0)+self._term(1)+self._term(2), v*(3*self._term(0)+self._term(1)+self._term(2)+self._term(3)), self._term(0)]954 955 956 class AmbientLattice_g(AmbientLattice_generic):957 """958 TESTS:959 sage: [WeylDim(['G',2],[a,b]) for a,b in [[0,0], [1,0], [0,1], [1,1]]]960 [1, 7, 14, 64]961 """962 def __init__(self, ct):963 """964 EXAMPLES:965 sage: e = RootSystem(['G',2]).ambient_lattice()966 sage: e == loads(dumps(e))967 True968 """969 self.n = 3970 AmbientLattice_generic.__init__(self, ct)971 972 def simple_roots(self):973 """974 EXAMPLES:975 sage: CartanType(['G',2]).root_system().ambient_lattice().simple_roots()976 [(0, 1, -1), (1, -2, 1)]977 """978 return [ self._term(1)-self._term(2),\979 self._term(0)-2*self._term(1)+self._term(2)]980 981 def positive_roots(self):982 """983 EXAMPLES:984 sage: CartanType(['G',2]).root_system().ambient_lattice().positive_roots()985 [(0, 1, -1), (1, -2, 1), (1, -1, 0), (1, 0, -1), (1, 1, -2), (2, -1, -1)]986 """987 return [ c0*self._term(0)+c1*self._term(1)+c2*self._term(2) \988 for [c0,c1,c2] in989 [[0,1,-1],[1,-2,1],[1,-1,0],[1,0,-1],[1,1,-2],[2,-1,-1]]]990 991 def negative_roots(self):992 """993 EXAMPLES:994 sage: CartanType(['G',2]).root_system().ambient_lattice().negative_roots()995 [(0, -1, 1), (-1, 2, -1), (-1, 1, 0), (-1, 0, 1), (-1, -1, 2), (-2, 1, 1)]996 """997 return [ c0*self._term(0)+c1*self._term(1)+c2*self._term(2) \998 for [c0,c1,c2] in999 [[0,-1,1],[-1,2,-1],[-1,1,0],[-1,0,1],[-1,-1,2],[-2,1,1]]]1000 1001 def fundamental_weights(self):1002 """1003 EXAMPLES:1004 sage: CartanType(['G',2]).root_system().ambient_lattice().fundamental_weights()1005 [(1, 0, -1), (2, -1, -1)]1006 """1007 return [ c0*self._term(0)+c1*self._term(1)+c2*self._term(2) \1008 for [c0,c1,c2] in1009 [[1,0,-1],[2,-1,-1]]]1010 1011 406 1012 407 def WeylDim(ct, coeffs): 1013 408 """ … … 1038 433 sage: [WeylDim(['E', 6], x) for x in [0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 2], [0, 0, 0, 0, 1, 0], [0, 0, 1, 0, 0, 0], [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1], [2, 0, 0, 0, 0, 0]] 1039 434 [1, 78, 27, 351, 351, 351, 27, 650, 351] 1040 435 """ 1041 lattice = RootSystem(ct).ambient_lattice() 1042 rank = ct[1] 436 ct = CartanType(ct) 437 lattice = RootSystem(ct).ambient_space() 438 rank = ct.rank() 1043 439 fw = lattice.fundamental_weights() 1044 hwv = sum(coeffs[i]*fw[i] for i in range(min(rank, len(coeffs))))440 hwv = lattice.sum(coeffs[i]*fw[i+1] for i in range(min(rank, len(coeffs)))) 1045 441 return lattice.weyl_dimension(hwv) -
new file sage/combinat/root_system/type_A.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_A.py
- + 1 from ambient_space import AmbientSpace 2 from sage.rings.all import ZZ 3 from sage.combinat.family import Family 4 5 class ambient_space(AmbientSpace): 6 r""" 7 sage: R = RootSystem(["A",3]) 8 sage: R.ambient_space () 9 Ambient space for the Root system of type ['A', 3] 10 """ 11 12 @classmethod 13 def smallest_base_ring(cls): 14 return ZZ; 15 16 def dimension(self): 17 return self.root_system.cartan_type().rank()+1 18 19 def root(self, i, j): 20 """ 21 Note that indexing starts at 0. 22 23 EXAMPLES: 24 sage: e = RootSystem(['A',3]).ambient_lattice() 25 sage: e.root(0,1) 26 (1, -1, 0, 0) 27 """ 28 return self._term(i) - self._term(j) 29 30 def simple_root(self, i): 31 """ 32 EXAMPLES: 33 sage: e = CartanType(['A',3]).root_system().ambient_lattice() 34 sage: e.simple_roots() 35 Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1)} 36 """ 37 return self.root(i-1, i) 38 39 def negative_roots(self): 40 """ 41 EXAMPLES: 42 sage: e = CartanType(['A',3]).root_system().ambient_lattice() 43 sage: e.negative_roots() 44 [(-1, 1, 0, 0), 45 (-1, 0, 1, 0), 46 (-1, 0, 0, 1), 47 (0, -1, 1, 0), 48 (0, -1, 0, 1), 49 (0, 0, -1, 1)] 50 """ 51 res = [] 52 for j in range(self.n-1): 53 for i in range(j+1,self.n): 54 res.append( self.root(i,j) ) 55 return res 56 57 def positive_roots(self): 58 """ 59 EXAMPLES: 60 sage: e = CartanType(['A',3]).root_system().ambient_lattice() 61 sage: e.positive_roots() 62 [(1, -1, 0, 0), 63 (1, 0, -1, 0), 64 (0, 1, -1, 0), 65 (1, 0, 0, -1), 66 (0, 1, 0, -1), 67 (0, 0, 1, -1)] 68 69 """ 70 res = [] 71 for j in range(self.n): 72 for i in range(j): 73 res.append( self.root(i,j) ) 74 return res 75 76 def highest_root(self): 77 """ 78 EXAMPLE: 79 sage: e = CartanType(['A',3]).root_system().ambient_lattice() 80 sage: e.highest_root() 81 (1, 0, 0, -1) 82 """ 83 return self.root(0,self.n-1) 84 85 def fundamental_weight(self, i): 86 """ 87 EXAMPLES: 88 sage: e = CartanType(['A',3]).root_system().ambient_lattice() 89 sage: e.fundamental_weights() 90 Finite family {1: (1, 0, 0, 0), 2: (1, 1, 0, 0), 3: (1, 1, 1, 0)} 91 92 """ 93 return self.sum(self.term(j) for j in range(i)) -
new file sage/combinat/root_system/type_B.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_B.py
- + 1 from ambient_space import AmbientSpace 2 3 class ambient_space(AmbientSpace): 4 def dimension(self): 5 return self.root_system.cartan_type().rank() 6 7 def root(self, i, j): 8 """ 9 Note that indexing starts at 0. 10 11 EXAMPLES: 12 sage: e = RootSystem(['B',3]).ambient_space() 13 sage: e.root(0,1) 14 (1, -1, 0) 15 16 """ 17 return self._term(i) - self._term(j) 18 19 def simple_root(self, i): 20 """ 21 EXAMPLES: 22 sage: e = RootSystem(['B',4]).ambient_space() 23 sage: e.simple_roots() 24 Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1), 4: (0, 0, 0, 1)} 25 sage: e.positive_roots() 26 [(1, -1, 0, 0), 27 (1, 1, 0, 0), 28 (1, 0, -1, 0), 29 (1, 0, 1, 0), 30 (1, 0, 0, -1), 31 (1, 0, 0, 1), 32 (0, 1, -1, 0), 33 (0, 1, 1, 0), 34 (0, 1, 0, -1), 35 (0, 1, 0, 1), 36 (0, 0, 1, -1), 37 (0, 0, 1, 1), 38 (1, 0, 0, 0), 39 (0, 1, 0, 0), 40 (0, 0, 1, 0), 41 (0, 0, 0, 1)] 42 sage: e.fundamental_weights() 43 Finite family {1: (1, 0, 0, 0), 2: (1, 1, 0, 0), 3: (1, 1, 1, 0), 4: (1/2, 1/2, 1/2, 1/2)} 44 """ 45 assert(i in self.index_set()) 46 return self.root(i-1,i) if i < self.n else self._term(self.n-1) 47 48 def negative_roots(self): 49 """ 50 EXAMPLES: 51 sage: RootSystem(['B',3]).ambient_space().negative_roots() 52 [(-1, 1, 0), 53 (-1, -1, 0), 54 (-1, 0, 1), 55 (-1, 0, -1), 56 (0, -1, 1), 57 (0, -1, -1), 58 (-1, 0, 0), 59 (0, -1, 0), 60 (0, 0, -1)] 61 62 """ 63 return [ -a for a in self.positive_roots()] 64 65 66 def positive_roots(self): 67 """ 68 EXAMPLES: 69 sage: RootSystem(['B',3]).ambient_space().positive_roots() 70 [(1, -1, 0), 71 (1, 1, 0), 72 (1, 0, -1), 73 (1, 0, 1), 74 (0, 1, -1), 75 (0, 1, 1), 76 (1, 0, 0), 77 (0, 1, 0), 78 (0, 0, 1)] 79 80 """ 81 res = [] 82 for i in range(self.n-1): 83 for j in range(i+1,self.n): 84 res.append(self._term(i) - self._term(j)) 85 res.append(self._term(i) + self._term(j)) 86 for i in range(self.n): 87 res.append(self._term(i)) 88 return res 89 90 def fundamental_weight(self, i): 91 """ 92 EXAMPLES: 93 sage: RootSystem(['B',3]).ambient_space().fundamental_weights() 94 Finite family {1: (1, 0, 0), 2: (1, 1, 0), 3: (1/2, 1/2, 1/2)} 95 """ 96 assert(i in self.index_set()) 97 n = self.dimension() 98 if i == n: 99 return self.sum( self.term(j) for j in range(n) ) / 2 100 else: 101 return self.sum(self.term(j) for j in range(i)) -
new file sage/combinat/root_system/type_C.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_C.py
- + 1 from ambient_space import AmbientSpace 2 from sage.rings.all import ZZ 3 4 class ambient_space(AmbientSpace): 5 6 # The coroots can't be defined with integer coefficients! 7 # @classmethod 8 # def smallest_base_ring(cls): 9 # return ZZ; 10 11 def dimension(self): 12 return self.root_system.cartan_type().rank() 13 14 def root(self, i, j, p1, p2): 15 """ 16 Note that indexing starts at 0. 17 18 EXAMPLES: 19 sage: e = RootSystem(['C',3]).ambient_space() 20 sage: e.root(0, 1, 1, 1) 21 (-1, -1, 0) 22 """ 23 return (-1)**p1 * self._term(i) + (-1)**p2 * self._term(j) 24 25 def simple_root(self, i): 26 """ 27 EXAMPLES: 28 sage: RootSystem(['C',3]).ambient_space().simple_roots() 29 Finite family {1: (1, -1, 0), 2: (0, 1, -1), 3: (0, 0, 2)} 30 """ 31 assert(i in self.index_set()) 32 return self.root(i-1, i,0,1) if i < self.n else self.root(self.n-1, self.n-1, 0, 0) 33 34 def positive_roots(self): 35 """ 36 EXAMPLES: 37 sage: RootSystem(['C',3]).ambient_space().positive_roots() 38 [(1, 1, 0), 39 (1, 0, 1), 40 (0, 1, 1), 41 (1, -1, 0), 42 (1, 0, -1), 43 (0, 1, -1), 44 (2, 0, 0), 45 (0, 2, 0), 46 (0, 0, 2)] 47 """ 48 res = [] 49 for p in [0,1]: 50 for j in range(self.n): 51 res.extend([self.root(i,j,0,p) for i in range(j)]) 52 res.extend([self.root(i,i,0,0) for i in range(self.n)]) 53 return res 54 55 def negative_roots(self): 56 """ 57 EXAMPLES: 58 sage: RootSystem(['C',3]).ambient_space().negative_roots() 59 [(-1, 1, 0), 60 (-1, 0, 1), 61 (0, -1, 1), 62 (-1, -1, 0), 63 (-1, 0, -1), 64 (0, -1, -1), 65 (-2, 0, 0), 66 (0, -2, 0), 67 (0, 0, -2)] 68 """ 69 res = [] 70 for p in [0,1]: 71 for j in range(self.n): 72 res.extend( [self.root(i,j,1,p) for i in range(j) ] ) 73 res.extend( [ self.root(i,i,1,1) for i in range(self.n) ] ) 74 return res 75 76 77 def fundamental_weight(self, i): 78 """ 79 EXAMPLES: 80 sage: RootSystem(['C',3]).ambient_space().fundamental_weights() 81 Finite family {1: (1, 0, 0), 2: (1, 1, 0), 3: (1, 1, 1)} 82 """ 83 return self.sum(self._term(j) for j in range(i)) -
new file sage/combinat/root_system/type_D.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_D.py
- + 1 from ambient_space import AmbientSpace 2 3 class ambient_space(AmbientSpace): 4 def dimension(self): 5 return self.root_system.cartan_type().rank() 6 7 def root(self, i, j, p1, p2): 8 """ 9 Note that indexing starts at 0. 10 11 EXAMPLES: 12 sage: e = RootSystem(['D',3]).ambient_space() 13 sage: e.root(0, 1, 1, 1) 14 (-1, -1, 0) 15 sage: e.root(0, 0, 1, 1) 16 (-1, 0, 0) 17 18 """ 19 if i != j: 20 return (-1)**p1 * self._term(i) + (-1)**p2 * self._term(j) 21 else: 22 return (-1)**p1 * self._term(i) 23 24 def simple_root(self, i): 25 """ 26 EXAMPLES: 27 sage: RootSystem(['D',4]).ambient_space().simple_roots() 28 Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1), 4: (0, 0, 1, 1)} 29 30 """ 31 assert(i in self.index_set()) 32 return self.root(i-1, i, 0, 1) if i < self.n else self.root(self.n-2, self.n-1, 0, 0) 33 34 def positive_roots(self): 35 """ 36 EXAMPLES: 37 sage: RootSystem(['D',4]).ambient_space().positive_roots() 38 [(1, 1, 0, 0), 39 (1, 0, 1, 0), 40 (0, 1, 1, 0), 41 (1, 0, 0, 1), 42 (0, 1, 0, 1), 43 (0, 0, 1, 1), 44 (1, -1, 0, 0), 45 (1, 0, -1, 0), 46 (0, 1, -1, 0), 47 (1, 0, 0, -1), 48 (0, 1, 0, -1), 49 (0, 0, 1, -1)] 50 51 """ 52 res = [] 53 for p in [0,1]: 54 for j in range(self.n): 55 res.extend([self.root(i,j,0,p) for i in range(j)]) 56 return res 57 58 def negative_roots(self): 59 """ 60 EXAMPLES: 61 sage: RootSystem(['D',4]).ambient_space().negative_roots() 62 [(-1, 1, 0, 0), 63 (-1, 0, 1, 0), 64 (0, -1, 1, 0), 65 (-1, 0, 0, 1), 66 (0, -1, 0, 1), 67 (0, 0, -1, 1), 68 (-1, -1, 0, 0), 69 (-1, 0, -1, 0), 70 (0, -1, -1, 0), 71 (-1, 0, 0, -1), 72 (0, -1, 0, -1), 73 (0, 0, -1, -1)] 74 75 """ 76 res = [] 77 for p in [0,1]: 78 for j in range(self.n): 79 res.extend([self.root(i,j,1,p) for i in range(j)]) 80 return res 81 82 83 def fundamental_weight(self, i): 84 """ 85 EXAMPLES: 86 sage: RootSystem(['D',4]).ambient_space().fundamental_weights() 87 Finite family {1: (1, 0, 0, 0), 2: (1, 1, 0, 0), 3: (1/2, 1/2, 1/2, -1/2), 4: (1/2, 1/2, 1/2, 1/2)} 88 """ 89 assert(i in self.index_set()) 90 n = self.dimension() 91 if i == n: 92 return self.sum(self.term(j) for j in range(n)) / 2 93 elif i == n-1: 94 return (self.sum(self.term(j) for j in range(n-1)) - self._term(n-1)) / 2 95 else: 96 return self.sum(self.term(j) for j in range(i)) -
new file sage/combinat/root_system/type_E.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_E.py
- + 1 from ambient_space import AmbientSpace 2 from sage.rings.all import ZZ 3 from sage.combinat.family import Family 4 5 class ambient_space(AmbientSpace): 6 """ 7 The lattice behind E6, E7, or E8. The computations are based on Bourbaki, 8 Groupes et Algebres de Lie, Ch. 4,5,6 (planche V-VII). 9 """ 10 def dimension(self): 11 return 8; 12 13 def __init__(self, root_system, baseRing): 14 """ 15 Create the ambient space for the root system for E6, E7, E8. 16 Specify the Base, i.e., the simple roots w.r. to the canonical 17 basis for R^8. 18 19 EXAMPLES: 20 sage: e = RootSystem(['E',6]).ambient_space() 21 sage: e == loads(dumps(e)) 22 True 23 sage: [e.weyl_dimension(v) for v in e.fundamental_weights()] 24 [27, 78, 351, 2925, 351, 27] 25 sage: e = RootSystem(['E',7]).ambient_space() 26 sage: [e.weyl_dimension(v) for v in e.fundamental_weights()] 27 [133, 912, 8645, 365750, 27664, 1539, 56] 28 sage: e = RootSystem(['E',8]).ambient_space() 29 sage: [e.weyl_dimension(v) for v in e.fundamental_weights()] 30 [3875, 147250, 6696000, 6899079264, 146325270, 2450240, 30380, 248] 31 """ 32 v = ZZ(1)/ZZ(2) 33 self.rank = root_system.cartan_type().rank() 34 AmbientSpace.__init__(self, root_system, baseRing) 35 if self.rank == 6: 36 self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)), 37 self.root(0,1), 38 self.root(0,1,p1=1), 39 self.root(1,2,p1=1), 40 self.root(2,3,p1=1), 41 self.root(3,4,p1=1)] 42 elif self.rank == 7: 43 self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)), 44 self.root(0,1), 45 self.root(0,1,p1=1), 46 self.root(1,2,p1=1), 47 self.root(2,3,p1=1), 48 self.root(3,4,p1=1), 49 self.root(4,5,p1=1)] 50 elif self.rank == 8: 51 self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)), 52 self.root(0,1), 53 self.root(0,1,p1=1), 54 self.root(1,2,p1=1), 55 self.root(2,3,p1=1), 56 self.root(3,4,p1=1), 57 self.root(4,5,p1=1), 58 self.root(5,6,p1=1)] 59 else: 60 raise NotImplementedError, "Type \'E\' root systems only come in flavors 6, 7, 8. Please make another choice" 61 62 def root(self, i1, i2=None, i3=None, i4=None, i5=None, i6=None, i7=None, i8=None, p1=0, p2=0, p3=0, p4=0, p5=0, p6=0, p7=0, p8=0): 63 """ 64 Compute an element of the underlying lattice, using the specified elements of 65 the standard basis, with signs dictated by the corresponding 'pi' arguments. 66 We rely on the caller to provide the correct arguments. 67 This is typically used to generate roots, although the generated elements 68 need not be roots themselves. 69 We assume that if one of the indices is not given, the rest are not as well. 70 This should work for E6, E7, E8. 71 72 EXAMPLES: 73 sage: E6 = RootSystem(['E',6]) 74 sage: LE6 = E6.ambient_space() 75 sage: [ LE6.root(i,j,p3=1) for i in xrange(LE6.n) for j in xrange(i+1,LE6.n) ] 76 [(1, 1, 0, 0, 0, 0, 0, 0), (1, 0, 1, 0, 0, 0, 0, 0), (1, 0, 0, 1, 0, 0, 0, 0), (1, 0, 0, 0, 1, 0, 0, 0), (1, 0, 0, 0, 0, 1, 0, 0), (1, 0, 0, 0, 0, 0, 1, 0), (1, 0, 0, 0, 0, 0, 0, 1), (0, 1, 1, 0, 0, 0, 0, 0), (0, 1, 0, 1, 0, 0, 0, 0), (0, 1, 0, 0, 1, 0, 0, 0), (0, 1, 0, 0, 0, 1, 0, 0), (0, 1, 0, 0, 0, 0, 1, 0), (0, 1, 0, 0, 0, 0, 0, 1), (0, 0, 1, 1, 0, 0, 0, 0), (0, 0, 1, 0, 1, 0, 0, 0), (0, 0, 1, 0, 0, 1, 0, 0), (0, 0, 1, 0, 0, 0, 1, 0), (0, 0, 1, 0, 0, 0, 0, 1), (0, 0, 0, 1, 1, 0, 0, 0), (0, 0, 0, 1, 0, 1, 0, 0), (0, 0, 0, 1, 0, 0, 1, 0), (0, 0, 0, 1, 0, 0, 0, 1), (0, 0, 0, 0, 1, 1, 0, 0), (0, 0, 0, 0, 1, 0, 1, 0), (0, 0, 0, 0, 1, 0, 0, 1), (0, 0, 0, 0, 0, 1, 1, 0), (0, 0, 0, 0, 0, 1, 0, 1), (0, 0, 0, 0, 0, 0, 1, 1)] 77 """ 78 if i1 == i2 or i2 == None: 79 return (-1)**p1*self._term(i1) 80 if i3 == None: 81 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2) 82 if i4 == None: 83 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3) 84 if i5 == None: 85 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4) 86 if i6 == None: 87 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)+(-1)**p5*self._term(i5) 88 if i7 == None: 89 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)+(-1)**p5*self._term(i5)+(-1)**p6*self._term(i6) 90 if i8 == None: 91 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)+(-1)**p5*self._term(i5)+(-1)**p6*self._term(i6)+(-1)**p7*self._term(i7) 92 return (-1)**p1*self._term(i1) + (-1)**p2*self._term(i2)+(-1)**p3*self._term(i3)+(-1)**p4*self._term(i4)+(-1)**p5*self._term(i5)+(-1)**p6*self._term(i6)+(-1)**p7*self._term(i7)+(-1)**p8*self._term(i8) 93 94 def simple_root(self, i): 95 """ 96 There are computed as what Bourbaki calls the Base: 97 a1 = e2-e3, a2 = e3-e4, a3 = e4, a4 = 1/2*(e1-e2-e3-e4) 98 EXAMPLES: 99 sage: LE6 = RootSystem(['E',6]).ambient_space() 100 sage: LE6.simple_roots() 101 Finite family {1: (1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2), 2: (1, 1, 0, 0, 0, 0, 0, 0), 3: (-1, 1, 0, 0, 0, 0, 0, 0), 4: (0, -1, 1, 0, 0, 0, 0, 0), 5: (0, 0, -1, 1, 0, 0, 0, 0), 6: (0, 0, 0, -1, 1, 0, 0, 0)} 102 """ 103 assert(i in self.index_set()) 104 return self.Base[i-1] 105 106 def negative_roots(self): 107 """ 108 The negative postive roots. 109 EXAMPLES: 110 sage: LE6 = RootSystem(['E',6]).ambient_space() 111 sage: LE6.negative_roots() 112 [(-1, -1, 0, 0, 0, 0, 0, 0), (-1, 0, -1, 0, 0, 0, 0, 0), (-1, 0, 0, -1, 0, 0, 0, 0), (-1, 0, 0, 0, -1, 0, 0, 0), (0, -1, -1, 0, 0, 0, 0, 0), (0, -1, 0, -1, 0, 0, 0, 0), (0, -1, 0, 0, -1, 0, 0, 0), (0, 0, -1, -1, 0, 0, 0, 0), (0, 0, -1, 0, -1, 0, 0, 0), (0, 0, 0, -1, -1, 0, 0, 0), (1, -1, 0, 0, 0, 0, 0, 0), (1, 0, -1, 0, 0, 0, 0, 0), (1, 0, 0, -1, 0, 0, 0, 0), (1, 0, 0, 0, -1, 0, 0, 0), (0, 1, -1, 0, 0, 0, 0, 0), (0, 1, 0, -1, 0, 0, 0, 0), (0, 1, 0, 0, -1, 0, 0, 0), (0, 0, 1, -1, 0, 0, 0, 0), (0, 0, 1, 0, -1, 0, 0, 0), (0, 0, 0, 1, -1, 0, 0, 0), (-1/2, -1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (1/2, -1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (1/2, -1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2)] 113 """ 114 return [ -a for a in self.positive_roots()] 115 116 def positive_roots(self): 117 """ 118 These are the roots positive w.r. to lexicographic ordering of the 119 basis elements (e1<...<e4). 120 EXAMPLES: 121 sage: LE6 = RootSystem(['E',6]).ambient_space() 122 sage: LE6.positive_roots() 123 [(1, 1, 0, 0, 0, 0, 0, 0), (1, 0, 1, 0, 0, 0, 0, 0), (1, 0, 0, 1, 0, 0, 0, 0), (1, 0, 0, 0, 1, 0, 0, 0), (0, 1, 1, 0, 0, 0, 0, 0), (0, 1, 0, 1, 0, 0, 0, 0), (0, 1, 0, 0, 1, 0, 0, 0), (0, 0, 1, 1, 0, 0, 0, 0), (0, 0, 1, 0, 1, 0, 0, 0), (0, 0, 0, 1, 1, 0, 0, 0), (-1, 1, 0, 0, 0, 0, 0, 0), (-1, 0, 1, 0, 0, 0, 0, 0), (-1, 0, 0, 1, 0, 0, 0, 0), (-1, 0, 0, 0, 1, 0, 0, 0), (0, -1, 1, 0, 0, 0, 0, 0), (0, -1, 0, 1, 0, 0, 0, 0), (0, -1, 0, 0, 1, 0, 0, 0), (0, 0, -1, 1, 0, 0, 0, 0), (0, 0, -1, 0, 1, 0, 0, 0), (0, 0, 0, -1, 1, 0, 0, 0), (1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (1/2, 1/2, 1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (1/2, 1/2, -1/2, 1/2, -1/2, -1/2, -1/2, 1/2), (1/2, 1/2, -1/2, -1/2, 1/2, -1/2, -1/2, 1/2), (1/2, -1/2, 1/2, 1/2, -1/2, -1/2, -1/2, 1/2), (1/2, -1/2, 1/2, -1/2, 1/2, -1/2, -1/2, 1/2), (1/2, -1/2, -1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, 1/2, 1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, -1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (-1/2, 1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, 1/2, -1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, -1/2, 1/2, -1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, -1/2, -1/2, 1/2, -1/2, -1/2, 1/2)] 124 sage: LE6.rho() 125 (0, 1, 2, 3, 4, -4, -4, 4) 126 sage: E8=RootSystem(['E',8]) 127 sage: LE8=E8.ambient_space() 128 sage: LE8.negative_roots() 129 [(-1, -1, 0, 0, 0, 0, 0, 0), (-1, 0, -1, 0, 0, 0, 0, 0), (-1, 0, 0, -1, 0, 0, 0, 0), (-1, 0, 0, 0, -1, 0, 0, 0), (-1, 0, 0, 0, 0, -1, 0, 0), (-1, 0, 0, 0, 0, 0, -1, 0), (-1, 0, 0, 0, 0, 0, 0, -1), (0, -1, -1, 0, 0, 0, 0, 0), (0, -1, 0, -1, 0, 0, 0, 0), (0, -1, 0, 0, -1, 0, 0, 0), (0, -1, 0, 0, 0, -1, 0, 0), (0, -1, 0, 0, 0, 0, -1, 0), (0, -1, 0, 0, 0, 0, 0, -1), (0, 0, -1, -1, 0, 0, 0, 0), (0, 0, -1, 0, -1, 0, 0, 0), (0, 0, -1, 0, 0, -1, 0, 0), (0, 0, -1, 0, 0, 0, -1, 0), (0, 0, -1, 0, 0, 0, 0, -1), (0, 0, 0, -1, -1, 0, 0, 0), (0, 0, 0, -1, 0, -1, 0, 0), (0, 0, 0, -1, 0, 0, -1, 0), (0, 0, 0, -1, 0, 0, 0, -1), (0, 0, 0, 0, -1, -1, 0, 0), (0, 0, 0, 0, -1, 0, -1, 0), (0, 0, 0, 0, -1, 0, 0, -1), (0, 0, 0, 0, 0, -1, -1, 0), (0, 0, 0, 0, 0, -1, 0, -1), (0, 0, 0, 0, 0, 0, -1, -1), (1, -1, 0, 0, 0, 0, 0, 0), (1, 0, -1, 0, 0, 0, 0, 0), (1, 0, 0, -1, 0, 0, 0, 0), (1, 0, 0, 0, -1, 0, 0, 0), (1, 0, 0, 0, 0, -1, 0, 0), (1, 0, 0, 0, 0, 0, -1, 0), (1, 0, 0, 0, 0, 0, 0, -1), (0, 1, -1, 0, 0, 0, 0, 0), (0, 1, 0, -1, 0, 0, 0, 0), (0, 1, 0, 0, -1, 0, 0, 0), (0, 1, 0, 0, 0, -1, 0, 0), (0, 1, 0, 0, 0, 0, -1, 0), (0, 1, 0, 0, 0, 0, 0, -1), (0, 0, 1, -1, 0, 0, 0, 0), (0, 0, 1, 0, -1, 0, 0, 0), (0, 0, 1, 0, 0, -1, 0, 0), (0, 0, 1, 0, 0, 0, -1, 0), (0, 0, 1, 0, 0, 0, 0, -1), (0, 0, 0, 1, -1, 0, 0, 0), (0, 0, 0, 1, 0, -1, 0, 0), (0, 0, 0, 1, 0, 0, -1, 0), (0, 0, 0, 1, 0, 0, 0, -1), (0, 0, 0, 0, 1, -1, 0, 0), (0, 0, 0, 0, 1, 0, -1, 0), (0, 0, 0, 0, 1, 0, 0, -1), (0, 0, 0, 0, 0, 1, -1, 0), (0, 0, 0, 0, 0, 1, 0, -1), (0, 0, 0, 0, 0, 0, 1, -1), (-1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, -1/2, -1/2, 1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, -1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, -1/2, 1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, 1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, -1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, -1/2, 1/2, -1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, 1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, -1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, 1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, -1/2, -1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, -1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, 1/2, -1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, -1/2, -1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, 1/2, -1/2, 1/2, -1/2), (-1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, -1/2, -1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, 1/2, -1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2, -1/2), (-1/2, 1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2, -1/2), (1/2, -1/2, -1/2, -1/2, -1/2, 1/2, -1/2, -1/2), (1/2, -1/2, -1/2, -1/2, 1/2, -1/2, -1/2, -1/2), (1/2, -1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2, -1/2, -1/2, -1/2, -1/2), (1/2, -1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2, 1/2, -1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2, 1/2, 1/2, -1/2, -1/2), (1/2, -1/2, 1/2, -1/2, -1/2, -1/2, -1/2, -1/2), (1/2, -1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (1/2, -1/2, 1/2, -1/2, 1/2, -1/2, 1/2, -1/2), (1/2, -1/2, 1/2, -1/2, 1/2, 1/2, -1/2, -1/2), (1/2, -1/2, 1/2, 1/2, -1/2, -1/2, 1/2, -1/2), (1/2, -1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2), (1/2, -1/2, 1/2, 1/2, 1/2, -1/2, -1/2, -1/2), (1/2, -1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2), (1/2, 1/2, -1/2, -1/2, -1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, -1/2, 1/2, -1/2, 1/2, -1/2), (1/2, 1/2, -1/2, -1/2, 1/2, 1/2, -1/2, -1/2), (1/2, 1/2, -1/2, 1/2, -1/2, -1/2, 1/2, -1/2), (1/2, 1/2, -1/2, 1/2, -1/2, 1/2, -1/2, -1/2), (1/2, 1/2, -1/2, 1/2, 1/2, -1/2, -1/2, -1/2), (1/2, 1/2, -1/2, 1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, -1/2, -1/2, -1/2, 1/2, -1/2), (1/2, 1/2, 1/2, -1/2, -1/2, 1/2, -1/2, -1/2), (1/2, 1/2, 1/2, -1/2, 1/2, -1/2, -1/2, -1/2), (1/2, 1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, -1/2, -1/2, -1/2, -1/2), (1/2, 1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, 1/2, -1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2)] 130 sage: LE8.rho() 131 (0, 1, 2, 3, 4, 5, 6, 23) 132 """ 133 v = ZZ(1)/ZZ(2) 134 # Note that 135 if not hasattr(self, 'PosRoots'): 136 if self.rank == 6: 137 self.PosRoots = ( [ self.root(i,j) for i in xrange(self.rank-1) for j in xrange(i+1,self.rank-1) ] + 138 [ self.root(i,j,p1=1) for i in xrange(self.rank-1) for j in xrange(i+1,self.rank-1) ] + 139 [ v*(self.root(7)-self.root(6)-self.root(5)+self.root(0,1,2,3,4,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5)) 140 for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] if (p1+p2+p3+p4+p5)%2 == 0 ]) 141 elif self.rank == 7: 142 self.PosRoots = ( [ self.root(i,j) for i in xrange(self.rank-1) for j in xrange(i+1,self.rank-1) ] + 143 [ self.root(i,j,p1=1) for i in xrange(self.rank-1) for j in xrange(i+1,self.rank-1) ] + 144 [ self.root(6,7,p1=1) ] + 145 [ v*(self.root(7)-self.root(6)+self.root(0,1,2,3,4,5,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5,p6=p6)) 146 for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] if (p1+p2+p3+p4+p5+p6)%2 == 1 ]) 147 elif self.rank == 8: 148 self.PosRoots = ( [ self.root(i,j) for i in xrange(self.rank) for j in xrange(i+1,self.rank) ] + 149 [ self.root(i,j,p1=1) for i in xrange(self.rank) for j in xrange(i+1,self.rank) ] + 150 [ v*(self.root(7)+self.root(0,1,2,3,4,5,6,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5,p6=p6,p7=p7)) 151 for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] for p7 in [0,1] if (p1+p2+p3+p4+p5+p6+p7)%2 == 0 ]) 152 153 return self.PosRoots 154 155 def fundamental_weights(self): 156 """ 157 EXAMPLES: 158 sage: LE6 = RootSystem(['E',6]).ambient_space() 159 sage: LE6.fundamental_weights() 160 Finite family {1: (0, 0, 0, 0, 0, -2/3, -2/3, 2/3), 2: (1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2), 3: (-1/2, 1/2, 1/2, 1/2, 1/2, -5/6, -5/6, 5/6), 4: (0, 0, 1, 1, 1, -1, -1, 1), 5: (0, 0, 0, 1, 1, -2/3, -2/3, 2/3), 6: (0, 0, 0, 0, 1, -1/3, -1/3, 1/3)} 161 """ 162 v2 = ZZ(1)/ZZ(2) 163 v3 = ZZ(1)/ZZ(3) 164 if self.rank == 6: 165 return Family({ 1: 2*v3*self.root(7,6,5,p2=1,p3=1), 166 2: v2*self.root(0,1,2,3,4,5,6,7,p6=1,p7=1), 167 3: 5*v2*v3*self.root(7,6,5,p2=1,p3=1)+v2*self.root(0,1,2,3,4,p1=1), 168 4: self.root(2,3,4,5,6,7,p4=1,p5=1), 169 5: 2*v3*self.root(7,6,5,p2=1,p3=1)+self.root(3,4), 170 6: v3*self.root(7,6,5,p2=1,p3=1)+self.root(4)}) 171 elif self.rank == 7: 172 return Family({ 1: self.root(7,6,p2=1), 173 2: v2*self.root(0,1,2,3,4,5)+self.root(6,7,p1=1), 174 3: v2*(self.root(0,1,2,3,4,5,p1=1)+3*self.root(6,7,p1=1)), 175 4: self.root(2,3,4,5)+2*self.root(6,7,p1=1), 176 5: 3*v2*self.root(6,7,p1=1)+self.root(3,4,5), 177 6: self.root(4,5,6,7,p3=1), 178 7: self.root(5)+v2*self.root(6,7,p1=1)}) 179 elif self.rank == 8: 180 return Family({ 1: 2*self.root(7), 181 2: v2*(self.root(0,1,2,3,4,5,6)+5*self.root(7)), 182 3: v2*(self.root(0,1,2,3,4,5,6,p1=1)+7*self.root(7)), 183 4: self.root(2,3,4,5,6)+5*self.root(7), 184 5: self.root(3,4,5,6)+4*self.root(7), 185 6: self.root(4,5,6)+3*self.root(7), 186 7: self.root(5,6)+2*self.root(7), 187 8: self.root(6,7)}) -
new file sage/combinat/root_system/type_F.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_F.py
- + 1 from ambient_space import AmbientSpace 2 from sage.rings.all import ZZ 3 from sage.combinat.family import Family 4 5 # TODO: double check that this can't be defined over ZZ 6 7 class ambient_space(AmbientSpace): 8 """ 9 The lattice behind F4. The computations are based on Bourbaki, Groupes et Algebres de Lie, 10 Ch. 4,5,6 (planche VIII). 11 """ 12 13 def dimension(self): 14 return self.root_system.cartan_type().rank() 15 16 def __init__(self, root_system, base_ring): 17 """ 18 Create the ambient lattice for the root system for F4. 19 Specify the Base, i.e., the simple roots w.r. to the canonical 20 basis for R^4. 21 22 EXAMPLES: 23 sage: e = RootSystem(['F',4]).ambient_space() 24 sage: e == loads(dumps(e)) 25 True 26 """ 27 AmbientSpace.__init__(self, root_system, base_ring) 28 v = ZZ(1)/ZZ(2) 29 self.Base = [self.root(1,2,p2=1), 30 self.root(2,3,p2=1), 31 self.root(3), 32 v*(self.root(0)-self.root(1)-self.root(2)-self.root(3))] 33 34 def root(self, i, j=None, k=None, l=None, p1=0, p2=0, p3=0, p4=0): 35 """ 36 Compute a root from base elements of the underlying lattice. 37 The arguments specify the basis elements and the signs. 38 Sadly, the base elements are indexed zero-based. 39 We assume that if one of the indices is not given, the rest are not as well. 40 41 EXAMPLES: 42 sage: F4 = RootSystem(['F',4]) 43 sage: LF4 = F4.ambient_space() 44 sage: [ LF4.root(i,j,p2=1) for i in xrange(LF4.n) for j in xrange(i+1,LF4.n) ] 45 [(1, -1, 0, 0), (1, 0, -1, 0), (1, 0, 0, -1), (0, 1, -1, 0), (0, 1, 0, -1), (0, 0, 1, -1)] 46 """ 47 if i == j or j == None: 48 return (-1)**p1*self._term(i) 49 if k == None: 50 return (-1)**p1*self._term(i) + (-1)**p2*self._term(j) 51 if l == None: 52 return (-1)**p1*self._term(i) + (-1)**p2*self._term(j)+(-1)**p3*self._term(k) 53 return (-1)**p1*self._term(i) + (-1)**p2*self._term(j)+(-1)**p3*self._term(k)+(-1)**p4*self._term(l) 54 55 def simple_root(self, i): 56 """ 57 There are computed as what Bourbaki calls the Base: 58 a1 = e2-e3, a2 = e3-e4, a3 = e4, a4 = 1/2*(e1-e2-e3-e4) 59 60 EXAMPLES: 61 sage: LF4 = RootSystem(['F',4]).ambient_space() 62 sage: LF4.simple_roots() 63 Finite family {1: (0, 1, -1, 0), 2: (0, 0, 1, -1), 3: (0, 0, 0, 1), 4: (1/2, -1/2, -1/2, -1/2)} 64 """ 65 return self.Base[i-1] 66 67 def negative_roots(self): 68 """ 69 Returns the negative roots in self. 70 71 EXAMPLES: 72 sage: LF4 = RootSystem(['F',4]).ambient_space() 73 sage: LF4.negative_roots() 74 [(-1, 0, 0, 0), (0, -1, 0, 0), (0, 0, -1, 0), (0, 0, 0, -1), (-1, -1, 0, 0), (-1, 0, -1, 0), (-1, 0, 0, -1), (0, -1, -1, 0), (0, -1, 0, -1), (0, 0, -1, -1), (-1, 1, 0, 0), (-1, 0, 1, 0), (-1, 0, 0, 1), (0, -1, 1, 0), (0, -1, 0, 1), (0, 0, -1, 1), (-1/2, -1/2, -1/2, -1/2), (-1/2, -1/2, -1/2, 1/2), (-1/2, -1/2, 1/2, -1/2), (-1/2, -1/2, 1/2, 1/2), (-1/2, 1/2, -1/2, -1/2), (-1/2, 1/2, -1/2, 1/2), (-1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, 1/2)] 75 """ 76 return [ -a for a in self.positive_roots()] 77 78 def positive_roots(self): 79 """ 80 These are the roots positive w.r. to lexicographic ordering of the 81 basis elements (e1<...<e4). 82 83 EXAMPLES: 84 sage: LF4 = RootSystem(['F',4]).ambient_space() 85 sage: LF4.positive_roots() 86 [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (1, 1, 0, 0), (1, 0, 1, 0), (1, 0, 0, 1), (0, 1, 1, 0), (0, 1, 0, 1), (0, 0, 1, 1), (1, -1, 0, 0), (1, 0, -1, 0), (1, 0, 0, -1), (0, 1, -1, 0), (0, 1, 0, -1), (0, 0, 1, -1), (1/2, 1/2, 1/2, 1/2), (1/2, 1/2, 1/2, -1/2), (1/2, 1/2, -1/2, 1/2), (1/2, 1/2, -1/2, -1/2), (1/2, -1/2, 1/2, 1/2), (1/2, -1/2, 1/2, -1/2), (1/2, -1/2, -1/2, 1/2), (1/2, -1/2, -1/2, -1/2)] 87 sage: LF4.rho() 88 (11/2, 5/2, 3/2, 1/2) 89 """ 90 v = ZZ(1)/ZZ(2) 91 if not hasattr(self, 'PosRoots'): 92 self.PosRoots = ([ self._term(i) for i in xrange(self.n) ] + 93 [ self.root(i,j,p2=0) for i in xrange(self.n) for j in xrange(i+1,self.n) ] + 94 [ self.root(i,j,p2=1) for i in xrange(self.n) for j in xrange(i+1,self.n) ] + 95 [ v*self.root(0,1,2,3,0,p2,p3,p4) for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] ]) 96 return self.PosRoots 97 98 def fundamental_weights(self): 99 """ 100 EXAMPLES: 101 sage: LF4 = RootSystem(['F',4]).ambient_space() 102 sage: LF4.fundamental_weights() 103 Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)} 104 """ 105 v = ZZ(1)/ZZ(2) 106 return Family({ 1: self._term(0)+self._term(1), 107 2: 2*self._term(0)+self._term(1)+self._term(2), 108 3: v*(3*self._term(0)+self._term(1)+self._term(2)+self._term(3)), 109 4: self._term(0)}) -
new file sage/combinat/root_system/type_G.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_G.py
- + 1 from ambient_space import AmbientSpace 2 from sage.combinat.family import Family 3 4 # TODO: check whether this can be defined over ZZ 5 6 class ambient_space(AmbientSpace): 7 """ 8 TESTS: 9 sage: [WeylDim(['G',2],[a,b]) for a,b in [[0,0], [1,0], [0,1], [1,1]]] 10 [1, 7, 14, 64] 11 12 EXAMPLES: 13 sage: e = RootSystem(['G',2]).ambient_space() 14 sage: e == loads(dumps(e)) 15 True 16 """ 17 18 def dimension(self): 19 return 3 20 21 def simple_root(self, i): 22 """ 23 EXAMPLES: 24 sage: CartanType(['G',2]).root_system().ambient_space().simple_roots() 25 Finite family {1: (0, 1, -1), 2: (1, -2, 1)} 26 """ 27 return self._term(1)-self._term(2) if i == 1 else self._term(0)-2*self._term(1)+self._term(2) 28 29 def positive_roots(self): 30 """ 31 EXAMPLES: 32 sage: CartanType(['G',2]).root_system().ambient_space().positive_roots() 33 [(0, 1, -1), (1, -2, 1), (1, -1, 0), (1, 0, -1), (1, 1, -2), (2, -1, -1)] 34 """ 35 return [ self(v) for v in 36 [[0,1,-1],[1,-2,1],[1,-1,0],[1,0,-1],[1,1,-2],[2,-1,-1]]] 37 38 def negative_roots(self): 39 """ 40 EXAMPLES: 41 sage: CartanType(['G',2]).root_system().ambient_space().negative_roots() 42 [(0, -1, 1), (-1, 2, -1), (-1, 1, 0), (-1, 0, 1), (-1, -1, 2), (-2, 1, 1)] 43 """ 44 return [ self(v) for v in 45 [[0,-1,1],[-1,2,-1],[-1,1,0],[-1,0,1],[-1,-1,2],[-2,1,1]]] 46 47 def fundamental_weights(self): 48 """ 49 EXAMPLES: 50 sage: CartanType(['G',2]).root_system().ambient_space().fundamental_weights() 51 Finite family {1: (1, 0, -1), 2: (2, -1, -1)} 52 """ 53 return Family({ 1: self([1,0,-1]), 54 2: self([2,-1,-1])}) -
new file sage/combinat/root_system/type_None.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_None.py
- + 1 -
new file sage/combinat/root_system/type_dual.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_dual.py
- + 1 from sage.combinat.root_system.cartan_type import CartanType_abstract 2 3 class CartanType(CartanType_abstract): 4 r""" 5 A class for dual Cartan types 6 7 The dual of a cartan type is a cartan type with the same index 8 set, but all arrows reversed in the Dynkin diagram (otherwise 9 said, the Cartan matrix is transposed). It shares a lot of 10 properties in common with its dual. In particular, the Weyl group 11 is isomorphic to that of the dual as a Coxeter group. 12 """ 13 14 def __init__(self, type): 15 """ 16 INPUT: 17 type -- a Cartan type 18 19 EXAMPLES: 20 sage: ct = CartanType(['F',4]).dual() 21 sage: ct == loads(dumps(ct)) 22 True 23 """ 24 self._dual = type 25 26 def __repr__(self): 27 """ 28 EXAMPLES: 29 sage: ct = CartanType(['F', 4]).dual() 30 sage: ct 31 ['F', 4]^* 32 """ 33 return self.dual().__repr__()+"^*" 34 35 def __cmp__(self, other): 36 """ 37 EXAMPLES: 38 sage: ct1 = CartanType(['A',1],['B',2]) 39 sage: ct2 = CartanType(['B',2],['A',1]) 40 sage: ct3 = CartanType(['A',4]) 41 sage: ct = [ct1, ct2, ct3] 42 sage: [[x.__cmp__(y) for x in ct] for y in ct] 43 [[0, 1, -1], [-1, 0, -1], [1, 1, 0]] 44 sage: sorted(ct) 45 [['A', 4], A1xB2, B2xA1] 46 """ 47 if other.__class__ != self.__class__: 48 return cmp(self.__class__, other.__class__) 49 return cmp(self._dual, other._dual) 50 51 def dual(self): 52 return self._dual 53 54 def is_irreducible(self): 55 return self._dual.is_irreducible() 56 57 def is_finite(self): 58 return self._dual.is_finite() 59 60 def is_crystalographic(self): 61 return self._dual.is_crystalographic 62 63 def is_affine(self): 64 return self._dual.is_affine() 65 66 def rank(self): 67 return self._dual.rank() 68 69 def index_set(self): 70 return self._dual.index_set() 71 72 def dynkin_diagram(self): 73 return self._dual.dynkin_diagram().dual() 74 75 #class ambient_space(AmbientSpace): 76 # todo? -
new file sage/combinat/root_system/type_reducible.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/type_reducible.py
- + 1 from sage.combinat.root_system.cartan_type import CartanType_abstract, CartanType_simple 2 from sage.misc.flatten import flatten 3 from sage.matrix.constructor import block_diagonal_matrix 4 from ambient_space import AmbientSpace 5 6 class CartanType(CartanType_abstract): 7 r""" 8 A class for reducible Cartan types 9 """ 10 11 def __init__(self, types): 12 """ 13 INPUT: 14 types -- a list of simple Cartan types 15 Reducible root systems are ones that can be factored as 16 direct products. Strictly speaking type D2 (corresponding 17 to orthogonal groups of degree 4) are reducible since they 18 are isomorphic to A1xA1. However type D2 is considered 19 irreducible for our purposes. 20 EXAMPLES: 21 sage: [t1,t2]=[CartanType(x) for x in ['A',1],['B',2]] 22 sage: CartanType([t1,t2]) 23 A1xB2 24 sage: t = CartanType("A2xB2") 25 sage: t == loads(dumps(t)) 26 True 27 """ 28 self._types = types 29 self.affine = False 30 self._spaces = [t.root_system().ambient_space() for t in types] 31 self._shifts = [sum(l.n for l in self._spaces[:k]) for k in range(len(types))] 32 self._rshifts = [sum(l[1] for l in types[:k]) for k in range(len(types))] 33 34 def __repr__(self): 35 """ 36 EXAMPLES: 37 sage: ct = CartanType("A2","B2") 38 sage: repr(ct) 39 'A2xB2' 40 """ 41 names = [t[0]+str(t[1]) for t in self._types] 42 return names[0]+"".join(flatten([["x",t] for t in names[1:]])) 43 44 def __cmp__(self, other): 45 """ 46 EXAMPLES: 47 sage: ct1 = CartanType(['A',1],['B',2]) 48 sage: ct2 = CartanType(['B',2],['A',1]) 49 sage: ct3 = CartanType(['A',4]) 50 sage: ct = [ct1, ct2, ct3] 51 sage: [[x.__cmp__(y) for x in ct] for y in ct] 52 [[0, 1, -1], [-1, 0, -1], [1, 1, 0]] 53 sage: sorted(ct) 54 [['A', 4], A1xB2, B2xA1] 55 """ 56 if isinstance(other, CartanType_simple): 57 return 1 58 if len(self._types) < len(other._types): 59 return -1 60 if len(self._types) > len(other._types): 61 return 1 62 for i in range(len(self._types)): 63 if self._types[i] != other._types[i]: 64 return self._types[i].__cmp__(other._types[i]) 65 return 0 66 67 def component_types(self): 68 """ 69 A list of Cartan types making up the reducible type 70 EXAMPLES: 71 sage: CartanType(['A',2],['B',2]).component_types() 72 [['A', 2], ['B', 2]] 73 """ 74 return self._types 75 76 def type(self): 77 """ 78 Returns "reducible" since the type is reducible 79 """ 80 return "reducible" 81 82 def is_finite(self): 83 return all(t.is_finite() for t in self.component_types()) 84 85 def rank(self): 86 """ 87 Returns the rank of self. 88 EXAMPLES: 89 sage: CartanType("A2","A1").rank() 90 3 91 """ 92 return sum(t.rank() for t in self._types) 93 94 def root_system(self): 95 """ 96 Returns the root system associated to self. 97 98 EXAMPLES: 99 sage: CartanType(['A',4]).root_system() 100 Root system of type ['A', 4] 101 """ 102 return root_system.RootSystem(self) 103 104 def cartan_matrix(self, subdivide=True): 105 """ 106 Returns the Cartan matrix associated with self. By default 107 the Cartan matrix is a subdivided block matrix showing the 108 reducibility but the subdivision can be suppressed with 109 the option subdivide=False. 110 111 EXAMPLES: 112 sage: ct = CartanType("A2","B2") 113 sage: ct.cartan_matrix() 114 [ 2 -1| 0 0] 115 [-1 2| 0 0] 116 [-----+-----] 117 [ 0 0| 2 -1] 118 [ 0 0|-2 2] 119 sage: ct.cartan_matrix(subdivide=False) 120 [ 2 -1 0 0] 121 [-1 2 0 0] 122 [ 0 0 2 -1] 123 [ 0 0 -2 2] 124 """ 125 return block_diagonal_matrix([t.cartan_matrix() for t in self._types], subdivide=subdivide) 126 127 def is_irreducible(self): 128 """ 129 Report that this Cartan type is not irreducible 130 """ 131 return False 132 133 def dual(self): 134 """ 135 EXAMPLE: 136 sage: CartanType("A2xB2").dual() 137 A2xC2 138 """ 139 return CartanType([t.dual() for t in self._types]) 140 141 def type_string(self): 142 """ 143 EXAMPLE: 144 sage: CartanType(['A',2],['B',2]).type_string() 145 'type_reducible' 146 """ 147 return "type_reducible" 148 149 def is_affine(self): 150 """ 151 Report that this reducible Cartan type is not affine 152 """ 153 return False 154 155 156 class ambient_space(AmbientSpace): 157 """ 158 EXAMPLES: 159 sage: RootSystem("A2xB2").ambient_space() 160 Ambient space for the Root system of type A2xB2 161 """ 162 def cartan_type(self): 163 """ 164 EXAMPLES: 165 sage: RootSystem("A2xB2").ambient_space().cartan_type() 166 A2xB2 167 """ 168 return self.root_system.cartan_type() 169 170 def component_types(self): 171 """ 172 EXAMPLES: 173 sage: RootSystem("A2xB2").ambient_space().component_types() 174 [['A', 2], ['B', 2]] 175 """ 176 return self.root_system.cartan_type().component_types() 177 178 def dimension(self): 179 """ 180 EXAMPLES: 181 sage: RootSystem("A2xB2").ambient_space().dimension() 182 5 183 """ 184 return sum(v.dimension() for v in self.ambient_spaces()) 185 186 def ambient_spaces(self): 187 """ 188 Returns a list of the irreducible Cartan types of which the 189 given reducible Cartan type is a product. 190 191 EXAMPLES: 192 sage: RootSystem("A2xB2").ambient_space().ambient_spaces() 193 [Ambient space for the Root system of type ['A', 2], 194 Ambient space for the Root system of type ['B', 2]] 195 """ 196 return [t.root_system().ambient_space() for t in self.component_types()] 197 198 def inject_weights(self, i, v): 199 """ 200 INPUT: 201 i -- an integer in range(self.components) 202 v -- a vector in the i-th component weight lattice 203 Produces the corresponding element of the lattice. 204 EXAMPLES: 205 sage: V = RootSystem("A2xB2").ambient_space() 206 sage: [V.inject_weights(i,V.ambient_spaces()[i].fundamental_weights()[1]) for i in range(2)] 207 [(1, 0, 0, 0, 0), (0, 0, 0, 1, 0)] 208 sage: [V.inject_weights(i,V.ambient_spaces()[i].fundamental_weights()[2]) for i in range(2)] 209 [(1, 1, 0, 0, 0), (0, 0, 0, 1/2, 1/2)] 210 """ 211 shift = self.root_system.cartan_type()._shifts[i] 212 return self._from_dict( dict([(shift+k, c) for (k,c) in v ])) 213 214 def simple_roots(self): 215 """ 216 EXAMPLES: 217 sage: RootSystem("A1xA2").ambient_space().simple_roots() 218 [(1, -1, 0, 0, 0), (0, 0, 1, -1, 0), (0, 0, 0, 1, -1)] 219 """ 220 ret = [] 221 for i in range(len(self.component_types())): 222 ret.extend(self.inject_weights(i, v) for v in self.ambient_spaces()[i].simple_roots()) 223 return ret 224 225 def positive_roots(self): 226 """ 227 EXAMPLE: 228 sage: RootSystem("A1xA2").ambient_space().positive_roots() 229 [(1, -1, 0, 0, 0), (0, 0, 1, -1, 0), (0, 0, 1, 0, -1), (0, 0, 0, 1, -1)] 230 """ 231 ret = [] 232 for i in range(len(self.component_types())): 233 ret.extend(self.inject_weights(i, v) for v in self.ambient_spaces()[i].positive_roots()) 234 return ret 235 236 def negative_roots(self): 237 """ 238 EXAMPLE: 239 sage: RootSystem("A1xA2").ambient_space().negative_roots() 240 [(-1, 1, 0, 0, 0), (0, 0, -1, 1, 0), (0, 0, -1, 0, 1), (0, 0, 0, -1, 1)] 241 """ 242 ret = [] 243 for i in range(len(self.component_types())): 244 ret.extend(self.inject_weights(i, v) for v in self.ambient_spaces()[i].negative_roots()) 245 return ret 246 247 def fundamental_weights(self): 248 """ 249 EXAMPLE: 250 sage: RootSystem("A2xB2").ambient_space().fundamental_weights() 251 [(1, 0, 0, 0, 0), (1, 1, 0, 0, 0), (0, 0, 0, 1, 0), (0, 0, 0, 1/2, 1/2)] 252 """ 253 ret = [] 254 for i in range(len(self.component_types())): 255 ret.extend(self.inject_weights(i, v) for v in self.ambient_spaces()[i].fundamental_weights()) 256 return ret -
new file sage/combinat/root_system/weight_lattice_realization.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/weight_lattice_realization.py
- + 1 from sage.misc.misc import prod 2 from sage.combinat.family import Family 3 from root_lattice_realization import RootLatticeRealization 4 5 class WeightLatticeRealization (RootLatticeRealization): 6 7 def check(self): 8 RootLatticeRealization.check(self) 9 Lambda = self.fundamental_weights() 10 alphacheck = self.simple_coroots() 11 12 for i in self.index_set(): 13 assert(Lambda[i].is_dominant()) 14 for j in self.index_set(): 15 assert(Lambda[j].scalar(alphacheck[i]) == (1 if i==j else 0)) 16 17 assert(self.rho().is_dominant()) 18 assert(self.highest_root().is_dominant()) 19 20 # Should this be a method or an attribute? 21 # same question for the roots, ... 22 def fundamental_weights(self): 23 """ 24 Returns the family $(\Lambda_i)_{i\in I}$ of the fundamental weights 25 """ 26 if not hasattr(self,"_fundamental_weights"): 27 self._fundamental_weights = Family(self.index_set(), 28 self.fundamental_weight, 29 name = "Lambda") 30 return self._fundamental_weights 31 32 def rho(self): 33 """ 34 EXAMPLES: 35 sage: RootSystem(['A',3]).ambient_lattice().rho() 36 (3, 2, 1, 0) 37 """ 38 return sum(self.fundamental_weights()) 39 40 # Should it be a method of highest_weight? 41 def weyl_dimension(self, highest_weight): 42 """ 43 EXAMPLES: 44 sage: RootSystem(['A',3]).ambient_lattice().weyl_dimension([2,1,0,0]) 45 20 46 """ 47 highest_weight = self(highest_weight) 48 assert(highest_weight.is_dominant()) 49 rho = self.rho() 50 n = prod([(rho+highest_weight).dot_product(x) for x in self.positive_roots()]) 51 d = prod([ rho.dot_product(x) for x in self.positive_roots()]) 52 return n/d 53 -
new file sage/combinat/root_system/weight_space.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/weight_space.py
- + 1 #***************************************************************************** 2 # Copyright (C) 2007 Nicolas M. Thiery <nthiery at users.sf.net> 3 # 4 # Distributed under the terms of the GNU General Public License (GPL) 5 # 6 # This code is distributed in the hope that it will be useful, 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 # General Public License for more details. 10 # 11 # The full text of the GPL is available at: 12 # 13 # http://www.gnu.org/licenses/ 14 #***************************************************************************** 15 16 from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement 17 from sage.combinat.family import Family 18 from root_lattice_realization import RootLatticeRealizationElement 19 from weight_lattice_realization import WeightLatticeRealization 20 from sage.rings.all import ZZ 21 22 23 class WeightSpace(CombinatorialFreeModule, WeightLatticeRealization): 24 25 def __init__(self, root_system, base_ring): 26 self.root_system = root_system 27 basis_name = "Lambdacheck" if root_system.dualSide else "Lambda" 28 CombinatorialFreeModule.__init__(self, base_ring,\ 29 root_system.index_set(),\ 30 element_class = WeightSpaceElement,\ 31 prefix=basis_name) 32 33 def __repr__(self): 34 """ 35 TEST: 36 sage: RootSystem(['A',4]).weight_lattice() 37 The weight lattice of the Root system of type ['A', 4] 38 sage: RootSystem(['B',4]).weight_space() 39 The weight space over the Rational Field of the Root system of type ['B', 4] 40 sage: RootSystem(['A',4]).coweight_lattice() 41 The coweight lattice of the Root system of type ['A', 4] 42 sage: RootSystem(['B',4]).coweight_space() 43 The coweight space over the Rational Field of the Root system of type ['B', 4] 44 45 """ 46 return "The %s"%self.root_system.dualString+\ 47 ("weight lattice " if self.base_ring() == ZZ else "weight space over the %s "%self.base_ring())+\ 48 "of the %s"%(self.root_system.dual if self.root_system.dualSide else self.root_system) 49 50 fundamental_weights = CombinatorialFreeModule.basis 51 52 def simple_root(self, j): 53 """ 54 Returns the $j$-th simple root 55 56 TESTS: 57 sage: R = RootSystem(["C",4]) 58 sage: R.weight_lattice().simple_root(3) 59 -Lambda[2] + 2*Lambda[3] - Lambda[4] 60 61 sage: R.weight_lattice().simple_roots() 62 Finite family {1: 2*Lambda[1] - Lambda[2], 2: -Lambda[1] + 2*Lambda[2] - Lambda[3], 3: -Lambda[2] + 2*Lambda[3] - Lambda[4], 4: -2*Lambda[3] + 2*Lambda[4]} 63 64 """ 65 assert(j in self.index_set()) 66 return self._from_dict(dict([(i,c) for (i,c) in self.root_system.dynkin_diagram().column(j)])) 67 68 69 class WeightSpaceElement(CombinatorialFreeModuleElement, RootLatticeRealizationElement): 70 71 def scalar(self, lambdacheck): 72 """ 73 The canonical scalar product between the weight lattice and 74 the coroot lattice. 75 76 TODO: merge with_apply_multi_module_morphism 77 """ 78 zero = self.parent().base_ring().zero_element() 79 if len(self) < len(lambdacheck): 80 return sum( (lambdacheck[i]*c for (i,c) in self), zero) 81 else: 82 return sum( (self[i]*c for (i,c) in lambdacheck), zero) -
sage/combinat/root_system/weyl_characters.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/weyl_characters.py
a b 56 56 weight vector. 57 57 58 58 EXAMPLES: 59 sage: L = RootSystem(['A',2]).ambient_ lattice()59 sage: L = RootSystem(['A',2]).ambient_space() 60 60 sage: [fw1,fw2] = L.fundamental_weights() 61 61 sage: R = WeylCharacterRing(['A',2], prefix="R") 62 62 sage: [R(1),R(fw1),R(fw2)] … … 112 112 if self._hdict == {}: 113 113 return "0" 114 114 v = self._hdict.keys() 115 v.sort() 115 # Just a workaround to keep the same sorting as before when 116 # the dictionary was indexed by tuples 117 v.sort(key = lambda v: tuple(v.to_vector())) 116 118 return repr_lincomb([self._parent.irr_repr(k) for k in v], [self._hdict[k] for k in v]) 117 119 118 120 def __cmp__(self, right): … … 207 209 sage: [F4(x).check(verbose = true) for x in F4.lattice().fundamental_weights()] 208 210 [[52, 52], [1274, 1274], [273, 273], [26, 26]] 209 211 """ 210 theoretical = sum(self._hdict[k]*self._lattice.weyl_dimension( self._parent.VS(k)) for k in self._hdict)212 theoretical = sum(self._hdict[k]*self._lattice.weyl_dimension(k) for k in self._hdict) 211 213 practical = sum(self._mdict[k] for k in self._mdict) 212 214 if verbose: 213 215 return [theoretical, practical] … … 228 230 mdict = {} 229 231 for k in self._mdict: 230 232 for l in y._mdict: 231 m = tuple(self._parent.VS(k)+self._parent.VS(l))233 m = k+l 232 234 if m in mdict: 233 235 mdict[m] += self._mdict[k]*y._mdict[l] 234 236 else: … … 300 302 sage: B3(1/2,1/2,1/2).hlist() 301 303 [[(1/2, 1/2, 1/2), 1]] 302 304 """ 303 return [[ self._parent.VS(k),m] for k,m in self._hdict.iteritems()]305 return [[k,m] for k,m in self._hdict.iteritems()] 304 306 305 307 def mlist(self): 306 308 """ … … 309 311 EXAMPLES: 310 312 sage: B3 = WeylCharacterRing(['B',3]) 311 313 sage: B3(1/2,1/2,1/2).mlist() 312 [[(1/2, 1/2, 1/2), 1], 313 [(-1/2, 1/2, -1/2), 1], 314 [(-1/2, -1/2, -1/2), 1], 315 [(1/2, -1/2, 1/2), 1], 316 [(-1/2, 1/2, 1/2), 1], 317 [(1/2, -1/2, -1/2), 1], 318 [(-1/2, -1/2, 1/2), 1], 319 [(1/2, 1/2, -1/2), 1]] 314 [[(1/2, -1/2, -1/2), 1], [(-1/2, 1/2, -1/2), 1], [(1/2, 1/2, 1/2), 1], [(1/2, 1/2, -1/2), 1], [(-1/2, -1/2, 1/2), 1], [(-1/2, -1/2, -1/2), 1], [(1/2, -1/2, 1/2), 1], [(-1/2, 1/2, 1/2), 1]] 315 316 # Why did the test not pass with the following indentation? 317 # [[( 1/2, -1/2, -1/2), 1], 318 # [(-1/2, 1/2, -1/2), 1], 319 # [( 1/2, 1/2, 1/2), 1], 320 # [( 1/2, 1/2, -1/2), 1], 321 # [(-1/2, -1/2, 1/2), 1], 322 # [(-1/2, -1/2, -1/2), 1], 323 # [( 1/2, -1/2, 1/2), 1], 324 # [(-1/2, 1/2, 1/2), 1]] 320 325 """ 321 return [[ self._parent.VS(k),m] for k,m in self._mdict.iteritems()]326 return [[k,m] for k,m in self._mdict.iteritems()] 322 327 323 328 def parent(self): 324 329 """ … … 369 374 370 375 EXAMPLES: 371 376 sage: R = WeylCharacterRing(['B',3], prefix='R') 372 sage: chi = R(R.lattice().fundamental_weights()[ 2]); chi377 sage: chi = R(R.lattice().fundamental_weights()[3]); chi 373 378 R(1/2,1/2,1/2) 374 379 sage: R(1/2,1/2,1/2) == chi 375 380 True … … 407 412 EXAMPLES: 408 413 sage: R = WeylCharacterRing(['A',2], prefix = R) 409 414 sage: R([2,1,0]).mlist() 410 [[( 2, 1, 0), 1],411 [(0, 1, 2), 1],412 [(1, 1, 1), 2],413 [(0, 2, 1), 1],414 [(2, 0, 1), 1],415 [(1, 2, 0), 1],416 [(1, 0, 2), 1]]415 [[(1, 0, 2), 1], 416 [(1, 1, 1), 2], 417 [(2, 1, 0), 1], 418 [(1, 2, 0), 1], 419 [(2, 0, 1), 1], 420 [(0, 1, 2), 1], 421 [(0, 2, 1), 1]] 417 422 418 423 419 424 """ 420 425 ct = cartan_type.CartanType(ct) 421 426 return cache_wcr(ct, base_ring=base_ring, prefix=prefix, cache=cache) 427 428 # TODO: inherit all the data structure from CombinatorialFreeModule(base_ring, self._lattice) 422 429 423 430 class WeylCharacterRing_class(Algebra): 424 431 def __init__(self, ct, base_ring, prefix, cache): … … 432 439 433 440 self.cartan_type = ct 434 441 self._base_ring = base_ring 435 self._lattice = RootSystem(self.cartan_type).ambient_lattice() 436 self._origin = tuple(self._lattice._free_module(0)) 437 self.VS = VectorSpace(QQ, self._lattice.n) 442 self._lattice = RootSystem(self.cartan_type).ambient_space() 443 self._origin = self._lattice.zero() 438 444 if prefix == None: 439 445 prefix = ct[0]+str(ct[1]) 440 446 self._prefix = prefix 441 self._ip = [self._lattice.fundamental_weights()[i].inner_product(self._lattice.simple_roots()[i]) 442 for i in range(ct[1])] 447 alpha = self._lattice.simple_roots() 448 Lambda = self._lattice.fundamental_weights() 449 # FIXME: indexing of fundamental weights 450 self._ip = [Lambda[i].inner_product(alpha[i]) 451 for i in ct.index_set()] 443 452 self._cache = cache 444 453 if cache: 445 454 self._irreducibles={} … … 495 504 elif x in self.base_ring(): 496 505 hdict = {self._origin: x} 497 506 return WeylCharacter(self, hdict, hdict) 507 508 x = self._lattice(x) 498 509 499 x = self.VS(x)500 vp = [ QQ(x.inner_product(self._lattice.simple_roots()[i]))/QQ(self._ip[i])501 for i in range(self.cartan_type[1])]510 alphacheck = self._lattice.simple_coroots() 511 vp = [x.inner_product(alphacheck[i]) 512 for i in self.cartan_type.index_set()] 502 513 if not all(v in ZZ for v in vp): 503 514 raise ValueError, "not in weight lattice" 504 515 if not all(v >= 0 for v in vp): 505 516 raise ValueError, "the weight%s is not dominant"%x.__repr__() 506 if self._cache and tuple(x)in self._irreducibles:507 return self._irreducibles[ tuple(x)]508 hdict = { tuple(x): 1}517 if self._cache and x in self._irreducibles: 518 return self._irreducibles[x] 519 hdict = {x: 1} 509 520 mdict = irreducible_character_freudenthal(x, self._lattice) 510 521 ret = WeylCharacter(self, hdict, mdict) 511 522 if self._cache: 512 self._irreducibles[ tuple(x)] = ret523 self._irreducibles[x] = ret 513 524 return ret 514 525 515 526 def __repr__(self): … … 557 568 return self.__call__(x) 558 569 raise TypeError, "no canonical coercion of x" 559 570 571 # FIXME: should be something like weight_lattice_realization? 560 572 def lattice(self): 561 573 """ 562 574 Returns the weight lattice associated to self. 563 575 564 576 EXAMPLES: 565 577 sage: WeylCharacterRing(['E',8]).lattice() 566 Ambient lattice of the root system of type ['E', 8]578 Ambient space for the Root system of type ['E', 8] 567 579 """ 568 580 return self._lattice 569 581 … … 583 595 hdict = {} 584 596 ddict = mdict.copy() 585 597 while not ddict == {}: 586 highest = max((self.VS(x).inner_product(self._lattice.rho()),x) for x in ddict)[1] 587 hvect = self.VS(highest) 588 if not self._lattice.is_dominant(hvect): 598 highest = max((x.inner_product(self._lattice.rho()),x) for x in ddict)[1] 599 if not highest.is_dominant(): 589 600 raise ValueError, "multiplicity dictionary may not be Weyl group invariant" 590 601 if self._cache and highest in self._irreducibles: 591 602 sdict = self._irreducibles[highest]._mdict 592 603 else: 593 sdict = irreducible_character_freudenthal(h vect, self._lattice)604 sdict = irreducible_character_freudenthal(highest, self._lattice) 594 605 if self._cache and not highest in self._irreducibles: 595 606 self._irreducibles[highest] = WeylCharacter(self, {highest:1}, sdict) 596 607 c = ddict[highest] … … 643 654 L - the ambient lattice 644 655 645 656 """ 646 VS = VectorSpace(QQ, L.n) 657 647 658 rho = L.rho() 648 659 mdict = {} 649 current_layer = { tuple(hwv):1}660 current_layer = {hwv:1} 650 661 while len(current_layer) > 0: 651 662 next_layer = {} 652 663 for mu in current_layer: 653 664 if not current_layer[mu] == 0: 654 665 mdict[mu] = current_layer[mu] 655 666 for alpha in L.simple_roots(): 656 next_layer[ tuple(VS(mu)-alpha)] = None667 next_layer[mu-alpha] = None 657 668 if debug: 658 669 print next_layer 659 670 for mu in next_layer: 660 vmu = VS(mu)661 671 if next_layer[mu] == None: 662 672 if debug: 663 673 print " mu:", mu 664 674 accum = 0 665 675 for alpha in L.positive_roots(): 666 676 i = 1 667 while tuple(vmu+i*alpha)in mdict:677 while mu+i*alpha in mdict: 668 678 if debug: 669 print " ", vmu+i*alpha,670 print mdict[ tuple(vmu + i*alpha)]*(vmu + i*alpha).inner_product(alpha)671 accum += mdict[ tuple(vmu + i*alpha)]*(vmu + i*alpha).inner_product(alpha)679 print " ", mu+i*alpha, 680 print mdict[mu + i*alpha]*(mu + i*alpha).inner_product(alpha) 681 accum += mdict[mu + i*alpha]*(mu + i*alpha).inner_product(alpha) 672 682 i += 1 673 683 if accum == 0: 674 684 next_layer[mu] = 0 675 685 else: 676 next_layer[mu] = QQ(2*accum)/QQ((hwv+rho).inner_product(hwv+rho)-( vmu+rho).inner_product(vmu+rho))686 next_layer[mu] = QQ(2*accum)/QQ((hwv+rho).inner_product(hwv+rho)-(mu+rho).inner_product(mu+rho)) 677 687 current_layer = next_layer 678 688 return mdict 679 689 … … 897 907 """ 898 908 r = R.cartan_type[1] 899 909 s = S.cartan_type[1] 910 # Each rule takes a tuple or list and returns a list 900 911 if rule == "levi": 901 912 if not s == r-1: 902 913 raise ValueError, "Rank is wrong" … … 928 939 elif R.cartan_type[0] == 'A': 929 940 def rule(x) : y = [-i for i in x]; y.reverse(); return y 930 941 elif R.cartan_type[0] == 'D': 931 def rule(x) : y = R.VS(x); y[len(y)-1] = -y[len(y)-1]; return y942 def rule(x) : x[len(x)-1] = -x[len(x)-1]; return x 932 943 elif R.cartan_type[0] == 'E' and R.cartan_type[1] == 6: 933 944 raise NotImplementedError, "Exceptional branching rules are yet to be implemented" 934 945 else: … … 991 1002 992 1003 mdict = {} 993 1004 for k in chi._mdict: 994 h = tuple(S.VS(rule(k)))1005 h = S._lattice(rule(list(k.to_vector()))) 995 1006 if h in mdict: 996 1007 mdict[h] += chi._mdict[k] 997 1008 else: … … 1045 1056 sage: B3 = WeylCharacterRing(['B',3]) 1046 1057 sage: b3 = WeightRing(B3) 1047 1058 sage: fw = b3.lattice().fundamental_weights() 1048 sage: b3(fw[ 2])1059 sage: b3(fw[3]) 1049 1060 b3(1/2,1/2,1/2) 1050 sage: b3(B3(fw[ 2]))1061 sage: b3(B3(fw[3])) 1051 1062 b3(-1/2,-1/2,-1/2) + b3(-1/2,-1/2,1/2) + b3(-1/2,1/2,-1/2) + b3(-1/2,1/2,1/2) + b3(1/2,-1/2,-1/2) + b3(1/2,-1/2,1/2) + b3(1/2,1/2,-1/2) + b3(1/2,1/2,1/2) 1052 1063 """ 1053 1064 1054 1065 if self._mdict == {}: 1055 1066 return "0" 1056 1067 v = self._mdict.keys() 1057 v.sort() 1068 # Just a workaround to keep the same sorting as before when 1069 # the dictionary was indexed by tuples 1070 v.sort(key = lambda v: tuple(v.to_vector())) 1058 1071 return repr_lincomb([self._wt_repr(k) for k in v], [self._mdict[k] for k in v]) 1059 1072 1060 1073 def __cmp__(left, right): … … 1131 1144 mdict = {} 1132 1145 for k in self._mdict: 1133 1146 for l in y._mdict: 1134 m = tuple(self._parent.VS(k)+self._parent.VS(l))1147 m = k+l 1135 1148 if m in mdict: 1136 1149 mdict[m] += self._mdict[k]*y._mdict[l] 1137 1150 else: … … 1173 1186 sage: g2 = WeightRing(G2) 1174 1187 sage: pr = sum(g2(a) for a in g2.lattice().positive_roots()) 1175 1188 sage: pr.mlist() 1176 [[(1, 1, -2), 1], 1177 [(1, -1, 0), 1], 1178 [(1, 0, -1), 1], 1179 [(1, -2, 1), 1], 1189 [[(1, -2, 1), 1], 1190 [(1, -1, 0), 1], 1191 [(1, 0, -1), 1], 1180 1192 [(2, -1, -1), 1], 1181 [(0, 1, -1), 1]] 1193 [(0, 1, -1), 1], 1194 [(1, 1, -2), 1]] 1182 1195 """ 1183 return [[ self._parent.VS(k),m] for k,m in self._mdict.iteritems()]1196 return [[k,m] for k,m in self._mdict.iteritems()] 1184 1197 1185 1198 def weyl_group_action(self, w): 1186 1199 """ … … 1194 1207 sage: sum(g2(fw2).weyl_group_action(w) for w in L.weyl_group()) 1195 1208 2*g2(-2,1,1) + 2*g2(-1,-1,2) + 2*g2(-1,2,-1) + 2*g2(1,-2,1) + 2*g2(1,1,-2) + 2*g2(2,-1,-1) 1196 1209 """ 1197 return WeightRingElement(self._parent, dict([[ tuple(w.action(self._parent.VS(x))),self._mdict[x]] for x in self._mdict.keys()]))1210 return WeightRingElement(self._parent, dict([[w.action(x),self._mdict[x]] for x in self._mdict.keys()])) 1198 1211 1199 1212 def character(self): 1200 1213 """ … … 1292 1305 self._base_ring = self._parent._base_ring 1293 1306 self._lattice = self._parent._lattice 1294 1307 self._origin = self._parent._origin 1295 self.VS = self._parent.VS1296 1308 self._prefix = prefix 1297 1309 self._ip = self._parent._ip 1298 1310 … … 1329 1341 return WeightRingElement(self, x._mdict) 1330 1342 except AttributeError: 1331 1343 pass 1332 x = self. VS(x)1333 mdict = { tuple(x): 1}1344 x = self._lattice(x) 1345 mdict = {x: 1} 1334 1346 return WeightRingElement(self, mdict) 1335 1347 1336 1348 def __repr__(self): … … 1383 1395 1384 1396 def lattice(self): 1385 1397 """ 1386 Returns the weight lattice associated to self.1398 Returns the weight lattice realization associated to self. 1387 1399 . 1388 1400 EXAMPLES: 1389 1401 sage: E8 = WeylCharacterRing(['E',8]) 1390 1402 sage: e8 = WeightRing(E8) 1391 1403 sage: e8.lattice() 1392 Ambient lattice of the root system of type ['E', 8]1404 Ambient space for the Root system of type ['E', 8] 1393 1405 """ 1394 1406 return self._lattice 1395 1407 -
sage/combinat/root_system/weyl_group.py
diff -r 29be632ff7bc -r db34e50d9e6c sage/combinat/root_system/weyl_group.py
a b 41 41 42 42 or alternatively and equivalently: 43 43 44 sage: L = RootSystem(['F',4]).ambient_ lattice()44 sage: L = RootSystem(['F',4]).ambient_space() 45 45 sage: G = L.weyl_group() 46 46 47 47 Either produces a weight lattice, with access to its … … 65 65 66 66 sage: L = G.lattice() 67 67 sage: fw = L.fundamental_weights(); fw 68 [(1, 1, 0, 0), (2, 1, 1, 0), (3/2, 1/2, 1/2, 1/2), (1, 0, 0, 0)]68 Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)} 69 69 sage: rho = sum(fw); rho 70 70 (11/2, 5/2, 3/2, 1/2) 71 71 sage: w.action(rho) # action of G on weight lattice … … 85 85 The Weyl Group of type ['A', 2] 86 86 """ 87 87 from sage.combinat.root_system.root_system import RootSystem 88 e = RootSystem(ct).ambient_ lattice()88 e = RootSystem(ct).ambient_space() 89 89 n = e.n 90 rank = e.ct[1]91 basis = e. _free_module.basis()90 rank = ct.rank() 91 basis = e.basis() 92 92 gens = [] 93 s = e.simple_reflections() 93 94 for k in range(rank): 94 95 m = [] 95 96 for i in range(n): 96 97 for j in range(n): 97 m.append( e.simple_reflection(k+1,basis[j]).inner_product(basis[i]))98 m.append(s[k+1](basis[j]).inner_product(basis[i])) 98 99 gens.append(matrix(QQ,n,m)) 99 100 return WeylGroup_gens(gens,e) 100 101 … … 111 112 True 112 113 """ 113 114 MatrixGroup_gens.__init__(self, gens) 114 self.ambient_ lattice = L115 self.ambient_space = L 115 116 self.reflections = [WeylGroupElement(g, self) for g in gens] 116 117 self.n = L.n 117 118 … … 121 122 sage: WeylGroup(['A',1]).__repr__() 122 123 "The Weyl Group of type ['A', 1]" 123 124 """ 124 return "The Weyl Group of type %s"%repr(self.ambient_lattice.ct) 125 # FIXME: do we want to say Weyl Group of the AmbientSpace of ...? 126 return "The Weyl Group of type %s"%repr(self.cartan_type()) 125 127 126 128 def __call__(self, x): 127 129 """ … … 189 191 EXAMPLES: 190 192 sage: G = WeylGroup(['F',4]) 191 193 sage: G.lattice() 192 Ambient lattice of the root system of type ['F', 4]194 Ambient space for the Root system of type ['F', 4] 193 195 """ 194 return self.ambient_ lattice196 return self.ambient_space 195 197 196 198 def simple_reflections(self): 197 199 """ … … 224 226 [0 1 0 0] 225 227 [0 0 0 1] 226 228 """ 227 if i not in self. ambient_lattice.ct.index_set():229 if i not in self.cartan_type().index_set(): 228 230 raise ValueError, "i must be in the index set" 229 231 return self.reflections[i-1] 230 232 … … 235 237 sage: [WeylGroup(t).long_element().length() for t in ['A',5],['B',3],['C',3],['D',4],['G',2],['F',4],['E',6]] 236 238 [15, 9, 9, 12, 6, 24, 36] 237 239 """ 238 type = self. ambient_lattice.ct240 type = self.cartan_type() 239 241 if type[0] == 'D' and type[1]%2 == 1: 240 242 l = [-1 for i in range(self.n-1)] 241 243 l.append(1) … … 280 282 ['F', 4] 281 283 282 284 """ 283 return self.ambient_ lattice.ct285 return self.ambient_space.root_system.cartan_type() 284 286 285 287 def __cmp__(self, other): 286 288 """ … … 293 295 """ 294 296 if self.__class__ != other.__class__: 295 297 return cmp(self.__class__, other.__class__) 296 if self. ambient_lattice.ct != other.ambient_lattice.ct:297 return cmp(self. ambient_lattice.ct, other.ambient_lattice.ct)298 if self.cartan_type() != other.cartan_type(): 299 return cmp(self.cartan_type(), other.cartan_type()) 298 300 return 0 299 301 300 302 class WeylGroupElement(MatrixGroupElement): … … 321 323 sage: w = WeylGroup(['A',2]) 322 324 sage: s1 = w.simple_reflection(1) 323 325 sage: s1.lattice() 324 Ambient lattice of the root system of type ['A', 2]326 Ambient space for the Root system of type ['A', 2] 325 327 """ 326 328 return self._parent.lattice() 327 329 … … 342 344 343 345 """ 344 346 ret = 0 345 for alph in self.lattice().positive_roots():346 walph = self. __matrix*alph347 for alpha in self.lattice().positive_roots(): 348 walph = self.action(alpha) 347 349 for v in self.lattice().fundamental_weights(): 348 350 if walph.inner_product(v) < 0: 349 351 ret += 1 … … 415 417 EXAMPLES: 416 418 sage: w = WeylGroup(['A',2]) 417 419 sage: s1 = w.simple_reflection(1) 418 sage: v = vector(QQ,[1,0,0])420 sage: v = w.lattice()([1,0,0]) 419 421 sage: s1.action(v) 420 422 (0, 1, 0) 421 423 """ 422 return (self. __matrix*transpose(v)).columns()[0]424 return (self.lattice()(list(self.__matrix*transpose(v.to_vector()).columns()[0])))
