Skip to content

Commit 81ae887

Browse files
author
Release Manager
committed
Trac #34912: Reduced words of ReflectionGroup elements are not well-defined
We cannot use it for hashing as I found the following: {{{ sage: G4 = ReflectionGroup(4) sage: elt = G4[22] sage: elt (1,12)(2,24)(3,19)(4,22)(5,17)(6,20)(7,23)(8,9)(10,21)(11,13)(14,18)(15, 16) sage: y = (elt * G4.gen(1)) * G4.gen(1) * G4.gen(1) sage: elt == y True sage: hash(elt) == hash(y) False sage: elt._reduced_word [0, 0, 1, 0, 0, 1] sage: y._reduced_word [1, 0, 0, 1, 0, 0] }}} Either we figure out how to make this consistent or we need to change the hashing. URL: https://trac.sagemath.org/34912 Reported by: tscrim Ticket author(s): Travis Scrimshaw, Christian Stump Reviewer(s): Christian Stump, Travis Scrimshaw
2 parents b17e117 + 14d6f61 commit 81ae887

File tree

5 files changed

+97
-59
lines changed

5 files changed

+97
-59
lines changed

src/sage/categories/coxeter_groups.py

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,11 @@ def braid_group_as_finitely_presented_group(self):
236236
sage: W.braid_group_as_finitely_presented_group()
237237
Finitely presented group < S1, S2 | (S1*S2)^2*(S1^-1*S2^-1)^2 >
238238
239-
sage: W = ReflectionGroup(['B',3], index_set=["AA","BB",5]) # optional - gap3
240-
sage: W.braid_group_as_finitely_presented_group() # optional - gap3
239+
sage: W = ReflectionGroup(['B',3], index_set=["AA","BB","5"]) # optional - gap3
240+
sage: W.braid_group_as_finitely_presented_group() # optional - gap3
241241
Finitely presented group < SAA, SBB, S5 |
242-
SAA*SBB*SAA*SBB^-1*SAA^-1*SBB^-1, SAA*S5*SAA^-1*S5^-1,
243-
(SBB*S5)^2*(SBB^-1*S5^-1)^2 >
242+
(SAA*SBB)^2*(SAA^-1*SBB^-1)^2, SAA*S5*SAA^-1*S5^-1,
243+
SBB*S5*SBB*S5^-1*SBB^-1*S5^-1 >
244244
"""
245245
from sage.groups.free_group import FreeGroup
246246
from sage.misc.misc_c import prod
@@ -285,25 +285,25 @@ def braid_orbit(self, word):
285285
sage: sorted(W.braid_orbit([2,1,1,2,1]))
286286
[[1, 2, 1, 1, 2], [2, 1, 1, 2, 1], [2, 1, 2, 1, 2], [2, 2, 1, 2, 2]]
287287
288-
sage: W = ReflectionGroup(['A',3], index_set=["AA","BB",5]) # optional - gap3
289-
sage: w = W.long_element() # optional - gap3
290-
sage: W.braid_orbit(w.reduced_word()) # optional - gap3
291-
[['AA', 5, 'BB', 5, 'AA', 'BB'],
292-
['AA', 'BB', 5, 'BB', 'AA', 'BB'],
293-
[5, 'BB', 'AA', 5, 'BB', 5],
294-
['BB', 5, 'AA', 'BB', 5, 'AA'],
295-
[5, 'BB', 5, 'AA', 'BB', 5],
296-
['BB', 5, 'AA', 'BB', 'AA', 5],
297-
[5, 'AA', 'BB', 'AA', 5, 'BB'],
298-
['BB', 'AA', 5, 'BB', 5, 'AA'],
299-
['AA', 'BB', 'AA', 5, 'BB', 'AA'],
300-
[5, 'BB', 'AA', 'BB', 5, 'BB'],
301-
['BB', 'AA', 5, 'BB', 'AA', 5],
302-
[5, 'AA', 'BB', 5, 'AA', 'BB'],
303-
['AA', 'BB', 5, 'AA', 'BB', 'AA'],
304-
['BB', 5, 'BB', 'AA', 'BB', 5],
305-
['AA', 5, 'BB', 'AA', 5, 'BB'],
306-
['BB', 'AA', 'BB', 5, 'BB', 'AA']]
288+
sage: W = ReflectionGroup(['A',3], index_set=["AA","BB","5"]) # optional - gap3
289+
sage: w = W.long_element() # optional - gap3
290+
sage: W.braid_orbit(w.reduced_word()) # optional - gap3
291+
[['BB', '5', 'AA', 'BB', '5', 'AA'],
292+
['5', 'BB', '5', 'AA', 'BB', '5'],
293+
['BB', 'AA', 'BB', '5', 'BB', 'AA'],
294+
['AA', '5', 'BB', 'AA', '5', 'BB'],
295+
['5', 'AA', 'BB', 'AA', '5', 'BB'],
296+
['AA', 'BB', '5', 'AA', 'BB', 'AA'],
297+
['AA', 'BB', 'AA', '5', 'BB', 'AA'],
298+
['AA', 'BB', '5', 'BB', 'AA', 'BB'],
299+
['BB', 'AA', '5', 'BB', 'AA', '5'],
300+
['BB', '5', 'AA', 'BB', 'AA', '5'],
301+
['AA', '5', 'BB', '5', 'AA', 'BB'],
302+
['5', 'BB', 'AA', '5', 'BB', '5'],
303+
['5', 'BB', 'AA', 'BB', '5', 'BB'],
304+
['5', 'AA', 'BB', '5', 'AA', 'BB'],
305+
['BB', '5', 'BB', 'AA', 'BB', '5'],
306+
['BB', 'AA', '5', 'BB', '5', 'AA']]
307307
308308
.. TODO::
309309
@@ -1608,25 +1608,25 @@ def reduced_words(self):
16081608
sage: sorted(w.reduced_words())
16091609
[[2, 3, 4, 2], [3, 2, 4, 2], [3, 4, 2, 4]]
16101610
1611-
sage: W = ReflectionGroup(['A',3], index_set=["AA","BB",5]) # optional - gap3
1612-
sage: w = W.long_element() # optional - gap3
1613-
sage: w.reduced_words() # optional - gap3
1614-
[['AA', 5, 'BB', 5, 'AA', 'BB'],
1615-
['AA', 'BB', 5, 'BB', 'AA', 'BB'],
1616-
[5, 'BB', 'AA', 5, 'BB', 5],
1617-
['BB', 5, 'AA', 'BB', 5, 'AA'],
1618-
[5, 'BB', 5, 'AA', 'BB', 5],
1619-
['BB', 5, 'AA', 'BB', 'AA', 5],
1620-
[5, 'AA', 'BB', 'AA', 5, 'BB'],
1621-
['BB', 'AA', 5, 'BB', 5, 'AA'],
1622-
['AA', 'BB', 'AA', 5, 'BB', 'AA'],
1623-
[5, 'BB', 'AA', 'BB', 5, 'BB'],
1624-
['BB', 'AA', 5, 'BB', 'AA', 5],
1625-
[5, 'AA', 'BB', 5, 'AA', 'BB'],
1626-
['AA', 'BB', 5, 'AA', 'BB', 'AA'],
1627-
['BB', 5, 'BB', 'AA', 'BB', 5],
1628-
['AA', 5, 'BB', 'AA', 5, 'BB'],
1629-
['BB', 'AA', 'BB', 5, 'BB', 'AA']]
1611+
sage: W = ReflectionGroup(['A',3], index_set=["AA","BB","5"]) # optional - gap3
1612+
sage: w = W.long_element() # optional - gap3
1613+
sage: w.reduced_words() # optional - gap3
1614+
[['BB', '5', 'AA', 'BB', '5', 'AA'],
1615+
['5', 'BB', '5', 'AA', 'BB', '5'],
1616+
['BB', 'AA', 'BB', '5', 'BB', 'AA'],
1617+
['AA', '5', 'BB', 'AA', '5', 'BB'],
1618+
['5', 'AA', 'BB', 'AA', '5', 'BB'],
1619+
['AA', 'BB', '5', 'AA', 'BB', 'AA'],
1620+
['AA', 'BB', 'AA', '5', 'BB', 'AA'],
1621+
['AA', 'BB', '5', 'BB', 'AA', 'BB'],
1622+
['BB', 'AA', '5', 'BB', 'AA', '5'],
1623+
['BB', '5', 'AA', 'BB', 'AA', '5'],
1624+
['AA', '5', 'BB', '5', 'AA', 'BB'],
1625+
['5', 'BB', 'AA', '5', 'BB', '5'],
1626+
['5', 'BB', 'AA', 'BB', '5', 'BB'],
1627+
['5', 'AA', 'BB', '5', 'AA', 'BB'],
1628+
['BB', '5', 'BB', 'AA', 'BB', '5'],
1629+
['BB', 'AA', '5', 'BB', '5', 'AA']]
16301630
16311631
.. TODO::
16321632

src/sage/combinat/root_system/reflection_group_complex.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@
205205
from sage.sets.family import Family
206206
from sage.structure.unique_representation import UniqueRepresentation
207207
from sage.groups.perm_gps.permgroup import PermutationGroup_generic
208+
from sage.combinat.permutation import Permutation
208209
from sage.rings.integer_ring import ZZ
209210
from sage.rings.rational_field import QQ
210211
from sage.matrix.all import Matrix, identity_matrix
@@ -367,17 +368,21 @@ def _repr_(self):
367368
type_str = type_str[:-3]
368369
return 'Reducible complex reflection group of rank %s and type %s' % (self._rank, type_str)
369370

370-
def __iter__(self):
371+
def iteration_tracking_words(self):
371372
r"""
372-
Return an iterator going through all elements in ``self``.
373+
Return an iterator going through all elements in ``self`` that
374+
tracks the reduced expressions.
375+
376+
This can be much slower than using the iteration as a permutation
377+
group with strong generating set.
373378
374379
EXAMPLES::
375380
376381
sage: W = ReflectionGroup((1,1,3)) # optional - gap3
377-
sage: for w in W: w # optional - gap3
382+
sage: for w in W.iteration_tracking_words(): w # optional - gap3
378383
()
379-
(1,3)(2,5)(4,6)
380384
(1,4)(2,3)(5,6)
385+
(1,3)(2,5)(4,6)
381386
(1,6,2)(3,5,4)
382387
(1,2,6)(3,4,5)
383388
(1,5)(2,4)(3,6)

