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