passagemath-coxeter3 10.6.34__cp310-cp310-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_coxeter3-10.6.34.dist-info/METADATA +94 -0
- passagemath_coxeter3-10.6.34.dist-info/RECORD +14 -0
- passagemath_coxeter3-10.6.34.dist-info/WHEEL +6 -0
- passagemath_coxeter3-10.6.34.dist-info/top_level.txt +2 -0
- passagemath_coxeter3.dylibs/libcoxeter3.dylib +0 -0
- sage/all__sagemath_coxeter3.py +2 -0
- sage/libs/all__sagemath_coxeter3.py +1 -0
- sage/libs/coxeter3/__init__.py +1 -0
- sage/libs/coxeter3/all__sagemath_coxeter3.py +1 -0
- sage/libs/coxeter3/coxeter.cpython-310-darwin.so +0 -0
- sage/libs/coxeter3/coxeter.pxd +31 -0
- sage/libs/coxeter3/coxeter.pyx +1223 -0
- sage/libs/coxeter3/coxeter_group.py +717 -0
- sage/libs/coxeter3/decl.pxd +166 -0
|
@@ -0,0 +1,1223 @@
|
|
|
1
|
+
# distutils: language = c++
|
|
2
|
+
# distutils: libraries = coxeter3
|
|
3
|
+
# sage_setup: distribution = sagemath-coxeter3
|
|
4
|
+
# sage.doctest: optional - coxeter3
|
|
5
|
+
"""
|
|
6
|
+
Low level part of the interface to Fokko Ducloux's Coxeter 3 library
|
|
7
|
+
|
|
8
|
+
.. TODO::
|
|
9
|
+
|
|
10
|
+
- Write a more efficient method for converting polynomials in
|
|
11
|
+
Coxeter to Sage polynomials.
|
|
12
|
+
"""
|
|
13
|
+
# ****************************************************************************
|
|
14
|
+
# Copyright (C) 2009-2013 Mike Hansen <mhansen@gmail.com>
|
|
15
|
+
#
|
|
16
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
17
|
+
# https://www.gnu.org/licenses/
|
|
18
|
+
# ****************************************************************************
|
|
19
|
+
|
|
20
|
+
from sage.libs.coxeter3.decl cimport *
|
|
21
|
+
from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE
|
|
22
|
+
from sage.cpython.string cimport str_to_bytes, bytes_to_str
|
|
23
|
+
|
|
24
|
+
initConstants()
|
|
25
|
+
|
|
26
|
+
from sage.rings.integer import Integer
|
|
27
|
+
from sage.rings.integer_ring import ZZ
|
|
28
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
cdef class String:
|
|
32
|
+
def __init__(self, s=""):
|
|
33
|
+
"""
|
|
34
|
+
Construct a Coxeter string from a Python string.
|
|
35
|
+
|
|
36
|
+
EXAMPLES::
|
|
37
|
+
|
|
38
|
+
sage: from sage.libs.coxeter3.coxeter import String
|
|
39
|
+
sage: s = String("hello"); s
|
|
40
|
+
hello
|
|
41
|
+
sage: del s
|
|
42
|
+
"""
|
|
43
|
+
self.x = c_String(str_to_bytes(s))
|
|
44
|
+
|
|
45
|
+
def __repr__(self):
|
|
46
|
+
"""
|
|
47
|
+
EXAMPLES::
|
|
48
|
+
|
|
49
|
+
sage: from sage.libs.coxeter3.coxeter import String
|
|
50
|
+
sage: s = String('Hi')
|
|
51
|
+
sage: s
|
|
52
|
+
Hi
|
|
53
|
+
"""
|
|
54
|
+
return bytes_to_str(self.x.ptr())
|
|
55
|
+
|
|
56
|
+
def __hash__(self):
|
|
57
|
+
"""
|
|
58
|
+
Return the hash of this String.
|
|
59
|
+
|
|
60
|
+
This is the hash of the tuple consisting of the class name and
|
|
61
|
+
the name of this type.
|
|
62
|
+
|
|
63
|
+
EXAMPLES::
|
|
64
|
+
|
|
65
|
+
sage: from sage.libs.coxeter3.coxeter import String
|
|
66
|
+
sage: s = String('hello')
|
|
67
|
+
sage: hash(s) == hash('hello')
|
|
68
|
+
True
|
|
69
|
+
"""
|
|
70
|
+
return hash(repr(self))
|
|
71
|
+
|
|
72
|
+
def __richcmp__(String self, other, int op):
|
|
73
|
+
"""
|
|
74
|
+
EXAMPLES::
|
|
75
|
+
|
|
76
|
+
sage: from sage.libs.coxeter3.coxeter import String
|
|
77
|
+
sage: ta1 = String('A')
|
|
78
|
+
sage: ta2 = String('A')
|
|
79
|
+
sage: tb = String('b')
|
|
80
|
+
sage: ta1 == ta2
|
|
81
|
+
True
|
|
82
|
+
sage: tb != ta1
|
|
83
|
+
True
|
|
84
|
+
sage: all([ta1 < tb, ta1 <= tb, ta1 <= ta1])
|
|
85
|
+
True
|
|
86
|
+
sage: all([tb > ta1, tb >= ta1, tb >= tb])
|
|
87
|
+
True
|
|
88
|
+
"""
|
|
89
|
+
if type(other) is not type(self):
|
|
90
|
+
if op in (Py_LT, Py_LE, Py_GT, Py_GE):
|
|
91
|
+
return NotImplemented
|
|
92
|
+
return op == Py_NE
|
|
93
|
+
|
|
94
|
+
s = repr(self)
|
|
95
|
+
o = repr(other)
|
|
96
|
+
|
|
97
|
+
if op == Py_EQ:
|
|
98
|
+
return s == o
|
|
99
|
+
elif op == Py_NE:
|
|
100
|
+
return s != o
|
|
101
|
+
elif op == Py_LT:
|
|
102
|
+
return s < o
|
|
103
|
+
elif op == Py_LE:
|
|
104
|
+
return s <= o
|
|
105
|
+
elif op == Py_GT:
|
|
106
|
+
return s > o
|
|
107
|
+
elif op == Py_GE:
|
|
108
|
+
return s >= o
|
|
109
|
+
|
|
110
|
+
def __len__(self):
|
|
111
|
+
"""
|
|
112
|
+
Return the length of this string.
|
|
113
|
+
|
|
114
|
+
EXAMPLES::
|
|
115
|
+
|
|
116
|
+
sage: from sage.libs.coxeter3.coxeter import String
|
|
117
|
+
sage: s = String('Hi')
|
|
118
|
+
sage: len(s)
|
|
119
|
+
2
|
|
120
|
+
"""
|
|
121
|
+
return self.x.length()
|
|
122
|
+
|
|
123
|
+
def __reduce__(self):
|
|
124
|
+
"""
|
|
125
|
+
EXAMPLES::
|
|
126
|
+
|
|
127
|
+
sage: from sage.libs.coxeter3.coxeter import String
|
|
128
|
+
sage: s = String('Hi')
|
|
129
|
+
sage: TestSuite(s).run()
|
|
130
|
+
"""
|
|
131
|
+
return (String, (repr(self),) )
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
cdef class Type:
|
|
135
|
+
def __init__(self, s):
|
|
136
|
+
"""
|
|
137
|
+
Construct a Coxeter Type from a Python string.
|
|
138
|
+
|
|
139
|
+
EXAMPLES::
|
|
140
|
+
|
|
141
|
+
sage: from sage.libs.coxeter3.coxeter import Type
|
|
142
|
+
sage: t = Type('A'); t
|
|
143
|
+
A
|
|
144
|
+
sage: del t
|
|
145
|
+
"""
|
|
146
|
+
self.x = c_Type(str_to_bytes(s))
|
|
147
|
+
|
|
148
|
+
def __repr__(self):
|
|
149
|
+
"""
|
|
150
|
+
EXAMPLES::
|
|
151
|
+
|
|
152
|
+
sage: from sage.libs.coxeter3.coxeter import Type
|
|
153
|
+
sage: t = Type('A'); t
|
|
154
|
+
A
|
|
155
|
+
"""
|
|
156
|
+
return bytes_to_str(self.x.name().ptr())
|
|
157
|
+
|
|
158
|
+
def name(self):
|
|
159
|
+
"""
|
|
160
|
+
EXAMPLES::
|
|
161
|
+
|
|
162
|
+
sage: from sage.libs.coxeter3.coxeter import Type
|
|
163
|
+
sage: t = Type('A')
|
|
164
|
+
sage: t.name()
|
|
165
|
+
A
|
|
166
|
+
"""
|
|
167
|
+
return String(bytes_to_str(self.x.name().ptr()))
|
|
168
|
+
|
|
169
|
+
def __hash__(self):
|
|
170
|
+
"""
|
|
171
|
+
Return the hash of this Type.
|
|
172
|
+
|
|
173
|
+
This is the hash of the tuple consisting of the class name and
|
|
174
|
+
the name of this type.
|
|
175
|
+
|
|
176
|
+
EXAMPLES::
|
|
177
|
+
|
|
178
|
+
sage: from sage.libs.coxeter3.coxeter import Type
|
|
179
|
+
sage: a = Type('A')
|
|
180
|
+
sage: b = Type('B')
|
|
181
|
+
sage: hash(a) == hash(b)
|
|
182
|
+
False
|
|
183
|
+
sage: d = {a: 1, b: 2}
|
|
184
|
+
"""
|
|
185
|
+
return hash(('Type', self.name()))
|
|
186
|
+
|
|
187
|
+
def __richcmp__(Type self, other, int op):
|
|
188
|
+
"""
|
|
189
|
+
EXAMPLES::
|
|
190
|
+
|
|
191
|
+
sage: from sage.libs.coxeter3.coxeter import Type
|
|
192
|
+
sage: ta1 = Type('A')
|
|
193
|
+
sage: ta2 = Type('A')
|
|
194
|
+
sage: tb = Type('b')
|
|
195
|
+
sage: ta1 == ta2
|
|
196
|
+
True
|
|
197
|
+
sage: tb != ta1
|
|
198
|
+
True
|
|
199
|
+
sage: all([ta1 < tb, ta1 <= tb, ta1 <= ta1])
|
|
200
|
+
True
|
|
201
|
+
sage: all([tb > ta1, tb >= ta1, tb >= tb])
|
|
202
|
+
True
|
|
203
|
+
"""
|
|
204
|
+
if type(other) is not type(self):
|
|
205
|
+
if op in (Py_LT, Py_LE, Py_GT, Py_GE):
|
|
206
|
+
return NotImplemented
|
|
207
|
+
return op == Py_NE
|
|
208
|
+
|
|
209
|
+
s = repr(self)
|
|
210
|
+
o = repr(other)
|
|
211
|
+
|
|
212
|
+
if op == Py_EQ:
|
|
213
|
+
return s == o
|
|
214
|
+
elif op == Py_NE:
|
|
215
|
+
return s != o
|
|
216
|
+
elif op == Py_LT:
|
|
217
|
+
return s < o
|
|
218
|
+
elif op == Py_LE:
|
|
219
|
+
return s <= o
|
|
220
|
+
elif op == Py_GT:
|
|
221
|
+
return s > o
|
|
222
|
+
elif op == Py_GE:
|
|
223
|
+
return s >= o
|
|
224
|
+
|
|
225
|
+
def __reduce__(self):
|
|
226
|
+
"""
|
|
227
|
+
EXAMPLES::
|
|
228
|
+
|
|
229
|
+
sage: from sage.libs.coxeter3.coxeter import Type
|
|
230
|
+
sage: t = Type('A')
|
|
231
|
+
sage: TestSuite(t).run()
|
|
232
|
+
"""
|
|
233
|
+
return (Type, (repr(self), ))
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
cdef class CoxGroup(SageObject):
|
|
237
|
+
def __cinit__(self, cartan_type):
|
|
238
|
+
"""
|
|
239
|
+
EXAMPLES::
|
|
240
|
+
|
|
241
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
242
|
+
sage: W = CoxGroup(['A', 5]); W
|
|
243
|
+
Coxeter group of type A and rank 5
|
|
244
|
+
|
|
245
|
+
Coxeter 3 segfault's on the trivial Coxeter group; so we catch
|
|
246
|
+
this and raise a not implemented error::
|
|
247
|
+
|
|
248
|
+
sage: W = CoxGroup(['A', 0]); W
|
|
249
|
+
Traceback (most recent call last):
|
|
250
|
+
...
|
|
251
|
+
NotImplementedError: Coxeter group of type ['A',0] using Coxeter 3 not yet implemented
|
|
252
|
+
|
|
253
|
+
Successfully initializes from a relabeled Cartan type::
|
|
254
|
+
|
|
255
|
+
sage: ctype = CartanType(['B', 3]).relabel({1: 3, 2: 2, 3: 1})
|
|
256
|
+
sage: W = CoxGroup(ctype)
|
|
257
|
+
sage: CoxeterMatrix(W.coxeter_matrix(), ctype.index_set()) == CoxeterMatrix(ctype)
|
|
258
|
+
True
|
|
259
|
+
"""
|
|
260
|
+
from sage.combinat.root_system.cartan_type import CartanType
|
|
261
|
+
from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix
|
|
262
|
+
self.cartan_type = CartanType(cartan_type)
|
|
263
|
+
ordering = self._ordering_from_cartan_type(self.cartan_type)
|
|
264
|
+
|
|
265
|
+
type, rank = self.cartan_type.type(), self.cartan_type.rank()
|
|
266
|
+
if self.cartan_type.is_affine():
|
|
267
|
+
# Only untwisted affine groups are supported
|
|
268
|
+
try:
|
|
269
|
+
if not self.cartan_type.is_untwisted_affine():
|
|
270
|
+
raise NotImplementedError('twisted affine groups are not supported in coxeter3')
|
|
271
|
+
except AttributeError:
|
|
272
|
+
pass
|
|
273
|
+
type = type.lower()
|
|
274
|
+
|
|
275
|
+
type = 'B' if type == 'C' else type
|
|
276
|
+
|
|
277
|
+
if rank == 0:
|
|
278
|
+
raise NotImplementedError("Coxeter group of type ['A',0] using Coxeter 3 not yet implemented")
|
|
279
|
+
cdef Type t = Type(type)
|
|
280
|
+
cdef c_CoxGroup* c_W = coxeterGroup(t.x, rank)
|
|
281
|
+
self.x = c_W
|
|
282
|
+
self.out_ordering = {i+1: o for i,o in enumerate(ordering)}
|
|
283
|
+
self.in_ordering = {self.out_ordering[a]: a for a in self.out_ordering}
|
|
284
|
+
|
|
285
|
+
# If the Cartan type supplied is relabeled, compose these orderings
|
|
286
|
+
# with the relabelling on the appropriate sides:
|
|
287
|
+
if hasattr(self.cartan_type, '_relabelling'):
|
|
288
|
+
r = self.cartan_type._relabelling
|
|
289
|
+
r_inv = {v: k for (k, v) in r.items()}
|
|
290
|
+
# Pre-compose in_ordering with r
|
|
291
|
+
self.in_ordering = {i: self.in_ordering[r[i]] for i in self.in_ordering}
|
|
292
|
+
# Post-compose out_ordering with r inverse
|
|
293
|
+
self.out_ordering = {i: r_inv[self.out_ordering[i]] for i in self.out_ordering}
|
|
294
|
+
|
|
295
|
+
# Check that the Coxeter matrices match up.
|
|
296
|
+
cox_mat = CoxeterMatrix(self.coxeter_matrix(), self.cartan_type.index_set())
|
|
297
|
+
if cox_mat != CoxeterMatrix(self.cartan_type):
|
|
298
|
+
print("Warning, differing Coxeter matrices")
|
|
299
|
+
|
|
300
|
+
@classmethod
|
|
301
|
+
def _ordering_from_cartan_type(cls, cartan_type):
|
|
302
|
+
"""
|
|
303
|
+
Return an ordering of the index set associated to the Cartan type.
|
|
304
|
+
|
|
305
|
+
EXAMPLES::
|
|
306
|
+
|
|
307
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
308
|
+
sage: W = CoxGroup(['A', 5])
|
|
309
|
+
sage: W._ordering_from_cartan_type(CartanType(['A',5]))
|
|
310
|
+
[1, 2, 3, 4, 5]
|
|
311
|
+
"""
|
|
312
|
+
from sage.arith.srange import srange
|
|
313
|
+
t = cartan_type.type()
|
|
314
|
+
r = cartan_type.rank()
|
|
315
|
+
is_affine = cartan_type.is_affine()
|
|
316
|
+
|
|
317
|
+
if t in ['B', 'C', 'D', 'F', 'H']:
|
|
318
|
+
return srange(r-1 if is_affine else r,
|
|
319
|
+
-1 if is_affine else 0, -1)
|
|
320
|
+
elif t in ['A', 'I']:
|
|
321
|
+
return srange(0 if is_affine else 1, r+1)
|
|
322
|
+
elif t in ['G']:
|
|
323
|
+
if is_affine:
|
|
324
|
+
raise NotImplementedError
|
|
325
|
+
else:
|
|
326
|
+
return [Integer(1), Integer(2)]
|
|
327
|
+
elif t in ['E']:
|
|
328
|
+
if is_affine:
|
|
329
|
+
return srange(1, r) + [ZZ.zero()]
|
|
330
|
+
else:
|
|
331
|
+
return srange(1, r+1)
|
|
332
|
+
else:
|
|
333
|
+
raise NotImplementedError
|
|
334
|
+
|
|
335
|
+
def __hash__(self):
|
|
336
|
+
"""
|
|
337
|
+
Return the hash of this CoxGroup.
|
|
338
|
+
|
|
339
|
+
This is the hash of the tuple of the class's name, the type,
|
|
340
|
+
and the rank.
|
|
341
|
+
|
|
342
|
+
EXAMPLES::
|
|
343
|
+
|
|
344
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
345
|
+
sage: A4 = CoxGroup(['A', 4])
|
|
346
|
+
sage: d = {A4: True}
|
|
347
|
+
"""
|
|
348
|
+
return hash((self.__class__.__name__, self.type(), self.rank()))
|
|
349
|
+
|
|
350
|
+
def __richcmp__(CoxGroup self, other, int op):
|
|
351
|
+
"""
|
|
352
|
+
EXAMPLES::
|
|
353
|
+
|
|
354
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
355
|
+
sage: A4 = CoxGroup(['A', 4])
|
|
356
|
+
sage: A5 = CoxGroup(['A', 5])
|
|
357
|
+
sage: B4 = CoxGroup(['B', 4])
|
|
358
|
+
sage: A4 == A4
|
|
359
|
+
True
|
|
360
|
+
sage: A4 != B4
|
|
361
|
+
True
|
|
362
|
+
sage: A4 < B4
|
|
363
|
+
True
|
|
364
|
+
sage: A5 > A4
|
|
365
|
+
True
|
|
366
|
+
sage: A4 >= A4
|
|
367
|
+
True
|
|
368
|
+
sage: B4 >= A5
|
|
369
|
+
True
|
|
370
|
+
"""
|
|
371
|
+
if type(other) is not type(self):
|
|
372
|
+
if op in (Py_LT, Py_LE, Py_GT, Py_GE):
|
|
373
|
+
return NotImplemented
|
|
374
|
+
return op == Py_NE
|
|
375
|
+
|
|
376
|
+
s_t = self.type()
|
|
377
|
+
o_t = other.type()
|
|
378
|
+
s_r = self.rank()
|
|
379
|
+
o_r = other.rank()
|
|
380
|
+
|
|
381
|
+
if op == Py_EQ:
|
|
382
|
+
return s_t == o_t and s_r == o_r
|
|
383
|
+
elif op == Py_NE:
|
|
384
|
+
return s_t != o_t or s_r != o_r
|
|
385
|
+
elif op == Py_LT:
|
|
386
|
+
return s_t < o_t or (s_t == o_t and s_r < o_r)
|
|
387
|
+
elif op == Py_LE:
|
|
388
|
+
return s_t < o_t or (s_t == o_t and s_r <= o_r)
|
|
389
|
+
elif op == Py_GT:
|
|
390
|
+
return s_t > o_t or (s_t == o_t and s_r > o_r)
|
|
391
|
+
elif op == Py_GE:
|
|
392
|
+
return s_t > o_t or (s_t == o_t and s_r >= o_r)
|
|
393
|
+
|
|
394
|
+
def __reduce__(self):
|
|
395
|
+
"""
|
|
396
|
+
EXAMPLES::
|
|
397
|
+
|
|
398
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
399
|
+
sage: W = CoxGroup(['A', 5])
|
|
400
|
+
sage: TestSuite((W)).run()
|
|
401
|
+
"""
|
|
402
|
+
return (CoxGroup, (self.cartan_type,))
|
|
403
|
+
|
|
404
|
+
def __dealloc__(self):
|
|
405
|
+
"""
|
|
406
|
+
Deallocate the memory for this CoxGroup.
|
|
407
|
+
|
|
408
|
+
EXAMPLES::
|
|
409
|
+
|
|
410
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
411
|
+
sage: W = CoxGroup(['A', 5])
|
|
412
|
+
sage: del W
|
|
413
|
+
"""
|
|
414
|
+
del self.x
|
|
415
|
+
|
|
416
|
+
def __repr__(self):
|
|
417
|
+
"""
|
|
418
|
+
Return a string representation of this Coxeter group.
|
|
419
|
+
|
|
420
|
+
EXAMPLES::
|
|
421
|
+
|
|
422
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
423
|
+
sage: W = CoxGroup(['A', 5]); W
|
|
424
|
+
Coxeter group of type A and rank 5
|
|
425
|
+
"""
|
|
426
|
+
return "Coxeter group of type %s and rank %s" % (self.type(),
|
|
427
|
+
self.rank())
|
|
428
|
+
|
|
429
|
+
def __iter__(self):
|
|
430
|
+
"""
|
|
431
|
+
EXAMPLES::
|
|
432
|
+
|
|
433
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
434
|
+
sage: W = CoxGroup(['A', 2])
|
|
435
|
+
sage: list(iter(W))
|
|
436
|
+
[[], [1], [2], [1, 2], [2, 1], [1, 2, 1]]
|
|
437
|
+
"""
|
|
438
|
+
return CoxGroupIterator(self)
|
|
439
|
+
|
|
440
|
+
def bruhat_interval(self, w, v):
|
|
441
|
+
"""
|
|
442
|
+
Return the list of the elements in the Bruhat interval between `w` and `v`.
|
|
443
|
+
|
|
444
|
+
EXAMPLES::
|
|
445
|
+
|
|
446
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
447
|
+
sage: W = CoxGroup(['A', 2])
|
|
448
|
+
sage: W.bruhat_interval([], [1,2])
|
|
449
|
+
[[], [1], [2], [1, 2]]
|
|
450
|
+
"""
|
|
451
|
+
cdef CoxGroupElement ww = CoxGroupElement(self, w)
|
|
452
|
+
cdef CoxGroupElement vv = CoxGroupElement(self, v)
|
|
453
|
+
cdef c_List_CoxWord l = c_List_CoxWord(0)
|
|
454
|
+
interval(l, self.x[0], ww.word, vv.word)
|
|
455
|
+
bruhat_interval = []
|
|
456
|
+
cdef CoxGroupElement u
|
|
457
|
+
cdef CoxGroupElement gg = CoxGroupElement(self, [])
|
|
458
|
+
cdef size_t j
|
|
459
|
+
for j in range(l.size()):
|
|
460
|
+
u = gg._new()
|
|
461
|
+
u.word = l[j]
|
|
462
|
+
bruhat_interval.append(u)
|
|
463
|
+
|
|
464
|
+
return bruhat_interval
|
|
465
|
+
|
|
466
|
+
def orderings(self):
|
|
467
|
+
"""
|
|
468
|
+
Return two dictionaries specifying the mapping of the labels
|
|
469
|
+
of the Dynkin diagram between Sage and Coxeter3 and the its
|
|
470
|
+
inverse.
|
|
471
|
+
|
|
472
|
+
EXAMPLES::
|
|
473
|
+
|
|
474
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
475
|
+
sage: W = CoxGroup(['A', 5])
|
|
476
|
+
sage: W.orderings()
|
|
477
|
+
({1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, {1: 1, 2: 2, 3: 3, 4: 4, 5: 5})
|
|
478
|
+
"""
|
|
479
|
+
return self.in_ordering, self.out_ordering
|
|
480
|
+
|
|
481
|
+
def type(self):
|
|
482
|
+
"""
|
|
483
|
+
Return the type of this Coxeter group.
|
|
484
|
+
|
|
485
|
+
Note that the type does not include the rank.
|
|
486
|
+
|
|
487
|
+
EXAMPLES::
|
|
488
|
+
|
|
489
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
490
|
+
sage: W = CoxGroup(['A', 5])
|
|
491
|
+
sage: W.type()
|
|
492
|
+
A
|
|
493
|
+
"""
|
|
494
|
+
return Type(bytes_to_str(self.x.type().name().ptr()))
|
|
495
|
+
|
|
496
|
+
def rank(self):
|
|
497
|
+
"""
|
|
498
|
+
Return the rank of this Coxeter group.
|
|
499
|
+
|
|
500
|
+
EXAMPLES::
|
|
501
|
+
|
|
502
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
503
|
+
sage: W = CoxGroup(['A', 5])
|
|
504
|
+
sage: W.rank()
|
|
505
|
+
5
|
|
506
|
+
"""
|
|
507
|
+
return self.x.rank()
|
|
508
|
+
|
|
509
|
+
def order(self):
|
|
510
|
+
"""
|
|
511
|
+
Return the order of this Coxeter group.
|
|
512
|
+
|
|
513
|
+
EXAMPLES::
|
|
514
|
+
|
|
515
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
516
|
+
sage: W = CoxGroup(['A', 5])
|
|
517
|
+
sage: W.order()
|
|
518
|
+
720
|
|
519
|
+
sage: W = CoxGroup(['A', 3, 1])
|
|
520
|
+
sage: W.order()
|
|
521
|
+
+Infinity
|
|
522
|
+
"""
|
|
523
|
+
if self.is_finite():
|
|
524
|
+
return Integer(self.x.order())
|
|
525
|
+
else:
|
|
526
|
+
from sage.rings.infinity import infinity
|
|
527
|
+
return infinity
|
|
528
|
+
|
|
529
|
+
def is_finite(self):
|
|
530
|
+
"""
|
|
531
|
+
Return whether this Coxeter group is finite.
|
|
532
|
+
|
|
533
|
+
EXAMPLES::
|
|
534
|
+
|
|
535
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
536
|
+
sage: W = CoxGroup(['A', 5])
|
|
537
|
+
sage: W.is_finite()
|
|
538
|
+
True
|
|
539
|
+
sage: W = CoxGroup(['A', 3, 1])
|
|
540
|
+
sage: W.is_finite()
|
|
541
|
+
False
|
|
542
|
+
"""
|
|
543
|
+
return isFiniteType(self.x)
|
|
544
|
+
|
|
545
|
+
cpdef full_context(self) noexcept:
|
|
546
|
+
"""
|
|
547
|
+
Make all of the elements of a finite Coxeter group available.
|
|
548
|
+
|
|
549
|
+
Raises an error if ``self`` is not finite.
|
|
550
|
+
|
|
551
|
+
EXAMPLES::
|
|
552
|
+
|
|
553
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
554
|
+
sage: W = CoxGroup(['A', 2])
|
|
555
|
+
sage: W.full_context()
|
|
556
|
+
sage: W = CoxGroup(['A', 2,1])
|
|
557
|
+
sage: W.full_context()
|
|
558
|
+
Traceback (most recent call last):
|
|
559
|
+
...
|
|
560
|
+
TypeError: group needs to be finite
|
|
561
|
+
"""
|
|
562
|
+
if not self.is_finite():
|
|
563
|
+
raise TypeError("group needs to be finite")
|
|
564
|
+
cdef c_FiniteCoxGroup* fcoxgroup = <c_FiniteCoxGroup*>(self.x)
|
|
565
|
+
if not fcoxgroup.isFullContext():
|
|
566
|
+
fcoxgroup.fullContext()
|
|
567
|
+
|
|
568
|
+
def long_element(self):
|
|
569
|
+
"""
|
|
570
|
+
Return the longest word in a finite Coxeter group.
|
|
571
|
+
|
|
572
|
+
EXAMPLES::
|
|
573
|
+
|
|
574
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
575
|
+
sage: W = CoxGroup(['A', 5])
|
|
576
|
+
sage: W.long_element()
|
|
577
|
+
[1, 2, 1, 3, 2, 1, 4, 3, 2, 1, 5, 4, 3, 2, 1]
|
|
578
|
+
|
|
579
|
+
sage: W = CoxGroup(['A', 3, 1])
|
|
580
|
+
sage: W.long_element()
|
|
581
|
+
Traceback (most recent call last):
|
|
582
|
+
...
|
|
583
|
+
TypeError: group needs to be finite
|
|
584
|
+
"""
|
|
585
|
+
self.full_context()
|
|
586
|
+
cdef c_FiniteCoxGroup* fcoxgroup = <c_FiniteCoxGroup*>(self.x)
|
|
587
|
+
cdef CoxGroupElement w0 = CoxGroupElement(self, [])
|
|
588
|
+
w0.word = fcoxgroup.longest_coxword()
|
|
589
|
+
return w0
|
|
590
|
+
|
|
591
|
+
def __call__(self, w):
|
|
592
|
+
"""
|
|
593
|
+
Return a reduced expression for ``w``.
|
|
594
|
+
|
|
595
|
+
INPUT:
|
|
596
|
+
|
|
597
|
+
- ``w`` -- a word for an element of ``self``, not necessarily reduced
|
|
598
|
+
|
|
599
|
+
OUTPUT: a reduced expression for ``w``
|
|
600
|
+
|
|
601
|
+
EXAMPLES::
|
|
602
|
+
|
|
603
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
604
|
+
sage: W = CoxGroup(['A', 5])
|
|
605
|
+
sage: w = [1,1,3,5,4,5,4]
|
|
606
|
+
sage: W.__call__(w)
|
|
607
|
+
[3, 4, 5]
|
|
608
|
+
"""
|
|
609
|
+
return CoxGroupElement(self, w).reduced()
|
|
610
|
+
|
|
611
|
+
def coxeter_matrix(self):
|
|
612
|
+
"""
|
|
613
|
+
Return the Coxeter matrix for this Coxeter group.
|
|
614
|
+
|
|
615
|
+
EXAMPLES::
|
|
616
|
+
|
|
617
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
618
|
+
sage: W = CoxGroup(['A', 5])
|
|
619
|
+
sage: W.coxeter_matrix()
|
|
620
|
+
[1 3 2 2 2]
|
|
621
|
+
[3 1 3 2 2]
|
|
622
|
+
[2 3 1 3 2]
|
|
623
|
+
[2 2 3 1 3]
|
|
624
|
+
[2 2 2 3 1]
|
|
625
|
+
"""
|
|
626
|
+
from sage.matrix.constructor import matrix
|
|
627
|
+
rank = self.rank()
|
|
628
|
+
m = matrix(ZZ, rank, rank)
|
|
629
|
+
for i, ii in enumerate(self.cartan_type.index_set()):
|
|
630
|
+
ii = self.in_ordering[ii]-1
|
|
631
|
+
for j, jj in enumerate(self.cartan_type.index_set()):
|
|
632
|
+
jj = self.in_ordering[jj]-1
|
|
633
|
+
m[i,j] = self.x.M(ii, jj)
|
|
634
|
+
return m
|
|
635
|
+
|
|
636
|
+
def coxeter_graph(self):
|
|
637
|
+
"""
|
|
638
|
+
Return the Coxeter graph for this Coxeter group.
|
|
639
|
+
|
|
640
|
+
OUTPUT: a Sage graph
|
|
641
|
+
|
|
642
|
+
.. NOTE::
|
|
643
|
+
|
|
644
|
+
This uses the labels native to Coxeter3. This is useful
|
|
645
|
+
when trying to obtain the mapping between the labels of
|
|
646
|
+
Sage and Coxeter3.
|
|
647
|
+
|
|
648
|
+
EXAMPLES::
|
|
649
|
+
|
|
650
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
651
|
+
sage: W = CoxGroup(['A', 5])
|
|
652
|
+
sage: W.coxeter_graph()
|
|
653
|
+
Graph on 5 vertices
|
|
654
|
+
sage: W.coxeter_graph().edges(sort=True)
|
|
655
|
+
[(1, 2, None), (2, 3, None), (3, 4, None), (4, 5, None)]
|
|
656
|
+
"""
|
|
657
|
+
from sage.graphs.graph import Graph
|
|
658
|
+
g = Graph()
|
|
659
|
+
m = self.coxeter_matrix()
|
|
660
|
+
rank = self.rank()
|
|
661
|
+
for i, row in enumerate(m.rows()):
|
|
662
|
+
for j in range(i+1,rank):
|
|
663
|
+
if row[j] == 3:
|
|
664
|
+
g.add_edge(i+1, j+1)
|
|
665
|
+
elif row[j] > 4:
|
|
666
|
+
g.add_edge(i+1, j+1, row[j])
|
|
667
|
+
return g
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
cdef class CoxGroupElement:
|
|
671
|
+
def __init__(self, CoxGroup group, w, normal_form=True):
|
|
672
|
+
"""
|
|
673
|
+
TESTS::
|
|
674
|
+
|
|
675
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup, CoxGroupElement
|
|
676
|
+
sage: W = CoxGroup(['A', 5])
|
|
677
|
+
sage: w = CoxGroupElement(W, [2,1,2,1,1], normal_form=False); w
|
|
678
|
+
[2, 1, 2, 1, 1]
|
|
679
|
+
sage: w = CoxGroupElement(W, [1,1,4,5,4], normal_form=False); w
|
|
680
|
+
[1, 1, 4, 5, 4]
|
|
681
|
+
sage: w = CoxGroupElement(W, [1,1,4,5,4]); w
|
|
682
|
+
[4, 5, 4]
|
|
683
|
+
sage: W = CoxGroup(['A', 4])
|
|
684
|
+
sage: CoxGroupElement(W, [1,2,3,2,3])
|
|
685
|
+
[1, 3, 2]
|
|
686
|
+
sage: W = CoxGroup(['A', 4])
|
|
687
|
+
sage: w = CoxGroupElement(W, [1,2,3,2,3])
|
|
688
|
+
sage: del w
|
|
689
|
+
"""
|
|
690
|
+
self.group = (<CoxGroup>group).x
|
|
691
|
+
self._parent_group = group
|
|
692
|
+
self.word.reset()
|
|
693
|
+
for i in w:
|
|
694
|
+
self.word.append(self._parent_group.in_ordering[i])
|
|
695
|
+
|
|
696
|
+
if normal_form:
|
|
697
|
+
self.group.normalForm(self.word)
|
|
698
|
+
|
|
699
|
+
def _coxnumber(self):
|
|
700
|
+
"""
|
|
701
|
+
Return the internal integer used by Coxeter3 to represent this element.
|
|
702
|
+
|
|
703
|
+
TESTS::
|
|
704
|
+
|
|
705
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup, CoxGroupElement
|
|
706
|
+
sage: W = CoxGroup(['A', 4])
|
|
707
|
+
sage: w = CoxGroupElement(W, [1,2,3,2,3])
|
|
708
|
+
sage: w._coxnumber()
|
|
709
|
+
7
|
|
710
|
+
"""
|
|
711
|
+
return int(self.group.extendContext(self.word))
|
|
712
|
+
|
|
713
|
+
def __reduce__(self):
|
|
714
|
+
"""
|
|
715
|
+
EXAMPLES::
|
|
716
|
+
|
|
717
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
718
|
+
sage: W = CoxGroup(['A',5])
|
|
719
|
+
sage: w = W([1,2,3])
|
|
720
|
+
sage: TestSuite(w).run()
|
|
721
|
+
"""
|
|
722
|
+
return (CoxGroupElement, (self._parent_group, list(self)))
|
|
723
|
+
|
|
724
|
+
def __invert__(self):
|
|
725
|
+
"""
|
|
726
|
+
Return the inverse of this element.
|
|
727
|
+
|
|
728
|
+
EXAMPLES::
|
|
729
|
+
|
|
730
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
731
|
+
sage: W = CoxGroup(['A',5])
|
|
732
|
+
sage: w = W([1,2,3])
|
|
733
|
+
sage: ~w
|
|
734
|
+
[3, 2, 1]
|
|
735
|
+
"""
|
|
736
|
+
return CoxGroupElement(self._parent_group, reversed(self))
|
|
737
|
+
|
|
738
|
+
inverse = __invert__
|
|
739
|
+
|
|
740
|
+
cpdef CoxGroup parent_group(self) noexcept:
|
|
741
|
+
"""
|
|
742
|
+
Return the parent Coxeter group for this element.
|
|
743
|
+
|
|
744
|
+
EXAMPLES::
|
|
745
|
+
|
|
746
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
747
|
+
sage: W = CoxGroup(['A',5])
|
|
748
|
+
sage: w = W([1,2,3])
|
|
749
|
+
sage: w.parent_group()
|
|
750
|
+
Coxeter group of type A and rank 5
|
|
751
|
+
"""
|
|
752
|
+
return self._parent_group
|
|
753
|
+
|
|
754
|
+
def __getitem__(self, i):
|
|
755
|
+
"""
|
|
756
|
+
Return the `i`-th entry of this element.
|
|
757
|
+
|
|
758
|
+
EXAMPLES::
|
|
759
|
+
|
|
760
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
761
|
+
sage: W = CoxGroup(['A',5])
|
|
762
|
+
sage: w = W([1,2,3])
|
|
763
|
+
sage: w[0]
|
|
764
|
+
1
|
|
765
|
+
sage: w[2]
|
|
766
|
+
3
|
|
767
|
+
sage: w[:-2]
|
|
768
|
+
[1]
|
|
769
|
+
sage: w[-2:]
|
|
770
|
+
[2, 3]
|
|
771
|
+
sage: w[3:0:-1]
|
|
772
|
+
[3, 2]
|
|
773
|
+
sage: w[4]
|
|
774
|
+
Traceback (most recent call last):
|
|
775
|
+
...
|
|
776
|
+
IndexError: The index (4) is out of range.
|
|
777
|
+
"""
|
|
778
|
+
if isinstance(i, slice):
|
|
779
|
+
#Get the start, stop, and step from the slice
|
|
780
|
+
return [self[ii] for ii in range(*i.indices(len(self)))]
|
|
781
|
+
if i < 0:
|
|
782
|
+
i += len(self)
|
|
783
|
+
if i >= len(self):
|
|
784
|
+
raise IndexError("The index (%d) is out of range." % i)
|
|
785
|
+
|
|
786
|
+
return self._parent_group.out_ordering[self.word[i]]
|
|
787
|
+
|
|
788
|
+
def __repr__(self):
|
|
789
|
+
"""
|
|
790
|
+
Return a string representation of this CoxGroupElement as a list of generators.
|
|
791
|
+
|
|
792
|
+
EXAMPLES::
|
|
793
|
+
|
|
794
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
795
|
+
sage: W = CoxGroup(['A',5])
|
|
796
|
+
sage: w = W([1,2,3]); w
|
|
797
|
+
[1, 2, 3]
|
|
798
|
+
"""
|
|
799
|
+
return repr(list(self))
|
|
800
|
+
|
|
801
|
+
def __hash__(self):
|
|
802
|
+
"""
|
|
803
|
+
Return the hash of this element.
|
|
804
|
+
|
|
805
|
+
This is a hash of the tuple of the class name, the parent, and
|
|
806
|
+
a tuple of the reduced word.
|
|
807
|
+
|
|
808
|
+
EXAMPLES::
|
|
809
|
+
|
|
810
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
811
|
+
sage: W = CoxGroup(['A', 5])
|
|
812
|
+
sage: w = W([1,2,3])
|
|
813
|
+
sage: v = W([2,3,4])
|
|
814
|
+
sage: hash(w) == hash(v)
|
|
815
|
+
False
|
|
816
|
+
"""
|
|
817
|
+
return hash((self.__class__.__name__, self.parent_group(), tuple(self)))
|
|
818
|
+
|
|
819
|
+
def __richcmp__(CoxGroupElement self, other, int op):
|
|
820
|
+
"""
|
|
821
|
+
EXAMPLES::
|
|
822
|
+
|
|
823
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
824
|
+
sage: W = CoxGroup(['A', 5])
|
|
825
|
+
sage: V = CoxGroup(['A', 6])
|
|
826
|
+
sage: w1 = W([1,2,3])
|
|
827
|
+
sage: w2 = W([2,3,4])
|
|
828
|
+
sage: v1 = V([1,2,3])
|
|
829
|
+
sage: w1 == w1
|
|
830
|
+
True
|
|
831
|
+
sage: w1 != w2
|
|
832
|
+
True
|
|
833
|
+
sage: all([w1 < w2, w1 <= w2, w1 <= w1])
|
|
834
|
+
True
|
|
835
|
+
sage: all([w2 > w1, w2 >= w1, w2 >= w2])
|
|
836
|
+
True
|
|
837
|
+
sage: w1 == v1
|
|
838
|
+
False
|
|
839
|
+
sage: w1 != v1
|
|
840
|
+
True
|
|
841
|
+
"""
|
|
842
|
+
if type(other) is not type(self):
|
|
843
|
+
if op in (Py_LT, Py_LE, Py_GT, Py_GE):
|
|
844
|
+
return NotImplemented
|
|
845
|
+
return op == Py_NE
|
|
846
|
+
|
|
847
|
+
s_p = self.parent_group()
|
|
848
|
+
o_p = other.parent_group()
|
|
849
|
+
s_l = list(self)
|
|
850
|
+
o_l = list(other)
|
|
851
|
+
|
|
852
|
+
if op == Py_EQ:
|
|
853
|
+
return s_p == o_p and s_l == o_l
|
|
854
|
+
elif op == Py_NE:
|
|
855
|
+
return s_p != o_p or s_l != o_l
|
|
856
|
+
elif op == Py_LT:
|
|
857
|
+
return s_p < o_p or (s_p == o_p and s_l < o_l)
|
|
858
|
+
elif op == Py_LE:
|
|
859
|
+
return s_p < o_p or (s_p == o_p and s_l <= o_l)
|
|
860
|
+
elif op == Py_GT:
|
|
861
|
+
return s_p > o_p or (s_p == o_p and s_l > o_l)
|
|
862
|
+
elif op == Py_GE:
|
|
863
|
+
return s_p > o_p or (s_p == o_p and s_l >= o_l)
|
|
864
|
+
|
|
865
|
+
def __iter__(self):
|
|
866
|
+
"""
|
|
867
|
+
Return an iterator for the letters in the reduced word for this element.
|
|
868
|
+
|
|
869
|
+
EXAMPLES::
|
|
870
|
+
|
|
871
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
872
|
+
sage: W = CoxGroup(['A',5])
|
|
873
|
+
sage: w = W([1,2,3])
|
|
874
|
+
sage: [a for a in w]
|
|
875
|
+
[1, 2, 3]
|
|
876
|
+
"""
|
|
877
|
+
return (self[i] for i in range(len(self)))
|
|
878
|
+
|
|
879
|
+
def __len__(self):
|
|
880
|
+
"""
|
|
881
|
+
Return the length of this element.
|
|
882
|
+
|
|
883
|
+
EXAMPLES::
|
|
884
|
+
|
|
885
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
886
|
+
sage: W = CoxGroup(['A',5])
|
|
887
|
+
sage: w = W([1,2,3])
|
|
888
|
+
sage: len(w)
|
|
889
|
+
3
|
|
890
|
+
"""
|
|
891
|
+
return self.word.length()
|
|
892
|
+
|
|
893
|
+
def left_descents(self):
|
|
894
|
+
"""
|
|
895
|
+
Return the left descent set of this element.
|
|
896
|
+
|
|
897
|
+
EXAMPLES::
|
|
898
|
+
|
|
899
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
900
|
+
sage: W = CoxGroup(['A',5])
|
|
901
|
+
sage: w = W([1,2,1])
|
|
902
|
+
sage: w.left_descents()
|
|
903
|
+
[1, 2]
|
|
904
|
+
"""
|
|
905
|
+
return LFlags_to_list(self._parent_group, self.group.ldescent(self.word))
|
|
906
|
+
|
|
907
|
+
def right_descents(self):
|
|
908
|
+
"""
|
|
909
|
+
Return the right descent set of this element.
|
|
910
|
+
|
|
911
|
+
EXAMPLES::
|
|
912
|
+
|
|
913
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
914
|
+
sage: W = CoxGroup(['A',5])
|
|
915
|
+
sage: w = W([1,2,1])
|
|
916
|
+
sage: w.right_descents()
|
|
917
|
+
[1, 2]
|
|
918
|
+
"""
|
|
919
|
+
return LFlags_to_list(self._parent_group, self.group.rdescent(self.word))
|
|
920
|
+
|
|
921
|
+
def bruhat_le(self, w):
|
|
922
|
+
"""
|
|
923
|
+
Return whether u = (self) is less than w in Bruhat order.
|
|
924
|
+
|
|
925
|
+
EXAMPLES::
|
|
926
|
+
|
|
927
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
928
|
+
sage: W = CoxGroup(['A',5])
|
|
929
|
+
sage: w = W([1,2,3,4,5,4])
|
|
930
|
+
sage: v = W([1,2,4,5,4])
|
|
931
|
+
sage: v.bruhat_le(w)
|
|
932
|
+
True
|
|
933
|
+
sage: w.bruhat_le(w)
|
|
934
|
+
True
|
|
935
|
+
sage: w.bruhat_le(v)
|
|
936
|
+
False
|
|
937
|
+
"""
|
|
938
|
+
cdef CoxGroupElement ww = CoxGroupElement(self._parent_group, w)
|
|
939
|
+
return self.group.inOrder(self.word, ww.word)
|
|
940
|
+
|
|
941
|
+
def is_two_sided_descent(self, s):
|
|
942
|
+
"""
|
|
943
|
+
Return whether ``s`` is a two-sided descent of ``self``.
|
|
944
|
+
|
|
945
|
+
EXAMPLES::
|
|
946
|
+
|
|
947
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
948
|
+
sage: W = CoxGroup(['A',2])
|
|
949
|
+
sage: x = W([1,2,1])
|
|
950
|
+
sage: x.is_two_sided_descent(1)
|
|
951
|
+
True
|
|
952
|
+
"""
|
|
953
|
+
cdef Generator ss = self._parent_group.in_ordering[s]
|
|
954
|
+
return self.group.isDescent(self.word, s)
|
|
955
|
+
|
|
956
|
+
cdef CoxGroupElement _new(self) noexcept:
|
|
957
|
+
"""
|
|
958
|
+
Return a new copy of this element.
|
|
959
|
+
"""
|
|
960
|
+
cdef CoxGroupElement res = CoxGroupElement(self.parent_group(), [])
|
|
961
|
+
res.word = self.word
|
|
962
|
+
return res
|
|
963
|
+
|
|
964
|
+
def coatoms(self):
|
|
965
|
+
"""
|
|
966
|
+
Return the coatoms of this element in Bruhat order.
|
|
967
|
+
|
|
968
|
+
EXAMPLES::
|
|
969
|
+
|
|
970
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
971
|
+
sage: W = CoxGroup(['A',2])
|
|
972
|
+
sage: W([1,2,1]).coatoms()
|
|
973
|
+
[[2, 1], [1, 2]]
|
|
974
|
+
sage: W([]).coatoms()
|
|
975
|
+
[]
|
|
976
|
+
"""
|
|
977
|
+
cdef c_List_CoxWord list = c_List_CoxWord(0)
|
|
978
|
+
self.group.coatoms(list, self.word)
|
|
979
|
+
|
|
980
|
+
coatoms = []
|
|
981
|
+
|
|
982
|
+
cdef Length i = 0
|
|
983
|
+
cdef CoxGroupElement res
|
|
984
|
+
for i in range(list.size()):
|
|
985
|
+
res = self._new()
|
|
986
|
+
res.word = list[i]
|
|
987
|
+
coatoms.append(res)
|
|
988
|
+
return coatoms
|
|
989
|
+
|
|
990
|
+
def normal_form(self):
|
|
991
|
+
"""
|
|
992
|
+
Return ``self`` in normal form.
|
|
993
|
+
|
|
994
|
+
This is the lexicographically minimal reduced word for
|
|
995
|
+
``self``.
|
|
996
|
+
|
|
997
|
+
EXAMPLES::
|
|
998
|
+
|
|
999
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup, CoxGroupElement
|
|
1000
|
+
sage: W = CoxGroup(['A', 5])
|
|
1001
|
+
sage: w = CoxGroupElement(W, [2,1,2], normal_form=False); w
|
|
1002
|
+
[2, 1, 2]
|
|
1003
|
+
sage: w.normal_form()
|
|
1004
|
+
[1, 2, 1]
|
|
1005
|
+
"""
|
|
1006
|
+
cdef CoxGroupElement res = self._new()
|
|
1007
|
+
self.group.normalForm(res.word)
|
|
1008
|
+
return res
|
|
1009
|
+
|
|
1010
|
+
def reduced(self):
|
|
1011
|
+
"""
|
|
1012
|
+
Return a reduced word for this element.
|
|
1013
|
+
|
|
1014
|
+
EXAMPLES::
|
|
1015
|
+
|
|
1016
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup, CoxGroupElement
|
|
1017
|
+
sage: W = CoxGroup(['A', 5])
|
|
1018
|
+
sage: w = CoxGroupElement(W, [2,1,2,1,1], normal_form=False); w
|
|
1019
|
+
[2, 1, 2, 1, 1]
|
|
1020
|
+
sage: w.reduced()
|
|
1021
|
+
[1, 2, 1]
|
|
1022
|
+
"""
|
|
1023
|
+
cdef CoxGroupElement res = self._new()
|
|
1024
|
+
self.group.reduced(res.word, self.word)
|
|
1025
|
+
return res
|
|
1026
|
+
|
|
1027
|
+
def __mul__(CoxGroupElement self, CoxGroupElement y):
|
|
1028
|
+
"""
|
|
1029
|
+
EXAMPLES::
|
|
1030
|
+
|
|
1031
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
1032
|
+
sage: W = CoxGroup(['A', 5])
|
|
1033
|
+
sage: W([1]) * W([1])
|
|
1034
|
+
[]
|
|
1035
|
+
sage: W([1,2]) * W([1])
|
|
1036
|
+
[1, 2, 1]
|
|
1037
|
+
"""
|
|
1038
|
+
cdef CoxGroupElement res = self._new()
|
|
1039
|
+
self.group.prod(res.word, y.word)
|
|
1040
|
+
return res
|
|
1041
|
+
|
|
1042
|
+
def poincare_polynomial(self):
|
|
1043
|
+
"""
|
|
1044
|
+
Return the Poincaré polynomial associated with the Bruhat
|
|
1045
|
+
interval between the identity element and this one.
|
|
1046
|
+
|
|
1047
|
+
EXAMPLES::
|
|
1048
|
+
|
|
1049
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
1050
|
+
sage: W = CoxGroup(['A', 5])
|
|
1051
|
+
sage: W([]).poincare_polynomial()
|
|
1052
|
+
1
|
|
1053
|
+
sage: W([1,2,1]).poincare_polynomial()
|
|
1054
|
+
t^3 + 2*t^2 + 2*t + 1
|
|
1055
|
+
"""
|
|
1056
|
+
cdef CoxGroup W = self.parent_group()
|
|
1057
|
+
cdef c_List_CoxWord result = c_List_CoxWord(0)
|
|
1058
|
+
cdef CoxGroupElement id = CoxGroupElement(W, [])
|
|
1059
|
+
cdef CoxGroupElement ww = CoxGroupElement(W, self)
|
|
1060
|
+
interval(result, W.x[0], id.word, ww.word)
|
|
1061
|
+
|
|
1062
|
+
cdef list coefficients = [0]*(len(ww)+1)
|
|
1063
|
+
cdef size_t j
|
|
1064
|
+
for j in range(result.size()):
|
|
1065
|
+
coefficients[result[j].length()] += 1
|
|
1066
|
+
return ZZ['t'](coefficients)
|
|
1067
|
+
|
|
1068
|
+
def kazhdan_lusztig_polynomial(self, v):
|
|
1069
|
+
"""
|
|
1070
|
+
Return the Kazhdan-Lusztig polynomial `P_{u,v}` where `u` is ``self``.
|
|
1071
|
+
|
|
1072
|
+
Currently this is a bit inefficient as it constructs the
|
|
1073
|
+
polynomial from its string representation.
|
|
1074
|
+
|
|
1075
|
+
EXAMPLES::
|
|
1076
|
+
|
|
1077
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup
|
|
1078
|
+
sage: W = CoxGroup(['A', 2])
|
|
1079
|
+
sage: W([]).kazhdan_lusztig_polynomial([1,2,1])
|
|
1080
|
+
1
|
|
1081
|
+
sage: W([1,2,1]).kazhdan_lusztig_polynomial([])
|
|
1082
|
+
0
|
|
1083
|
+
"""
|
|
1084
|
+
cdef CoxGroupElement vv
|
|
1085
|
+
if not isinstance(v, CoxGroupElement):
|
|
1086
|
+
vv = CoxGroupElement(self._parent_group, v)
|
|
1087
|
+
else:
|
|
1088
|
+
vv = v
|
|
1089
|
+
|
|
1090
|
+
ZZq = PolynomialRing(ZZ, 'q')
|
|
1091
|
+
if not self.group.inOrder(self.word, vv.word):
|
|
1092
|
+
return ZZq.zero()
|
|
1093
|
+
|
|
1094
|
+
cdef CoxNbr x = self.group.extendContext(self.word)
|
|
1095
|
+
cdef CoxNbr y = self.group.extendContext(vv.word)
|
|
1096
|
+
cdef c_KLPol kl_poly = self.group.klPol(x, y)
|
|
1097
|
+
if kl_poly.isZero():
|
|
1098
|
+
return ZZq.zero()
|
|
1099
|
+
cdef size_t i
|
|
1100
|
+
l = [kl_poly[i] for i in range(kl_poly.deg()+1)]
|
|
1101
|
+
return ZZq(l)
|
|
1102
|
+
|
|
1103
|
+
def mu_coefficient(self, v):
|
|
1104
|
+
r"""
|
|
1105
|
+
Return the mu coefficient `\mu(u,v)` where `u` is this element.
|
|
1106
|
+
|
|
1107
|
+
EXAMPLES::
|
|
1108
|
+
|
|
1109
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
1110
|
+
sage: W = CoxGroup(['A',5])
|
|
1111
|
+
sage: w = W([1,2,3,4,5,4])
|
|
1112
|
+
sage: v = W([1,2,4,5,4])
|
|
1113
|
+
sage: w.mu_coefficient(v)
|
|
1114
|
+
0
|
|
1115
|
+
sage: w.mu_coefficient(w)
|
|
1116
|
+
0
|
|
1117
|
+
sage: v.mu_coefficient(w)
|
|
1118
|
+
1
|
|
1119
|
+
"""
|
|
1120
|
+
cdef CoxGroupElement vv = CoxGroupElement(self._parent_group, v)
|
|
1121
|
+
cdef CoxNbr x = self.group.extendContext(self.word)
|
|
1122
|
+
cdef CoxNbr y = self.group.extendContext(vv.word)
|
|
1123
|
+
return ZZ(self.group.mu(x,y))
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
cdef LFlags_to_list(CoxGroup parent, LFlags f) noexcept:
|
|
1127
|
+
"""
|
|
1128
|
+
Return the right descent set of this element.
|
|
1129
|
+
|
|
1130
|
+
EXAMPLES::
|
|
1131
|
+
|
|
1132
|
+
sage: from sage.libs.coxeter3.coxeter import *
|
|
1133
|
+
sage: W = CoxGroup(['A',5])
|
|
1134
|
+
sage: w = W([1,2,1])
|
|
1135
|
+
sage: w.right_descents()
|
|
1136
|
+
[1, 2]
|
|
1137
|
+
"""
|
|
1138
|
+
cdef Generator s
|
|
1139
|
+
cdef LFlags f1 = f
|
|
1140
|
+
l = []
|
|
1141
|
+
while f1:
|
|
1142
|
+
s = firstBit(f1)
|
|
1143
|
+
l.append(parent.out_ordering[s+1])
|
|
1144
|
+
f1 = f1 & (f1-1)
|
|
1145
|
+
return l
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
class CoxGroupIterator():
|
|
1149
|
+
def __init__(self, group):
|
|
1150
|
+
"""
|
|
1151
|
+
A class used to iterate over all of the elements of a Coxeter group.
|
|
1152
|
+
|
|
1153
|
+
.. NOTE::
|
|
1154
|
+
|
|
1155
|
+
This will construct all of the elements of the group within
|
|
1156
|
+
Coxeter3. For some groups, this may be too large to fit
|
|
1157
|
+
into memory.
|
|
1158
|
+
|
|
1159
|
+
EXAMPLES::
|
|
1160
|
+
|
|
1161
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup, CoxGroupIterator
|
|
1162
|
+
sage: W = CoxGroup(['A', 2])
|
|
1163
|
+
sage: it = CoxGroupIterator(W)
|
|
1164
|
+
sage: [next(it) for i in range(W.order())]
|
|
1165
|
+
[[], [1], [2], [1, 2], [2, 1], [1, 2, 1]]
|
|
1166
|
+
"""
|
|
1167
|
+
self.group = group
|
|
1168
|
+
self.order = group.order()
|
|
1169
|
+
self.n = 0
|
|
1170
|
+
self.group.full_context()
|
|
1171
|
+
|
|
1172
|
+
def __iter__(self):
|
|
1173
|
+
"""
|
|
1174
|
+
Return self, as per the iterator protocol.
|
|
1175
|
+
|
|
1176
|
+
EXAMPLES::
|
|
1177
|
+
|
|
1178
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup, CoxGroupIterator
|
|
1179
|
+
sage: W = CoxGroup(['A', 2])
|
|
1180
|
+
sage: it = iter(W)
|
|
1181
|
+
sage: it is iter(it)
|
|
1182
|
+
True
|
|
1183
|
+
"""
|
|
1184
|
+
return self
|
|
1185
|
+
|
|
1186
|
+
def __next__(self):
|
|
1187
|
+
"""
|
|
1188
|
+
Return the next element in the associated Coxeter group.
|
|
1189
|
+
|
|
1190
|
+
EXAMPLES::
|
|
1191
|
+
|
|
1192
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup, CoxGroupIterator
|
|
1193
|
+
sage: W = CoxGroup(['A', 2])
|
|
1194
|
+
sage: it = CoxGroupIterator(W)
|
|
1195
|
+
sage: next(it)
|
|
1196
|
+
[]
|
|
1197
|
+
"""
|
|
1198
|
+
if self.n >= self.order:
|
|
1199
|
+
raise StopIteration
|
|
1200
|
+
cdef CoxGroupElement w = self.group([])
|
|
1201
|
+
|
|
1202
|
+
(<CoxGroup>self.group).x.prod_nbr(w.word, self.n)
|
|
1203
|
+
self.n += 1
|
|
1204
|
+
return w
|
|
1205
|
+
|
|
1206
|
+
next = __next__
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
CoxGroup_cache = {}
|
|
1210
|
+
|
|
1211
|
+
|
|
1212
|
+
def get_CoxGroup(cartan_type):
|
|
1213
|
+
"""
|
|
1214
|
+
TESTS::
|
|
1215
|
+
|
|
1216
|
+
sage: from sage.libs.coxeter3.coxeter import get_CoxGroup as CoxGroup, CoxGroupIterator
|
|
1217
|
+
sage: W = CoxGroup(['A', 2])
|
|
1218
|
+
"""
|
|
1219
|
+
from sage.combinat.root_system.cartan_type import CartanType
|
|
1220
|
+
cartan_type = CartanType(cartan_type)
|
|
1221
|
+
if cartan_type not in CoxGroup_cache:
|
|
1222
|
+
CoxGroup_cache[cartan_type] = CoxGroup(cartan_type)
|
|
1223
|
+
return CoxGroup_cache[cartan_type]
|