src/sage/combinat/root_system/reflection_group_element.pyx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,21 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement):
7171
7272
sage: WB_hash.intersection(WC_hash) # optional - gap3
7373
set()
74+
75+
Check that :trac:`34912` is fixed::
76+
77+
sage: G4 = ReflectionGroup(4) # optional - gap3
78+
sage: g0, g1 = G4.gens() # optional - gap3
79+
sage: elt = g0^2 * g1 * g0^2 * g1 # optional - gap3
80+
sage: elt # optional - gap3
81+
(1,12)(2,24)(3,19)(4,22)(5,17)(6,20)(7,23)(8,9)(10,21)(11,13)(14,18)(15,16)
82+
sage: y = (elt * G4.gen(1)) * G4.gen(1) * G4.gen(1) # optional - gap3
83+
sage: elt == y # optional - gap3
84+
True
85+
sage: hash(elt) == hash(y) # optional - gap3
86+
True
7487
"""
75-
return hash(self._parent) | hash(tuple(self._reduced_word))
88+
return hash(self._parent) | super().__hash__()
7689

7790
def reduced_word(self):
7891
r"""
@@ -136,7 +149,7 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement):
136149
EXAMPLES::
137150
138151
sage: W = ReflectionGroup(4) # optional - gap3
139-
sage: for w in W: # optional - gap3
152+
sage: for w in W.iteration_tracking_words(): # optional - gap3
140153
....: print("{} {}".format(w.reduced_word(), w.length()))
141154
[] 0
142155
[1] 1
@@ -162,6 +175,11 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement):
162175
[1, 2, 2, 1, 1] 5
163176
[1, 1, 2, 1, 1, 2] 6
164177
[1, 1, 2, 2, 1, 1] 6
178+
179+
sage: data = {w: (len(w.reduced_word()), w.length()) # optional - gap3
180+
....: for w in W.iteration_tracking_words()}
181+
sage: for w in W: # optional - gap3
182+
....: assert data[w] == (w.length(), w.length()), w
165183
"""
166184
return ZZ(len(self.reduced_word()))
167185

@@ -178,10 +196,13 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement):
178196
179197
EXAMPLES::
180198
181-
sage: W = ReflectionGroup((3,1,2)) # optional - gap3
182-
sage: for w in W: # optional - gap3
183-
....: w.reduced_word() # optional - gap3
184-
....: [w.to_matrix(), w.to_matrix(on_space="dual")] # optional - gap3
199+
sage: W = ReflectionGroup((3,1,2)) # optional - gap3
200+
sage: data = {w: [w.to_matrix(), w.to_matrix(on_space="dual")] for w in W} # optional - gap3
201+
sage: for w in W.iteration_tracking_words(): # optional - gap3
202+
....: w.reduced_word() # optional - gap3
203+
....: mats = [w.to_matrix(), w.to_matrix(on_space="dual")] # optional - gap3
204+
....: mats
205+
....: assert data[w] == mats
185206
[]
186207
[
187208
[1 0] [1 0]
@@ -525,7 +546,8 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement):
525546
EXAMPLES::
526547
527548
sage: W = ReflectionGroup(4) # optional - gap3
528-
sage: for w in W: w.reflection_eigenvalues() # optional - gap3
549+
sage: for w in W.iteration_tracking_words(): # optional - gap3
550+
....: w.reflection_eigenvalues()
529551
[0, 0]
530552
[1/3, 0]
531553
[1/3, 0]
@@ -550,6 +572,10 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement):
550572
[2/3, 0]
551573
[1/2, 1/2]
552574
[1/4, 3/4]
575+
576+
sage: data = {w: w.reflection_eigenvalues() for w in W} # optional - gap3
577+
sage: all(w.reflection_eigenvalues() == data[w] for w in W.iteration_tracking_words()) # optional - gap3
578+
True
553579
"""
554580
return self._parent.reflection_eigenvalues(self, is_class_representative=is_class_representative)
555581

