passagemath-groups 10.6.45__cp314-cp314-macosx_13_0_arm64.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_groups/.dylibs/libgap.10.dylib +0 -0
- passagemath_groups/.dylibs/libgmp.10.dylib +0 -0
- passagemath_groups/.dylibs/libreadline.8.2.dylib +0 -0
- passagemath_groups/.dylibs/libz.1.3.1.dylib +0 -0
- passagemath_groups/__init__.py +3 -0
- passagemath_groups-10.6.45.dist-info/METADATA +113 -0
- passagemath_groups-10.6.45.dist-info/RECORD +40 -0
- passagemath_groups-10.6.45.dist-info/WHEEL +6 -0
- passagemath_groups-10.6.45.dist-info/top_level.txt +3 -0
- sage/all__sagemath_groups.py +21 -0
- sage/geometry/all__sagemath_groups.py +1 -0
- sage/geometry/palp_normal_form.cpython-314-darwin.so +0 -0
- sage/geometry/palp_normal_form.pyx +401 -0
- sage/groups/abelian_gps/all.py +25 -0
- sage/groups/all.py +5 -0
- sage/groups/all__sagemath_groups.py +32 -0
- sage/groups/artin.py +1074 -0
- sage/groups/braid.py +3806 -0
- sage/groups/cactus_group.py +1001 -0
- sage/groups/cubic_braid.py +2052 -0
- sage/groups/finitely_presented.py +1896 -0
- sage/groups/finitely_presented_catalog.py +27 -0
- sage/groups/finitely_presented_named.py +592 -0
- sage/groups/fqf_orthogonal.py +579 -0
- sage/groups/free_group.py +944 -0
- sage/groups/group_exp.py +360 -0
- sage/groups/group_semidirect_product.py +504 -0
- sage/groups/kernel_subgroup.py +231 -0
- sage/groups/lie_gps/all.py +1 -0
- sage/groups/lie_gps/catalog.py +8 -0
- sage/groups/lie_gps/nilpotent_lie_group.py +945 -0
- sage/groups/misc_gps/all.py +1 -0
- sage/groups/misc_gps/misc_groups.py +11 -0
- sage/groups/misc_gps/misc_groups_catalog.py +33 -0
- sage/groups/raag.py +866 -0
- sage/groups/semimonomial_transformations/all.py +1 -0
- sage/groups/semimonomial_transformations/semimonomial_transformation.cpython-314-darwin.so +0 -0
- sage/groups/semimonomial_transformations/semimonomial_transformation.pxd +9 -0
- sage/groups/semimonomial_transformations/semimonomial_transformation.pyx +346 -0
- sage/groups/semimonomial_transformations/semimonomial_transformation_group.py +512 -0
sage/groups/artin.py
ADDED
|
@@ -0,0 +1,1074 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-groups
|
|
2
|
+
"""
|
|
3
|
+
Artin Groups
|
|
4
|
+
|
|
5
|
+
Artin groups are implemented as a particular case of finitely presented
|
|
6
|
+
groups. For finite-type Artin groups, there is a specific left normal
|
|
7
|
+
form using the Garside structure associated to the lift the long element
|
|
8
|
+
of the corresponding Coxeter group.
|
|
9
|
+
|
|
10
|
+
AUTHORS:
|
|
11
|
+
|
|
12
|
+
- Travis Scrimshaw (2018-02-05): Initial version
|
|
13
|
+
- Travis Scrimshaw (2025-01-30): Allowed general construction; implemented
|
|
14
|
+
general Burau representation
|
|
15
|
+
|
|
16
|
+
.. TODO::
|
|
17
|
+
|
|
18
|
+
Implement affine type Artin groups with their well-known embeddings into
|
|
19
|
+
the classical braid group.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
# ****************************************************************************
|
|
23
|
+
# Copyright (C) 2018-2025 Travis Scrimshaw <tcscrims at gmail.com>
|
|
24
|
+
#
|
|
25
|
+
# This program is free software: you can redistribute it and/or modify
|
|
26
|
+
# it under the terms of the GNU General Public License as published by
|
|
27
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
28
|
+
# (at your option) any later version.
|
|
29
|
+
# http://www.gnu.org/licenses/
|
|
30
|
+
# *****************************************************************************
|
|
31
|
+
|
|
32
|
+
from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix
|
|
33
|
+
from sage.combinat.root_system.coxeter_group import CoxeterGroup
|
|
34
|
+
from sage.groups.free_group import FreeGroup
|
|
35
|
+
from sage.groups.finitely_presented import FinitelyPresentedGroup, FinitelyPresentedGroupElement
|
|
36
|
+
from sage.misc.cachefunc import cached_method
|
|
37
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
38
|
+
from sage.rings.infinity import Infinity
|
|
39
|
+
from sage.structure.richcmp import richcmp, rich_to_bool
|
|
40
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ArtinGroupElement(FinitelyPresentedGroupElement):
|
|
44
|
+
"""
|
|
45
|
+
An element of an Artin group.
|
|
46
|
+
|
|
47
|
+
It is a particular case of element of a finitely presented group.
|
|
48
|
+
|
|
49
|
+
EXAMPLES::
|
|
50
|
+
|
|
51
|
+
sage: # needs sage.rings.number_field
|
|
52
|
+
sage: A.<s1,s2,s3> = ArtinGroup(['B',3])
|
|
53
|
+
sage: A
|
|
54
|
+
Artin group of type ['B', 3]
|
|
55
|
+
sage: s1 * s2 / s3 / s2
|
|
56
|
+
s1*s2*s3^-1*s2^-1
|
|
57
|
+
sage: A((1, 2, -3, -2))
|
|
58
|
+
s1*s2*s3^-1*s2^-1
|
|
59
|
+
"""
|
|
60
|
+
def _latex_(self):
|
|
61
|
+
r"""
|
|
62
|
+
Return a LaTeX representation of ``self``.
|
|
63
|
+
|
|
64
|
+
OUTPUT: string; a valid LaTeX math command sequence
|
|
65
|
+
|
|
66
|
+
TESTS::
|
|
67
|
+
|
|
68
|
+
sage: A = ArtinGroup(['B', 3]) # needs sage.rings.number_field
|
|
69
|
+
sage: b = A([1, 2, 3, -1, 2, -3]) # needs sage.rings.number_field
|
|
70
|
+
sage: b._latex_() # needs sage.rings.number_field
|
|
71
|
+
'\\sigma_{1}\\sigma_{2}\\sigma_{3}\\sigma_{1}^{-1}\\sigma_{2}\\sigma_{3}^{-1}'
|
|
72
|
+
|
|
73
|
+
sage: # needs sage.combinat sage.graphs
|
|
74
|
+
sage: B = BraidGroup(4)
|
|
75
|
+
sage: b = B([1, 2, 3, -1, 2, -3])
|
|
76
|
+
sage: b._latex_()
|
|
77
|
+
'\\sigma_{1}\\sigma_{2}\\sigma_{3}\\sigma_{1}^{-1}\\sigma_{2}\\sigma_{3}^{-1}'
|
|
78
|
+
sage: B.one()._latex_()
|
|
79
|
+
'1'
|
|
80
|
+
"""
|
|
81
|
+
word = self.Tietze()
|
|
82
|
+
if not word:
|
|
83
|
+
return '1'
|
|
84
|
+
return ''.join(r"\sigma_{%s}^{-1}" % (-i) if i < 0 else r"\sigma_{%s}" % i
|
|
85
|
+
for i in word)
|
|
86
|
+
|
|
87
|
+
def exponent_sum(self):
|
|
88
|
+
"""
|
|
89
|
+
Return the exponent sum of ``self``.
|
|
90
|
+
|
|
91
|
+
OUTPUT: integer
|
|
92
|
+
|
|
93
|
+
EXAMPLES::
|
|
94
|
+
|
|
95
|
+
sage: # needs sage.rings.number_field
|
|
96
|
+
sage: A = ArtinGroup(['E',6])
|
|
97
|
+
sage: b = A([1, 4, -3, 2])
|
|
98
|
+
sage: b.exponent_sum()
|
|
99
|
+
2
|
|
100
|
+
sage: b = A([])
|
|
101
|
+
sage: b.exponent_sum()
|
|
102
|
+
0
|
|
103
|
+
|
|
104
|
+
sage: # needs sage.combinat sage.graphs
|
|
105
|
+
sage: B = BraidGroup(5)
|
|
106
|
+
sage: b = B([1, 4, -3, 2])
|
|
107
|
+
sage: b.exponent_sum()
|
|
108
|
+
2
|
|
109
|
+
sage: b = B([])
|
|
110
|
+
sage: b.exponent_sum()
|
|
111
|
+
0
|
|
112
|
+
"""
|
|
113
|
+
return sum(s.sign() for s in self.Tietze())
|
|
114
|
+
|
|
115
|
+
def coxeter_group_element(self, W=None):
|
|
116
|
+
"""
|
|
117
|
+
Return the corresponding Coxeter group element under the natural
|
|
118
|
+
projection.
|
|
119
|
+
|
|
120
|
+
INPUT:
|
|
121
|
+
|
|
122
|
+
- ``W`` -- (default: ``self.parent().coxeter_group()``) the image
|
|
123
|
+
Coxeter group
|
|
124
|
+
|
|
125
|
+
OUTPUT: an element of the Coxeter group ``W``
|
|
126
|
+
|
|
127
|
+
EXAMPLES::
|
|
128
|
+
|
|
129
|
+
sage: # needs sage.rings.number_field
|
|
130
|
+
sage: B.<s1,s2,s3> = ArtinGroup(['B',3])
|
|
131
|
+
sage: b = s1 * s2 / s3 / s2
|
|
132
|
+
sage: b1 = b.coxeter_group_element(); b1
|
|
133
|
+
[ 1 -1 0]
|
|
134
|
+
[ 2 -1 0]
|
|
135
|
+
[ a -a 1]
|
|
136
|
+
sage: b.coxeter_group_element().reduced_word()
|
|
137
|
+
[1, 2, 3, 2]
|
|
138
|
+
|
|
139
|
+
sage: # neeeds sage.combinat sage.rings.number_field
|
|
140
|
+
sage: A.<s1,s2,s3> = ArtinGroup(['A',3])
|
|
141
|
+
sage: c = s1 * s2 *s3
|
|
142
|
+
sage: c1 = c.coxeter_group_element(); c1
|
|
143
|
+
[4, 1, 2, 3]
|
|
144
|
+
sage: c1.reduced_word()
|
|
145
|
+
[3, 2, 1]
|
|
146
|
+
sage: c.coxeter_group_element(W=SymmetricGroup(4))
|
|
147
|
+
(1,4,3,2)
|
|
148
|
+
|
|
149
|
+
sage: # needs sage.graphs
|
|
150
|
+
sage: A.<s1,s2,s3> = BraidGroup(4)
|
|
151
|
+
sage: c = s1 * s2 * s3^-1
|
|
152
|
+
sage: c0 = c.coxeter_group_element(); c0
|
|
153
|
+
[4, 1, 2, 3]
|
|
154
|
+
sage: c1 = c.coxeter_group_element(W=SymmetricGroup(4)); c1
|
|
155
|
+
(1,4,3,2)
|
|
156
|
+
|
|
157
|
+
From an element of the Coxeter group it is possible to recover
|
|
158
|
+
the image by the standard section to the Artin group::
|
|
159
|
+
|
|
160
|
+
sage: # needs sage.rings.number_field
|
|
161
|
+
sage: B(b1)
|
|
162
|
+
s1*s2*s3*s2
|
|
163
|
+
|
|
164
|
+
sage: # needs sage.graphs
|
|
165
|
+
sage: A(c0)
|
|
166
|
+
s1*s2*s3
|
|
167
|
+
sage: A(c0) == A(c1)
|
|
168
|
+
True
|
|
169
|
+
"""
|
|
170
|
+
if W is None:
|
|
171
|
+
W = self.parent().coxeter_group()
|
|
172
|
+
s = W.simple_reflections()
|
|
173
|
+
In = W.index_set()
|
|
174
|
+
return W.prod(s[In[abs(i) - 1]] for i in self.Tietze())
|
|
175
|
+
|
|
176
|
+
def burau_matrix(self, var='t'):
|
|
177
|
+
r"""
|
|
178
|
+
Return the Burau matrix of the Artin group element.
|
|
179
|
+
|
|
180
|
+
Following [BQ2024]_, the (generalized) Burau representation
|
|
181
|
+
of an Artin group is defined by deforming the reflection
|
|
182
|
+
representation of the corresponding Coxeter group. However,
|
|
183
|
+
we substitute `q \mapsto -t` from [BQ2024]_ to match one of
|
|
184
|
+
the unitary (reduced) Burau representations of the braid group
|
|
185
|
+
(see :meth:`sage.groups.braid.Braid.burau_matrix()` for details.)
|
|
186
|
+
|
|
187
|
+
More precisely, let `(m_{ij})_{i,j \in I}` be the
|
|
188
|
+
:meth:`Coxeter matrix<coxeter_matrix>`. Then the action is
|
|
189
|
+
given on the basis `(\alpha_1, \ldots \alpha_n)` (corresponding
|
|
190
|
+
to the reflection representation of the corresponding
|
|
191
|
+
:meth:`Coxeter group<coxeter_group>`) by
|
|
192
|
+
|
|
193
|
+
.. MATH::
|
|
194
|
+
|
|
195
|
+
\sigma_i(\alpha_j) = \alpha_j
|
|
196
|
+
- \langle \alpha_i, \alpha_j \rangle_q \alpha_i,
|
|
197
|
+
\qquad \text{ where }
|
|
198
|
+
\langle \alpha_i, \alpha_j \rangle_q := \begin{cases}
|
|
199
|
+
1 + t^2 & \text{if } i = j, \\
|
|
200
|
+
-2 t \cos(\pi/m_{ij}) & \text{if } i \neq j.
|
|
201
|
+
\end{cases}.
|
|
202
|
+
|
|
203
|
+
By convention `\cos(\pi/\infty) = 1`. Note that the inverse of the
|
|
204
|
+
generators act by `\sigma_i^{-1}(\alpha_j) = \alpha_j - q^{-2}
|
|
205
|
+
\langle \alpha_j, \alpha_i \rangle_q \alpha_i`.
|
|
206
|
+
|
|
207
|
+
INPUT:
|
|
208
|
+
|
|
209
|
+
- ``var`` -- string (default: ``'t'``); the name of the
|
|
210
|
+
variable in the entries of the matrix
|
|
211
|
+
|
|
212
|
+
OUTPUT:
|
|
213
|
+
|
|
214
|
+
The Burau matrix of the Artin group element over the Laurent
|
|
215
|
+
polynomial ring in the variable ``var``.
|
|
216
|
+
|
|
217
|
+
EXAMPLES::
|
|
218
|
+
|
|
219
|
+
sage: A.<s1,s2,s3> = ArtinGroup(['B',3])
|
|
220
|
+
sage: B1 = s1.burau_matrix()
|
|
221
|
+
sage: B2 = s2.burau_matrix()
|
|
222
|
+
sage: B3 = s3.burau_matrix()
|
|
223
|
+
sage: [B1, B2, B3]
|
|
224
|
+
[
|
|
225
|
+
[-t^2 t 0] [ 1 0 0] [ 1 0 0]
|
|
226
|
+
[ 0 1 0] [ t -t^2 a*t] [ 0 1 0]
|
|
227
|
+
[ 0 0 1], [ 0 0 1], [ 0 a*t -t^2]
|
|
228
|
+
]
|
|
229
|
+
sage: B1 * B2 * B1 == B2 * B1 * B2
|
|
230
|
+
True
|
|
231
|
+
sage: B2 * B3 * B2 * B3 == B3 * B2 * B3 * B2
|
|
232
|
+
True
|
|
233
|
+
sage: B1 * B3 == B3 * B1
|
|
234
|
+
True
|
|
235
|
+
sage: (~s1).burau_matrix() * B1 == 1
|
|
236
|
+
True
|
|
237
|
+
|
|
238
|
+
We verify the example in Theorem 4.1 of [BQ2024]_::
|
|
239
|
+
|
|
240
|
+
sage: A.<s1,s2,s3,s4> = ArtinGroup(['A', 3, 1])
|
|
241
|
+
sage: [g.burau_matrix() for g in A.gens()]
|
|
242
|
+
[
|
|
243
|
+
[-t^2 t 0 t] [ 1 0 0 0] [ 1 0 0 0]
|
|
244
|
+
[ 0 1 0 0] [ t -t^2 t 0] [ 0 1 0 0]
|
|
245
|
+
[ 0 0 1 0] [ 0 0 1 0] [ 0 t -t^2 t]
|
|
246
|
+
[ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 1],
|
|
247
|
+
<BLANKLINE>
|
|
248
|
+
[ 1 0 0 0]
|
|
249
|
+
[ 0 1 0 0]
|
|
250
|
+
[ 0 0 1 0]
|
|
251
|
+
[ t 0 t -t^2]
|
|
252
|
+
]
|
|
253
|
+
sage: a = s3^2 * s4 * s3 * s2 *s1 * ~s3 * s4 * s3 * s2 * s1^-2 * s4
|
|
254
|
+
sage: b = s1^2 * ~s2 * s4 * s1 * ~s3 * s2 * ~s4 * s3 * s1 * s4 * s1 * ~s2 * s4^-2 * s3
|
|
255
|
+
sage: alpha = a * s3 * ~a
|
|
256
|
+
sage: beta = b * s2 * ~b
|
|
257
|
+
sage: elm = alpha * beta * ~alpha * ~beta
|
|
258
|
+
sage: print(elm.Tietze())
|
|
259
|
+
(3, 3, 4, 3, 2, 1, -3, 4, 3, 2, -1, -1, 4, 3, -4, 1, 1, -2, -3,
|
|
260
|
+
-4, 3, -1, -2, -3, -4, -3, -3, 1, 1, -2, 4, 1, -3, 2, -4, 3, 1,
|
|
261
|
+
4, 1, -2, -4, -4, 3, 2, -3, 4, 4, 2, -1, -4, -1, -3, 4, -2, 3,
|
|
262
|
+
-1, -4, 2, -1, -1, 3, 3, 4, 3, 2, 1, -3, 4, 3, 2, -1, -1, 4,
|
|
263
|
+
-3, -4, 1, 1, -2, -3, -4, 3, -1, -2, -3, -4, -3, -3, 1, 1, -2,
|
|
264
|
+
4, 1, -3, 2, -4, 3, 1, 4, 1, -2, -4, -4, 3, -2, -3, 4, 4, 2,
|
|
265
|
+
-1, -4, -1, -3, 4, -2, 3, -1, -4, 2, -1, -1)
|
|
266
|
+
sage: elm.burau_matrix()
|
|
267
|
+
[1 0 0 0]
|
|
268
|
+
[0 1 0 0]
|
|
269
|
+
[0 0 1 0]
|
|
270
|
+
[0 0 0 1]
|
|
271
|
+
|
|
272
|
+
Next, we show ``elm`` is not the identity by using the embedding of
|
|
273
|
+
the affine braid group `\widetilde{B}_n \to B_{n+1}`::
|
|
274
|
+
|
|
275
|
+
sage: # needs sage.libs.braiding
|
|
276
|
+
sage: B.<t1,t2,t3,t4> = BraidGroup(5)
|
|
277
|
+
sage: D = t1 * t2 * t3 * t4^2
|
|
278
|
+
sage: t0 = D * t3 * ~D
|
|
279
|
+
sage: t0*t1*t0 == t1*t0*t1
|
|
280
|
+
True
|
|
281
|
+
sage: t0*t2 == t2*t0
|
|
282
|
+
True
|
|
283
|
+
sage: t0*t3*t0 == t3*t0*t3
|
|
284
|
+
True
|
|
285
|
+
sage: T = [t0, t1, t2, t3]
|
|
286
|
+
sage: emb = B.prod(T[i-1] if i > 0 else ~T[-i-1] for i in elm.Tietze())
|
|
287
|
+
sage: emb.is_one()
|
|
288
|
+
False
|
|
289
|
+
|
|
290
|
+
Since the Burau representation does not respect the group embedding,
|
|
291
|
+
the corresponding `B_5` element's Burau matrix is not the identity
|
|
292
|
+
(Bigelow gave an example of the representation not being faithful for
|
|
293
|
+
`B_5`, but it is still open for `B_4`)::
|
|
294
|
+
|
|
295
|
+
sage: emb.burau_matrix() != 1 # needs sage.libs.braiding
|
|
296
|
+
True
|
|
297
|
+
|
|
298
|
+
We also verify the result using the elements in [BQ2024]_ Remark 4.2::
|
|
299
|
+
|
|
300
|
+
sage: ap = s3 * s1 * s2 * s1 * ~s3 * s4 * s2 * s3 * s2 * ~s3 * s1^-2 * s4
|
|
301
|
+
sage: bp = s1 * ~s4 * s1^2 * s3^-2 * ~s2 * s4 * s1 * ~s3 * s2 * ~s4 * s3 * s1 * s4 * s1 * ~s2 * s4^-2 * s3
|
|
302
|
+
sage: alpha = ap * s3 * ~ap
|
|
303
|
+
sage: beta = bp * s2 * ~bp
|
|
304
|
+
sage: elm = alpha * beta * ~alpha * ~beta # needs sage.libs.braiding
|
|
305
|
+
sage: elm.burau_matrix() # needs sage.libs.braiding
|
|
306
|
+
[1 0 0 0]
|
|
307
|
+
[0 1 0 0]
|
|
308
|
+
[0 0 1 0]
|
|
309
|
+
[0 0 0 1]
|
|
310
|
+
|
|
311
|
+
REFERENCES:
|
|
312
|
+
|
|
313
|
+
- [BQ2024]_
|
|
314
|
+
"""
|
|
315
|
+
gens, invs = self.parent()._burau_generators
|
|
316
|
+
MS = gens[0].parent()
|
|
317
|
+
ret = MS.prod(gens[i-1] if i > 0 else invs[-i-1] for i in self.Tietze())
|
|
318
|
+
|
|
319
|
+
if var == 't':
|
|
320
|
+
return ret
|
|
321
|
+
|
|
322
|
+
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
|
|
323
|
+
poly_ring = LaurentPolynomialRing(ret.base_ring().base_ring(), var)
|
|
324
|
+
return ret.change_ring(poly_ring)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class FiniteTypeArtinGroupElement(ArtinGroupElement):
|
|
328
|
+
"""
|
|
329
|
+
An element of a finite-type Artin group.
|
|
330
|
+
"""
|
|
331
|
+
def _richcmp_(self, other, op):
|
|
332
|
+
"""
|
|
333
|
+
Compare ``self`` and ``other``.
|
|
334
|
+
|
|
335
|
+
TESTS::
|
|
336
|
+
|
|
337
|
+
sage: # needs sage.rings.number_field
|
|
338
|
+
sage: A = ArtinGroup(['B',3])
|
|
339
|
+
sage: x = A([1, 2, 1])
|
|
340
|
+
sage: y = A([2, 1, 2])
|
|
341
|
+
sage: x == y
|
|
342
|
+
True
|
|
343
|
+
sage: x < y^(-1)
|
|
344
|
+
True
|
|
345
|
+
sage: A([]) == A.one()
|
|
346
|
+
True
|
|
347
|
+
sage: x = A([2, 3, 2, 3])
|
|
348
|
+
sage: y = A([3, 2, 3, 2])
|
|
349
|
+
sage: x == y
|
|
350
|
+
True
|
|
351
|
+
sage: x < y^(-1)
|
|
352
|
+
True
|
|
353
|
+
"""
|
|
354
|
+
if self.Tietze() == other.Tietze():
|
|
355
|
+
return rich_to_bool(op, 0)
|
|
356
|
+
nfself = [i.Tietze() for i in self.left_normal_form()]
|
|
357
|
+
nfother = [i.Tietze() for i in other.left_normal_form()]
|
|
358
|
+
return richcmp(nfself, nfother, op)
|
|
359
|
+
|
|
360
|
+
def __hash__(self):
|
|
361
|
+
r"""
|
|
362
|
+
Return a hash value for ``self``.
|
|
363
|
+
|
|
364
|
+
EXAMPLES::
|
|
365
|
+
|
|
366
|
+
sage: # needs sage.rings.number_field
|
|
367
|
+
sage: B.<s1,s2,s3> = ArtinGroup(['B',3])
|
|
368
|
+
sage: hash(s1*s3) == hash(s3*s1)
|
|
369
|
+
True
|
|
370
|
+
sage: hash(s1*s2) == hash(s2*s1)
|
|
371
|
+
False
|
|
372
|
+
sage: hash(s1*s2*s1) == hash(s2*s1*s2)
|
|
373
|
+
True
|
|
374
|
+
sage: hash(s2*s3*s2) == hash(s3*s2*s3)
|
|
375
|
+
False
|
|
376
|
+
sage: hash(s2*s3*s2*s3) == hash(s3*s2*s3*s2)
|
|
377
|
+
True
|
|
378
|
+
"""
|
|
379
|
+
return hash(tuple(i.Tietze() for i in self.left_normal_form()))
|
|
380
|
+
|
|
381
|
+
@cached_method
|
|
382
|
+
def left_normal_form(self):
|
|
383
|
+
r"""
|
|
384
|
+
Return the left normal form of ``self``.
|
|
385
|
+
|
|
386
|
+
OUTPUT:
|
|
387
|
+
|
|
388
|
+
A tuple of simple generators in the left normal form. The first
|
|
389
|
+
element is a power of `\Delta`, and the rest are elements of the
|
|
390
|
+
natural section lift from the corresponding Coxeter group.
|
|
391
|
+
|
|
392
|
+
EXAMPLES::
|
|
393
|
+
|
|
394
|
+
sage: # needs sage.rings.number_field
|
|
395
|
+
sage: A = ArtinGroup(['B',3])
|
|
396
|
+
sage: A([1]).left_normal_form()
|
|
397
|
+
(1, s1)
|
|
398
|
+
sage: A([-1]).left_normal_form()
|
|
399
|
+
(s1^-1*(s2^-1*s1^-1*s3^-1)^2*s2^-1*s3^-1, s3*(s2*s3*s1)^2*s2)
|
|
400
|
+
sage: A([1, 2, 2, 1, 2]).left_normal_form()
|
|
401
|
+
(1, s1*s2*s1, s2*s1)
|
|
402
|
+
sage: A([3, 3, -2]).left_normal_form()
|
|
403
|
+
(s1^-1*(s2^-1*s1^-1*s3^-1)^2*s2^-1*s3^-1,
|
|
404
|
+
s3*s1*s2*s3*s2*s1, s3, s3*s2*s3)
|
|
405
|
+
sage: A([1, 2, 3, -1, 2, -3]).left_normal_form()
|
|
406
|
+
(s1^-1*(s2^-1*s1^-1*s3^-1)^2*s2^-1*s3^-1,
|
|
407
|
+
(s3*s1*s2)^2*s1, s1*s2*s3*s2)
|
|
408
|
+
sage: A([1,2,1,3,2,1,3,2,3,3,2,3,1,2,3,1,2,3,1,2]).left_normal_form()
|
|
409
|
+
((s3*(s2*s3*s1)^2*s2*s1)^2, s3*s2)
|
|
410
|
+
|
|
411
|
+
sage: # needs sage.combinat
|
|
412
|
+
sage: B = BraidGroup(4)
|
|
413
|
+
sage: b = B([1, 2, 3, -1, 2, -3])
|
|
414
|
+
sage: b.left_normal_form() # needs sage.libs.braiding
|
|
415
|
+
(s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1, s0*s1*s2*s1*s0, s0*s2*s1)
|
|
416
|
+
sage: c = B([1])
|
|
417
|
+
sage: c.left_normal_form() # needs sage.libs.braiding
|
|
418
|
+
(1, s0)
|
|
419
|
+
"""
|
|
420
|
+
lnfp = self._left_normal_form_coxeter()
|
|
421
|
+
P = self.parent()
|
|
422
|
+
return tuple([P.delta() ** lnfp[0]] +
|
|
423
|
+
[P._standard_lift(w) for w in lnfp[1:]])
|
|
424
|
+
|
|
425
|
+
def _left_normal_form_coxeter(self):
|
|
426
|
+
r"""
|
|
427
|
+
Return the left normal form of the element, in the `\Delta`
|
|
428
|
+
exponent and Coxeter group element form.
|
|
429
|
+
|
|
430
|
+
OUTPUT: tuple whose first element is the power of `\Delta`, and the
|
|
431
|
+
rest are the Coxeter elements corresponding to the simple factors
|
|
432
|
+
|
|
433
|
+
EXAMPLES::
|
|
434
|
+
|
|
435
|
+
sage: # needs sage.rings.number_field
|
|
436
|
+
sage: A = ArtinGroup(['E',6])
|
|
437
|
+
sage: A([2, -4, 2, 3, 1, 3, 2, 1, -2])._left_normal_form_coxeter()
|
|
438
|
+
(
|
|
439
|
+
[ 0 0 0 0 0 -1] [ 0 0 -1 1 0 0] [-1 0 1 0 0 0]
|
|
440
|
+
[ 0 1 0 -1 0 0] [ 0 -1 0 1 0 0] [ 0 -1 0 1 0 0]
|
|
441
|
+
[ 0 0 0 0 -1 0] [-1 0 0 1 0 0] [ 0 0 1 0 0 0]
|
|
442
|
+
[ 0 1 -1 0 -1 0] [-1 -1 0 1 1 0] [ 0 0 0 1 0 0]
|
|
443
|
+
[ 0 0 -1 0 0 0] [ 0 0 0 0 1 0] [ 0 0 0 0 1 0]
|
|
444
|
+
-1, [-1 0 0 0 0 0], [ 0 0 0 0 0 1], [ 0 0 0 0 0 1]
|
|
445
|
+
)
|
|
446
|
+
sage: A = ArtinGroup(['F',4])
|
|
447
|
+
sage: A([2, 3, -4, 2, 3, -2, 1, -2, 3, 4, 1, -2])._left_normal_form_coxeter()
|
|
448
|
+
(
|
|
449
|
+
[-1 0 0 0] [ -1 1 0 0] [-1 0 0 0]
|
|
450
|
+
[-1 -1 a -a] [ -2 3 -a 0] [-1 1 -a 0]
|
|
451
|
+
[-a 0 1 -2] [ -a 2*a -1 -1] [ 0 0 -1 0]
|
|
452
|
+
-3, [-a 0 1 -1], [ -a a 0 -1], [ 0 0 0 -1],
|
|
453
|
+
<BLANKLINE>
|
|
454
|
+
[ -1 1 0 -a] [ -1 0 a -a]
|
|
455
|
+
[ 0 1 0 -2*a] [ -1 1 a -2*a]
|
|
456
|
+
[ 0 a -1 -2] [ 0 0 2 -3]
|
|
457
|
+
[ 0 a -1 -1], [ 0 0 1 -1]
|
|
458
|
+
)
|
|
459
|
+
"""
|
|
460
|
+
delta = 0
|
|
461
|
+
Delta = self.parent().coxeter_group().long_element()
|
|
462
|
+
sr = self.parent().coxeter_group().simple_reflections()
|
|
463
|
+
tz = self.Tietze()
|
|
464
|
+
if tz == ():
|
|
465
|
+
return (0,)
|
|
466
|
+
form = []
|
|
467
|
+
for i in tz:
|
|
468
|
+
if i > 0:
|
|
469
|
+
form.append(sr[i])
|
|
470
|
+
else:
|
|
471
|
+
delta += 1
|
|
472
|
+
form = [Delta * a * Delta for a in form]
|
|
473
|
+
form.append(Delta * sr[-i])
|
|
474
|
+
i = j = 0
|
|
475
|
+
while j < len(form):
|
|
476
|
+
while i < len(form) - j - 1:
|
|
477
|
+
e = form[i].descents(side='right')
|
|
478
|
+
s = form[i + 1].descents(side='left')
|
|
479
|
+
S = set(s).difference(set(e))
|
|
480
|
+
while S:
|
|
481
|
+
a = list(S)[0]
|
|
482
|
+
form[i] = form[i] * sr[a]
|
|
483
|
+
form[i + 1] = sr[a] * form[i+1]
|
|
484
|
+
e = form[i].descents(side='right')
|
|
485
|
+
s = form[i + 1].descents(side='left')
|
|
486
|
+
S = set(s).difference(set(e))
|
|
487
|
+
if form[i+1].length() == 0:
|
|
488
|
+
form.pop(i+1)
|
|
489
|
+
i = 0
|
|
490
|
+
else:
|
|
491
|
+
i += 1
|
|
492
|
+
j += 1
|
|
493
|
+
i = 0
|
|
494
|
+
form = [elt for elt in form if elt.length()]
|
|
495
|
+
while form and form[0] == Delta:
|
|
496
|
+
form.pop(0)
|
|
497
|
+
delta -= 1
|
|
498
|
+
return tuple([-delta] + form)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
class ArtinGroup(UniqueRepresentation, FinitelyPresentedGroup):
|
|
502
|
+
r"""
|
|
503
|
+
An Artin group.
|
|
504
|
+
|
|
505
|
+
Fix an index set `I`. Let `M = (m_{ij})_{i,j \in I}` be a
|
|
506
|
+
:class:`Coxeter matrix
|
|
507
|
+
<sage.combinat.root_system.coxeter_matrix.CoxeterMatrix>`.
|
|
508
|
+
An *Artin group* is a group `A_M` that has a presentation
|
|
509
|
+
given by generators `\{ s_i \mid i \in I \}` and relations
|
|
510
|
+
|
|
511
|
+
.. MATH::
|
|
512
|
+
|
|
513
|
+
\underbrace{s_i s_j s_i \cdots}_{m_{ij}}
|
|
514
|
+
= \underbrace{s_j s_i s_j \cdots}_{\text{$m_{ji}$ factors}}
|
|
515
|
+
|
|
516
|
+
for all `i,j \in I` with the usual convention that `m_{ij} = \infty`
|
|
517
|
+
implies no relation between `s_i` and `s_j`. There is a natural
|
|
518
|
+
corresponding Coxeter group `W_M` by imposing the additional
|
|
519
|
+
relations `s_i^2 = 1` for all `i \in I`. Furthermore, there is
|
|
520
|
+
a natural section of `W_M` by sending a reduced word
|
|
521
|
+
`s_{i_1} \cdots s_{i_{\ell}} \mapsto s_{i_1} \cdots s_{i_{\ell}}`.
|
|
522
|
+
|
|
523
|
+
Artin groups `A_M` are classified based on the Coxeter data:
|
|
524
|
+
|
|
525
|
+
- `A_M` is of *finite type* or *spherical* if `W_M` is finite;
|
|
526
|
+
- `A_M` is of *affine type* if `W_M` is of affine type;
|
|
527
|
+
- `A_M` is of *large type* if `m_{ij} \geq 4` for all `i,j \in I`;
|
|
528
|
+
- `A_M` is of *extra-large type* if `m_{ij} \geq 5` for all `i,j \in I`;
|
|
529
|
+
- `A_M` is *right-angled* if `m_{ij} \in \{2,\infty\}` for all `i,j \in I`.
|
|
530
|
+
|
|
531
|
+
Artin groups are conjectured to have many nice properties:
|
|
532
|
+
|
|
533
|
+
- Artin groups are torsion free.
|
|
534
|
+
- Finite type Artin groups have `Z(A_M) = \ZZ` and infinite type
|
|
535
|
+
Artin groups have trivial center.
|
|
536
|
+
- Artin groups have solvable word problems.
|
|
537
|
+
- `H_{W_M} / W_M` is a `K(A_M, 1)`-space, where `H_W` is the
|
|
538
|
+
hyperplane complement of the Coxeter group `W` acting on `\CC^n`.
|
|
539
|
+
|
|
540
|
+
These conjectures are known when the Artin group is finite type and a
|
|
541
|
+
number of other cases. See, e.g., [GP2012]_ and references therein.
|
|
542
|
+
|
|
543
|
+
INPUT:
|
|
544
|
+
|
|
545
|
+
- ``coxeter_data`` -- data defining a Coxeter matrix
|
|
546
|
+
|
|
547
|
+
- ``names`` -- string or list/tuple/iterable of strings
|
|
548
|
+
(default: ``'s'``); the generator names or name prefix
|
|
549
|
+
|
|
550
|
+
EXAMPLES::
|
|
551
|
+
|
|
552
|
+
sage: A.<a,b,c> = ArtinGroup(['B',3]); A # needs sage.rings.number_field
|
|
553
|
+
Artin group of type ['B', 3]
|
|
554
|
+
sage: ArtinGroup(['B',3]) # needs sage.rings.number_field
|
|
555
|
+
Artin group of type ['B', 3]
|
|
556
|
+
|
|
557
|
+
The input must always include the Coxeter data, but the ``names``
|
|
558
|
+
can either be a string representing the prefix of the names or
|
|
559
|
+
the explicit names of the generators. Otherwise the default prefix
|
|
560
|
+
of ``'s'`` is used::
|
|
561
|
+
|
|
562
|
+
sage: ArtinGroup(['B',2]).generators() # needs sage.rings.number_field
|
|
563
|
+
(s1, s2)
|
|
564
|
+
sage: ArtinGroup(['B',2], 'g').generators() # needs sage.rings.number_field
|
|
565
|
+
(g1, g2)
|
|
566
|
+
sage: ArtinGroup(['B',2], 'x,y').generators() # needs sage.rings.number_field
|
|
567
|
+
(x, y)
|
|
568
|
+
|
|
569
|
+
REFERENCES:
|
|
570
|
+
|
|
571
|
+
- :wikipedia:`Artin_group`
|
|
572
|
+
|
|
573
|
+
.. SEEALSO::
|
|
574
|
+
|
|
575
|
+
:class:`~sage.groups.raag.RightAngledArtinGroup`
|
|
576
|
+
"""
|
|
577
|
+
@staticmethod
|
|
578
|
+
def __classcall_private__(cls, coxeter_data, names=None):
|
|
579
|
+
"""
|
|
580
|
+
Normalize input to ensure a unique representation.
|
|
581
|
+
|
|
582
|
+
TESTS::
|
|
583
|
+
|
|
584
|
+
sage: # needs sage.rings.number_field
|
|
585
|
+
sage: A1 = ArtinGroup(['B',3])
|
|
586
|
+
sage: A2 = ArtinGroup(['B',3], 's')
|
|
587
|
+
sage: A3 = ArtinGroup(['B',3], ['s1','s2','s3'])
|
|
588
|
+
sage: A1 is A2 and A2 is A3
|
|
589
|
+
True
|
|
590
|
+
|
|
591
|
+
sage: # needs sage.rings.number_field
|
|
592
|
+
sage: A1 = ArtinGroup(['B',2], 'a,b')
|
|
593
|
+
sage: A2 = ArtinGroup([[1,4],[4,1]], 'a,b')
|
|
594
|
+
sage: A3.<a,b> = ArtinGroup('B2')
|
|
595
|
+
sage: A1 is A2 and A2 is A3
|
|
596
|
+
True
|
|
597
|
+
|
|
598
|
+
sage: ArtinGroup(['A',3]) is BraidGroup(4, 's1,s2,s3') # needs sage.combinat sage.rings.number_field
|
|
599
|
+
True
|
|
600
|
+
|
|
601
|
+
sage: # needs sage.graphs sage.rings.number_field
|
|
602
|
+
sage: G = graphs.PathGraph(3)
|
|
603
|
+
sage: CM = CoxeterMatrix([[1,-1,2],[-1,1,-1],[2,-1,1]], index_set=G.vertices(sort=True))
|
|
604
|
+
sage: A = groups.misc.Artin(CM)
|
|
605
|
+
sage: Ap = groups.misc.RightAngledArtin(G, 's')
|
|
606
|
+
sage: A is Ap
|
|
607
|
+
True
|
|
608
|
+
"""
|
|
609
|
+
coxeter_data = CoxeterMatrix(coxeter_data)
|
|
610
|
+
if names is None:
|
|
611
|
+
names = 's'
|
|
612
|
+
if isinstance(names, str):
|
|
613
|
+
if ',' in names:
|
|
614
|
+
names = [x.strip() for x in names.split(',')]
|
|
615
|
+
else:
|
|
616
|
+
names = [names + str(i) for i in coxeter_data.index_set()]
|
|
617
|
+
names = tuple(names)
|
|
618
|
+
if len(names) != coxeter_data.rank():
|
|
619
|
+
raise ValueError("the number of generators must match"
|
|
620
|
+
" the rank of the Coxeter type")
|
|
621
|
+
if all(m == Infinity for m in coxeter_data.coxeter_graph().edge_labels()):
|
|
622
|
+
from sage.groups.raag import RightAngledArtinGroup
|
|
623
|
+
return RightAngledArtinGroup(coxeter_data.coxeter_graph(), names)
|
|
624
|
+
if not coxeter_data.is_finite():
|
|
625
|
+
return super().__classcall__(cls, coxeter_data, names)
|
|
626
|
+
if coxeter_data.coxeter_type().cartan_type().type() == 'A':
|
|
627
|
+
from sage.groups.braid import BraidGroup
|
|
628
|
+
return BraidGroup(coxeter_data.rank() + 1, names)
|
|
629
|
+
return FiniteTypeArtinGroup(coxeter_data, names)
|
|
630
|
+
|
|
631
|
+
def __init__(self, coxeter_matrix, names) -> None:
|
|
632
|
+
"""
|
|
633
|
+
Initialize ``self``.
|
|
634
|
+
|
|
635
|
+
TESTS::
|
|
636
|
+
|
|
637
|
+
sage: # needs sage.rings.number_field
|
|
638
|
+
sage: A = ArtinGroup(['D',4])
|
|
639
|
+
sage: TestSuite(A).run()
|
|
640
|
+
sage: A = ArtinGroup(['B',3], ['x','y','z'])
|
|
641
|
+
sage: TestSuite(A).run()
|
|
642
|
+
"""
|
|
643
|
+
self._coxeter_group = CoxeterGroup(coxeter_matrix)
|
|
644
|
+
free_group = FreeGroup(names)
|
|
645
|
+
rels = []
|
|
646
|
+
# Generate the relations based on the Coxeter graph
|
|
647
|
+
I = coxeter_matrix.index_set()
|
|
648
|
+
gens = free_group.gens()
|
|
649
|
+
for ii, i in enumerate(I):
|
|
650
|
+
for jj, j in enumerate(I[ii + 1:], start=ii + 1):
|
|
651
|
+
m = coxeter_matrix[i, j]
|
|
652
|
+
if m == Infinity: # no relation
|
|
653
|
+
continue
|
|
654
|
+
elt = (gens[ii] * gens[jj]) ** (m // 2)
|
|
655
|
+
if m % 2 == 1:
|
|
656
|
+
elt = elt * gens[ii] * ~gens[jj]
|
|
657
|
+
elt = elt * (~gens[ii] * ~gens[jj]) ** (m // 2)
|
|
658
|
+
rels.append(elt)
|
|
659
|
+
FinitelyPresentedGroup.__init__(self, free_group, tuple(rels))
|
|
660
|
+
|
|
661
|
+
def _repr_(self) -> str:
|
|
662
|
+
"""
|
|
663
|
+
Return a string representation of ``self``.
|
|
664
|
+
|
|
665
|
+
TESTS::
|
|
666
|
+
|
|
667
|
+
sage: ArtinGroup(['B',3]) # needs sage.rings.number_field
|
|
668
|
+
Artin group of type ['B', 3]
|
|
669
|
+
sage: ArtinGroup(['D',4], 'g') # needs sage.rings.number_field
|
|
670
|
+
Artin group of type ['D', 4]
|
|
671
|
+
"""
|
|
672
|
+
try:
|
|
673
|
+
data = self.coxeter_type().cartan_type()
|
|
674
|
+
return "Artin group of type {}".format(data)
|
|
675
|
+
except AttributeError:
|
|
676
|
+
pass
|
|
677
|
+
return "Artin group with Coxeter matrix:\n{}".format(self.coxeter_matrix())
|
|
678
|
+
|
|
679
|
+
def cardinality(self):
|
|
680
|
+
"""
|
|
681
|
+
Return the number of elements of ``self``.
|
|
682
|
+
|
|
683
|
+
OUTPUT: infinity
|
|
684
|
+
|
|
685
|
+
EXAMPLES::
|
|
686
|
+
|
|
687
|
+
sage: # needs sage.graphs
|
|
688
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
689
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
690
|
+
sage: G.cardinality()
|
|
691
|
+
+Infinity
|
|
692
|
+
|
|
693
|
+
sage: A = ArtinGroup(['A',1]) # needs sage.rings.number_field
|
|
694
|
+
sage: A.cardinality() # needs sage.rings.number_field
|
|
695
|
+
+Infinity
|
|
696
|
+
"""
|
|
697
|
+
from sage.rings.infinity import Infinity
|
|
698
|
+
return Infinity
|
|
699
|
+
|
|
700
|
+
order = cardinality
|
|
701
|
+
|
|
702
|
+
def as_permutation_group(self):
|
|
703
|
+
"""
|
|
704
|
+
Return an isomorphic permutation group.
|
|
705
|
+
|
|
706
|
+
This raises a :exc:`ValueError` error since Artin groups are
|
|
707
|
+
infinite and have no corresponding permutation group.
|
|
708
|
+
|
|
709
|
+
EXAMPLES::
|
|
710
|
+
|
|
711
|
+
sage: # needs sage.graphs
|
|
712
|
+
sage: Gamma = graphs.CycleGraph(5)
|
|
713
|
+
sage: G = RightAngledArtinGroup(Gamma)
|
|
714
|
+
sage: G.as_permutation_group()
|
|
715
|
+
Traceback (most recent call last):
|
|
716
|
+
...
|
|
717
|
+
ValueError: the group is infinite
|
|
718
|
+
|
|
719
|
+
sage: A = ArtinGroup(['D',4], 'g') # needs sage.rings.number_field
|
|
720
|
+
sage: A.as_permutation_group() # needs sage.rings.number_field
|
|
721
|
+
Traceback (most recent call last):
|
|
722
|
+
...
|
|
723
|
+
ValueError: the group is infinite
|
|
724
|
+
"""
|
|
725
|
+
raise ValueError("the group is infinite")
|
|
726
|
+
|
|
727
|
+
def coxeter_type(self):
|
|
728
|
+
"""
|
|
729
|
+
Return the Coxeter type of ``self``.
|
|
730
|
+
|
|
731
|
+
EXAMPLES::
|
|
732
|
+
|
|
733
|
+
sage: A = ArtinGroup(['D',4]) # needs sage.rings.number_field
|
|
734
|
+
sage: A.coxeter_type() # needs sage.rings.number_field
|
|
735
|
+
Coxeter type of ['D', 4]
|
|
736
|
+
"""
|
|
737
|
+
return self._coxeter_group.coxeter_type()
|
|
738
|
+
|
|
739
|
+
def coxeter_matrix(self):
|
|
740
|
+
"""
|
|
741
|
+
Return the Coxeter matrix of ``self``.
|
|
742
|
+
|
|
743
|
+
EXAMPLES::
|
|
744
|
+
|
|
745
|
+
sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field
|
|
746
|
+
sage: A.coxeter_matrix() # needs sage.rings.number_field
|
|
747
|
+
[1 3 2]
|
|
748
|
+
[3 1 4]
|
|
749
|
+
[2 4 1]
|
|
750
|
+
"""
|
|
751
|
+
return self._coxeter_group.coxeter_matrix()
|
|
752
|
+
|
|
753
|
+
def coxeter_group(self):
|
|
754
|
+
"""
|
|
755
|
+
Return the Coxeter group of ``self``.
|
|
756
|
+
|
|
757
|
+
EXAMPLES::
|
|
758
|
+
|
|
759
|
+
sage: A = ArtinGroup(['D',4]) # needs sage.rings.number_field
|
|
760
|
+
sage: A.coxeter_group() # needs sage.rings.number_field
|
|
761
|
+
Finite Coxeter group over Integer Ring with Coxeter matrix:
|
|
762
|
+
[1 3 2 2]
|
|
763
|
+
[3 1 3 3]
|
|
764
|
+
[2 3 1 2]
|
|
765
|
+
[2 3 2 1]
|
|
766
|
+
"""
|
|
767
|
+
return self._coxeter_group
|
|
768
|
+
|
|
769
|
+
def index_set(self):
|
|
770
|
+
"""
|
|
771
|
+
Return the index set of ``self``.
|
|
772
|
+
|
|
773
|
+
OUTPUT: tuple
|
|
774
|
+
|
|
775
|
+
EXAMPLES::
|
|
776
|
+
|
|
777
|
+
sage: A = ArtinGroup(['E',7]) # needs sage.rings.number_field
|
|
778
|
+
sage: A.index_set() # needs sage.rings.number_field
|
|
779
|
+
(1, 2, 3, 4, 5, 6, 7)
|
|
780
|
+
"""
|
|
781
|
+
return self._coxeter_group.index_set()
|
|
782
|
+
|
|
783
|
+
def _element_constructor_(self, x):
|
|
784
|
+
"""
|
|
785
|
+
TESTS::
|
|
786
|
+
|
|
787
|
+
sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field
|
|
788
|
+
sage: A([2,1,-2,3,3,3,1]) # needs sage.rings.number_field
|
|
789
|
+
s2*s1*s2^-1*s3^3*s1
|
|
790
|
+
"""
|
|
791
|
+
if x in self._coxeter_group:
|
|
792
|
+
return self._standard_lift(x)
|
|
793
|
+
return self.element_class(self, x)
|
|
794
|
+
|
|
795
|
+
@cached_method
|
|
796
|
+
def _an_element_(self):
|
|
797
|
+
"""
|
|
798
|
+
Return an element of ``self``.
|
|
799
|
+
|
|
800
|
+
EXAMPLES::
|
|
801
|
+
|
|
802
|
+
sage: A = ArtinGroup(['B',2]) # needs sage.rings.number_field
|
|
803
|
+
sage: A.an_element() # needs sage.rings.number_field
|
|
804
|
+
s1
|
|
805
|
+
"""
|
|
806
|
+
return self.gen(0)
|
|
807
|
+
|
|
808
|
+
def some_elements(self) -> list:
|
|
809
|
+
"""
|
|
810
|
+
Return a list of some elements of ``self``.
|
|
811
|
+
|
|
812
|
+
EXAMPLES::
|
|
813
|
+
|
|
814
|
+
sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field
|
|
815
|
+
sage: A.some_elements() # needs sage.rings.number_field
|
|
816
|
+
[s1, s1*s2*s3, (s1*s2*s3)^3]
|
|
817
|
+
"""
|
|
818
|
+
rank = self.coxeter_matrix().rank()
|
|
819
|
+
elements_list = [self.gen(0)]
|
|
820
|
+
elements_list.append(self.prod(self.gens()))
|
|
821
|
+
elements_list.append(elements_list[-1] ** min(rank, 3))
|
|
822
|
+
return elements_list
|
|
823
|
+
|
|
824
|
+
def _standard_lift_Tietze(self, w):
|
|
825
|
+
"""
|
|
826
|
+
Return a Tietze word representing the Coxeter element ``w``
|
|
827
|
+
under the natural section.
|
|
828
|
+
|
|
829
|
+
INPUT:
|
|
830
|
+
|
|
831
|
+
- ``w`` -- an element of the Coxeter group of ``self``
|
|
832
|
+
|
|
833
|
+
EXAMPLES::
|
|
834
|
+
|
|
835
|
+
sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field
|
|
836
|
+
sage: A._standard_lift_Tietze(A.coxeter_group().long_element()) # needs sage.rings.number_field
|
|
837
|
+
[3, 2, 3, 1, 2, 3, 1, 2, 1]
|
|
838
|
+
"""
|
|
839
|
+
return w.reduced_word()
|
|
840
|
+
|
|
841
|
+
@cached_method
|
|
842
|
+
def _standard_lift(self, w):
|
|
843
|
+
"""
|
|
844
|
+
Return the element of ``self`` that corresponds to the given
|
|
845
|
+
Coxeter element ``w`` under the natural section.
|
|
846
|
+
|
|
847
|
+
INPUT:
|
|
848
|
+
|
|
849
|
+
- ``w`` -- an element of the Coxeter group of ``self``
|
|
850
|
+
|
|
851
|
+
EXAMPLES::
|
|
852
|
+
|
|
853
|
+
sage: A = ArtinGroup(['B',3]) # needs sage.combinat sage.rings.number_field
|
|
854
|
+
sage: A._standard_lift(A.coxeter_group().long_element()) # needs sage.combinat sage.rings.number_field
|
|
855
|
+
s3*(s2*s3*s1)^2*s2*s1
|
|
856
|
+
|
|
857
|
+
sage: B = BraidGroup(5)
|
|
858
|
+
sage: P = Permutation([5, 3, 1, 2, 4])
|
|
859
|
+
sage: B._standard_lift(P)
|
|
860
|
+
s0*s1*s2*s3*s0*s1
|
|
861
|
+
"""
|
|
862
|
+
return self(self._standard_lift_Tietze(w))
|
|
863
|
+
|
|
864
|
+
@lazy_attribute
|
|
865
|
+
def _burau_generators(self):
|
|
866
|
+
"""
|
|
867
|
+
The Burau matrices for the generators of ``self`` and their inverses.
|
|
868
|
+
|
|
869
|
+
EXAMPLES::
|
|
870
|
+
|
|
871
|
+
sage: A = ArtinGroup(['G',2])
|
|
872
|
+
sage: A._burau_generators
|
|
873
|
+
[[
|
|
874
|
+
[-t^2 a*t] [ 1 0]
|
|
875
|
+
[ 0 1], [ a*t -t^2]
|
|
876
|
+
],
|
|
877
|
+
[
|
|
878
|
+
[ -t^-2 a*t^-1] [ 1 0]
|
|
879
|
+
[ 0 1], [a*t^-1 -t^-2]
|
|
880
|
+
]]
|
|
881
|
+
|
|
882
|
+
sage: A = ArtinGroup(['H',3])
|
|
883
|
+
sage: A._burau_generators
|
|
884
|
+
[[
|
|
885
|
+
[-t^2 t 0] [ 1 0 0]
|
|
886
|
+
[ 0 1 0] [ t -t^2 (1/2*a + 1/2)*t]
|
|
887
|
+
[ 0 0 1], [ 0 0 1],
|
|
888
|
+
<BLANKLINE>
|
|
889
|
+
[ 1 0 0]
|
|
890
|
+
[ 0 1 0]
|
|
891
|
+
[ 0 (1/2*a + 1/2)*t -t^2]
|
|
892
|
+
],
|
|
893
|
+
[
|
|
894
|
+
[-t^-2 t^-1 0]
|
|
895
|
+
[ 0 1 0]
|
|
896
|
+
[ 0 0 1],
|
|
897
|
+
<BLANKLINE>
|
|
898
|
+
[ 1 0 0]
|
|
899
|
+
[ t^-1 -t^-2 (1/2*a + 1/2)*t^-1]
|
|
900
|
+
[ 0 0 1],
|
|
901
|
+
<BLANKLINE>
|
|
902
|
+
[ 1 0 0]
|
|
903
|
+
[ 0 1 0]
|
|
904
|
+
[ 0 (1/2*a + 1/2)*t^-1 -t^-2]
|
|
905
|
+
]]
|
|
906
|
+
|
|
907
|
+
sage: CM = matrix([[1,4,7], [4,1,10], [7,10,1]])
|
|
908
|
+
sage: A = ArtinGroup(CM)
|
|
909
|
+
sage: gens = A._burau_generators[0]; gens
|
|
910
|
+
[
|
|
911
|
+
[ -t^2 (E(8) - E(8)^3)*t (-E(7)^3 - E(7)^4)*t]
|
|
912
|
+
[ 0 1 0]
|
|
913
|
+
[ 0 0 1],
|
|
914
|
+
<BLANKLINE>
|
|
915
|
+
[ 1 0 0]
|
|
916
|
+
[ (E(8) - E(8)^3)*t -t^2 (E(20) - E(20)^9)*t]
|
|
917
|
+
[ 0 0 1],
|
|
918
|
+
<BLANKLINE>
|
|
919
|
+
[ 1 0 0]
|
|
920
|
+
[ 0 1 0]
|
|
921
|
+
[(-E(7)^3 - E(7)^4)*t (E(20) - E(20)^9)*t -t^2]
|
|
922
|
+
]
|
|
923
|
+
sage: all(gens[i] * A._burau_generators[1][i] == 1 for i in range(3))
|
|
924
|
+
True
|
|
925
|
+
sage: B1, B2, B3 = gens
|
|
926
|
+
sage: (B1 * B2)^2 == (B2 * B1)^2
|
|
927
|
+
True
|
|
928
|
+
sage: (B2 * B3)^5 == (B3 * B2)^5
|
|
929
|
+
True
|
|
930
|
+
sage: B1 * B3 * B1 * B3 * B1 * B3 * B1 == B3 * B1 * B3 * B1 * B3 * B1 * B3
|
|
931
|
+
True
|
|
932
|
+
"""
|
|
933
|
+
data = self.coxeter_type()
|
|
934
|
+
coxeter_matrix = self.coxeter_matrix()
|
|
935
|
+
n = coxeter_matrix.rank()
|
|
936
|
+
|
|
937
|
+
# Determine the base field
|
|
938
|
+
if data.is_simply_laced():
|
|
939
|
+
from sage.rings.integer_ring import ZZ
|
|
940
|
+
base_ring = ZZ
|
|
941
|
+
elif data.is_finite():
|
|
942
|
+
from sage.rings.number_field.number_field import QuadraticField
|
|
943
|
+
letter = data.cartan_type().type()
|
|
944
|
+
if letter in ['B', 'C', 'F']:
|
|
945
|
+
base_ring = QuadraticField(2)
|
|
946
|
+
elif letter == 'G':
|
|
947
|
+
base_ring = QuadraticField(3)
|
|
948
|
+
elif letter == 'H':
|
|
949
|
+
base_ring = QuadraticField(5)
|
|
950
|
+
else:
|
|
951
|
+
from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
|
|
952
|
+
base_ring = UniversalCyclotomicField()
|
|
953
|
+
else:
|
|
954
|
+
from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
|
|
955
|
+
base_ring = UniversalCyclotomicField()
|
|
956
|
+
|
|
957
|
+
# Construct the matrices
|
|
958
|
+
from sage.matrix.args import SparseEntry
|
|
959
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
960
|
+
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
|
|
961
|
+
import sage.rings.abc
|
|
962
|
+
poly_ring = LaurentPolynomialRing(base_ring, 't')
|
|
963
|
+
q = -poly_ring.gen()
|
|
964
|
+
MS = MatrixSpace(poly_ring, n, sparse=True)
|
|
965
|
+
one = MS.one()
|
|
966
|
+
# FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
|
|
967
|
+
if isinstance(base_ring, sage.rings.abc.UniversalCyclotomicField):
|
|
968
|
+
E = base_ring.gen
|
|
969
|
+
|
|
970
|
+
def val(x):
|
|
971
|
+
if x == -1:
|
|
972
|
+
return 2 * q
|
|
973
|
+
elif x == 1:
|
|
974
|
+
return 1 + q**2
|
|
975
|
+
else:
|
|
976
|
+
E2x = E(2 * x)
|
|
977
|
+
return q * (E2x + ~E2x)
|
|
978
|
+
elif isinstance(base_ring, sage.rings.abc.NumberField_quadratic):
|
|
979
|
+
from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
|
|
980
|
+
E = UniversalCyclotomicField().gen
|
|
981
|
+
|
|
982
|
+
def val(x):
|
|
983
|
+
if x == -1:
|
|
984
|
+
return 2 * q
|
|
985
|
+
elif x == 1:
|
|
986
|
+
return 1 + q**2
|
|
987
|
+
else:
|
|
988
|
+
return q * base_ring((E(2 * x) + ~E(2 * x)).to_cyclotomic_field())
|
|
989
|
+
else:
|
|
990
|
+
def val(x):
|
|
991
|
+
if x == -1:
|
|
992
|
+
return 2 * q
|
|
993
|
+
elif x == 1:
|
|
994
|
+
return 1 + q**2
|
|
995
|
+
elif x == 2:
|
|
996
|
+
return 0
|
|
997
|
+
elif x == 3:
|
|
998
|
+
return q
|
|
999
|
+
else:
|
|
1000
|
+
from sage.functions.trig import cos
|
|
1001
|
+
from sage.symbolic.constants import pi
|
|
1002
|
+
return q * base_ring(2 * cos(pi / x))
|
|
1003
|
+
index_set = data.index_set()
|
|
1004
|
+
gens = [one - MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]]))
|
|
1005
|
+
for j in range(n)])
|
|
1006
|
+
for i in range(n)]
|
|
1007
|
+
invs = [one - q**-2 * MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]]))
|
|
1008
|
+
for j in range(n)])
|
|
1009
|
+
for i in range(n)]
|
|
1010
|
+
return [gens, invs]
|
|
1011
|
+
|
|
1012
|
+
Element = ArtinGroupElement
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
class FiniteTypeArtinGroup(ArtinGroup):
|
|
1016
|
+
r"""
|
|
1017
|
+
A finite-type Artin group.
|
|
1018
|
+
|
|
1019
|
+
An Artin group is *finite-type* or *spherical* if the corresponding
|
|
1020
|
+
Coxeter group is finite. Finite type Artin groups are known to be
|
|
1021
|
+
torsion free, have a Garside structure given by `\Delta` (see
|
|
1022
|
+
:meth:`delta`) and have a center generated by `\Delta`.
|
|
1023
|
+
|
|
1024
|
+
.. SEEALSO::
|
|
1025
|
+
|
|
1026
|
+
:class:`ArtinGroup`
|
|
1027
|
+
|
|
1028
|
+
EXAMPLES::
|
|
1029
|
+
|
|
1030
|
+
sage: ArtinGroup(['E',7]) # needs sage.rings.number_field
|
|
1031
|
+
Artin group of type ['E', 7]
|
|
1032
|
+
|
|
1033
|
+
Since the word problem for finite-type Artin groups is solvable, their
|
|
1034
|
+
Cayley graph can be locally obtained as follows (see :issue:`16059`)::
|
|
1035
|
+
|
|
1036
|
+
sage: def ball(group, radius):
|
|
1037
|
+
....: ret = set()
|
|
1038
|
+
....: ret.add(group.one())
|
|
1039
|
+
....: for length in range(1, radius):
|
|
1040
|
+
....: for w in Words(alphabet=group.gens(), length=length):
|
|
1041
|
+
....: ret.add(prod(w))
|
|
1042
|
+
....: return ret
|
|
1043
|
+
sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field
|
|
1044
|
+
sage: GA = A.cayley_graph(elements=ball(A, 4), generators=A.gens()); GA # needs sage.combinat sage.graphs sage.rings.number_field
|
|
1045
|
+
Digraph on 32 vertices
|
|
1046
|
+
|
|
1047
|
+
Since the Artin group has nontrivial relations, this graph contains less
|
|
1048
|
+
vertices than the one associated to the free group (which is a tree)::
|
|
1049
|
+
|
|
1050
|
+
sage: F = FreeGroup(3)
|
|
1051
|
+
sage: GF = F.cayley_graph(elements=ball(F, 4), generators=F.gens()); GF # needs sage.combinat sage.graphs sage.combinat
|
|
1052
|
+
Digraph on 40 vertices
|
|
1053
|
+
"""
|
|
1054
|
+
def delta(self):
|
|
1055
|
+
r"""
|
|
1056
|
+
Return the `\Delta` element of ``self``.
|
|
1057
|
+
|
|
1058
|
+
EXAMPLES::
|
|
1059
|
+
|
|
1060
|
+
sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field
|
|
1061
|
+
sage: A.delta() # needs sage.rings.number_field
|
|
1062
|
+
s3*(s2*s3*s1)^2*s2*s1
|
|
1063
|
+
|
|
1064
|
+
sage: A = ArtinGroup(['G',2]) # needs sage.rings.number_field
|
|
1065
|
+
sage: A.delta() # needs sage.rings.number_field
|
|
1066
|
+
(s2*s1)^3
|
|
1067
|
+
|
|
1068
|
+
sage: B = BraidGroup(5) # needs sage.combinat
|
|
1069
|
+
sage: B.delta() # needs sage.combinat
|
|
1070
|
+
s0*s1*s2*s3*s0*s1*s2*s0*s1*s0
|
|
1071
|
+
"""
|
|
1072
|
+
return self._standard_lift(self._coxeter_group.long_element())
|
|
1073
|
+
|
|
1074
|
+
Element = FiniteTypeArtinGroupElement
|