@@ -561,7 +587,8 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement):
561587
EXAMPLES::
562588
563589
sage: W = ReflectionGroup(4) # optional - gap3
564-
sage: for w in W: print(w.galois_conjugates()) # optional - gap3
590+
sage: for w in W.iteration_tracking_words(): # optional - gap3
591+
....: print(w.galois_conjugates())
565592
[[1 0]
566593
[0 1]]
567594
[[ 1 0]
@@ -650,6 +677,10 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement):
650677
[ 2/3*E(3) - 2/3*E(3)^2 1/3*E(3) - 1/3*E(3)^2],
651678
[ 1/3*E(3) - 1/3*E(3)^2 -1/3*E(3) + 1/3*E(3)^2]
652679
[-2/3*E(3) + 2/3*E(3)^2 -1/3*E(3) + 1/3*E(3)^2]]
680+
681+
sage: data = {w: w.galois_conjugates() for w in W} # optional - gap3
682+
sage: all(w.galois_conjugates() == data[w] for w in W.iteration_tracking_words()) # optional - gap3
683+
True
653684
"""
654685
rk = self._parent.rank()
655686
M = self.to_matrix().list()

src/sage/combinat/root_system/reflection_group_real.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ def coxeter_diagram(self):
609609
EXAMPLES::
610610
611611
sage: G = ReflectionGroup(['B',3]) # optional - gap3
612-
sage: sorted(G.coxeter_diagram().edges(labels=True)) # optional - gap3
612+
sage: G.coxeter_diagram().edges(labels=True, sort=True) # optional - gap3
613613
[(1, 2, 4), (2, 3, 3)]
614614
"""
615615
from sage.graphs.graph import Graph

src/sage/combinat/subword_complex.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
sage: Q = I + W.w0.coxeter_sorting_word(I)
9191
sage: S = SubwordComplex(Q,W.w0)
9292
sage: S.brick_polytope()
93-
doctest:...: RuntimeWarning: the polytope is build with rational vertices
93+
doctest:...: RuntimeWarning: the polytope is built with rational vertices
9494
A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 32 vertices
9595
9696
AUTHORS:
@@ -768,7 +768,7 @@ def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14,
768768
sage: Q = c.reduced_word()*2 + W.w0.coxeter_sorting_word(c) # optional - gap3
769769
sage: SC = SubwordComplex(Q, W.w0) # optional - gap3
770770
sage: F = SC[15]; F.plot() # optional - gap3
771-
Graphics object consisting of 52 graphics primitives
771+
Graphics object consisting of 53 graphics primitives
772772
773773
TESTS::
774774
@@ -1696,7 +1696,7 @@ def minkowski_summand(self, i):
16961696
else:
16971697
from sage.rings.cc import CC
16981698
from warnings import warn
1699-
warn("the polytope is build with rational vertices", RuntimeWarning)
1699+
warn("the polytope is built with rational vertices", RuntimeWarning)
17001700
min_sum = [[QQ(CC(v)) for v in F.extended_weight_configuration()[i]] for F in self]
17011701
return Polyhedron(min_sum)
17021702

@@ -1737,6 +1737,8 @@ def brick_polytope(self, coefficients=None):
17371737
sage: c = W.index_set(); Q = c + tuple(W.w0.coxeter_sorting_word(c)) # optional - gap3
17381738
sage: SC = SubwordComplex(Q,W.w0) # optional - gap3
17391739
sage: SC.brick_polytope() # optional - gap3
1740+
doctest:...:
1741+
RuntimeWarning: the polytope is built with rational vertices
17401742
A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 32 vertices
17411743
"""
17421744
BV = self.brick_vectors(coefficients=coefficients)
@@ -1747,7 +1749,7 @@ def brick_polytope(self, coefficients=None):
17471749
else:
17481750
from sage.rings.cc import CC
17491751
from warnings import warn
1750-
warn("the polytope is build with rational vertices", RuntimeWarning)
1752+
warn("the polytope is built with rational vertices", RuntimeWarning)
17511753
BV = [[QQ(CC(v).real()) for v in V] for V in BV]
17521754
return Polyhedron(BV)
17531755

0 commit comments

Comments
 (0)