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
|
@@ -0,0 +1,2052 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-groups
|
|
2
|
+
# sage.doctest: needs sage.combinat
|
|
3
|
+
r"""
|
|
4
|
+
Cubic Braid Groups
|
|
5
|
+
|
|
6
|
+
This module is devoted to factor groups of the Artin braid groups, such
|
|
7
|
+
that the images `s_i` of the braid generators have order three:
|
|
8
|
+
|
|
9
|
+
.. MATH::
|
|
10
|
+
|
|
11
|
+
s_i^3 = 1.
|
|
12
|
+
|
|
13
|
+
In general these groups have firstly been investigated by Coxeter, H.S.M.
|
|
14
|
+
in: "Factor groups of the braid groups, Proceedings of the Fourth Canadian
|
|
15
|
+
Mathematical Congress (Vancouver 1957), pp. 95-122".
|
|
16
|
+
|
|
17
|
+
Coxeter showed, that these groups are finite as long as the number of
|
|
18
|
+
strands is less than 6 and infinite else-wise. More explicitly the factor
|
|
19
|
+
group on three strand braids is isomorphic to `SL(2,3)`, on four strand
|
|
20
|
+
braids to `GU(3,2)` and on five strand braids to `Sp(4,3) \times C_3`.
|
|
21
|
+
Today, these finite groups are known as irreducible complex reflection groups
|
|
22
|
+
enumerated in the Shephard-Todd classification as `G_{4}`, `G_{25}` and
|
|
23
|
+
`G_{32}`.
|
|
24
|
+
|
|
25
|
+
Coxeter realized these groups as subgroups of unitary groups with respect
|
|
26
|
+
to a certain Hermitian form over the complex numbers (in fact over `\QQ`
|
|
27
|
+
adjoined with a primitive `12`-th root of unity).
|
|
28
|
+
|
|
29
|
+
In "Einige endliche Faktorgruppen der Zopfgruppen" (Math. Z., 163 (1978),
|
|
30
|
+
291-302) J. Assion considered two series `S(m)` and `U(m)` of finite
|
|
31
|
+
factors of these groups. The additional relations on the braid group
|
|
32
|
+
generators `\{ s_1, \cdots, s_{m-1}\}` are
|
|
33
|
+
|
|
34
|
+
.. MATH::
|
|
35
|
+
|
|
36
|
+
\begin{array}{lll}
|
|
37
|
+
\mbox{S:} & s_3 s_1 t_2 s_1 t_2^{-1} t_3 t_2 s_1 t_2^{-1} t_3^{-1} = 1
|
|
38
|
+
& \mbox{ for } m >= 5 \mbox{ in case } S(m)\\
|
|
39
|
+
\mbox{U:} & t_1 t_3 = 1
|
|
40
|
+
& \mbox{ for } m >= 5 \mbox{ in case } U(m)
|
|
41
|
+
\end{array}
|
|
42
|
+
|
|
43
|
+
where `t_i = (s_i s_{i+1})^3`. He showed that each series of finite cubic
|
|
44
|
+
braid group factors must be an epimorphic image of one of his two series,
|
|
45
|
+
as long as the groups with less than 5 strands are the full cubic braid
|
|
46
|
+
groups, whereas the group on 5 strands is not. He realized the groups `S(m)`
|
|
47
|
+
as symplectic groups over `GF(3)` (resp. subgroups therein) and `U(m)` as
|
|
48
|
+
general unitary groups over `GF(4)` (resp. subgroups therein).
|
|
49
|
+
|
|
50
|
+
All the groups considered by Coxeter and Assion are considered as finitely
|
|
51
|
+
presented groups together with the classical realizations. It also allows
|
|
52
|
+
for the conversion maps between the two realizations. In addition, we can
|
|
53
|
+
construct other realizations and maps to matrix groups with help of the
|
|
54
|
+
Burau representation. In case ``gap3`` and ``CHEVIE`` are installed, the
|
|
55
|
+
reflection groups (via the ``gap3`` interface) are available, too. This can
|
|
56
|
+
be done using the methods :meth:`as_classical_group`, :meth:`as_matrix_group`,
|
|
57
|
+
:meth:`as_permutation_group`, and :meth:`as_reflection_group`.
|
|
58
|
+
|
|
59
|
+
TESTS::
|
|
60
|
+
|
|
61
|
+
sage: CubicBraidGroup(4).category()
|
|
62
|
+
Category of shephard groups
|
|
63
|
+
sage: CubicBraidGroup(6).category()
|
|
64
|
+
Category of infinite groups
|
|
65
|
+
|
|
66
|
+
REFERENCES:
|
|
67
|
+
|
|
68
|
+
- [Cox1957]_
|
|
69
|
+
- [Ass1978]_
|
|
70
|
+
|
|
71
|
+
AUTHORS:
|
|
72
|
+
|
|
73
|
+
- Sebastian Oehms 2019-02-16, initial version.
|
|
74
|
+
"""
|
|
75
|
+
# ****************************************************************************
|
|
76
|
+
# Copyright (C) 2019 Sebastian Oehms <seb.oehms@gmail.com>
|
|
77
|
+
#
|
|
78
|
+
# This program is free software: you can redistribute it and/or modify
|
|
79
|
+
# it under the terms of the GNU General Public License as published by
|
|
80
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
81
|
+
# (at your option) any later version.
|
|
82
|
+
# https://www.gnu.org/licenses/
|
|
83
|
+
# ****************************************************************************
|
|
84
|
+
|
|
85
|
+
from enum import Enum
|
|
86
|
+
|
|
87
|
+
import sage.rings.abc
|
|
88
|
+
|
|
89
|
+
from sage.categories.groups import Groups
|
|
90
|
+
from sage.categories.shephard_groups import ShephardGroups
|
|
91
|
+
from sage.groups.free_group import FreeGroup
|
|
92
|
+
from sage.groups.finitely_presented import FinitelyPresentedGroup, FinitelyPresentedGroupElement
|
|
93
|
+
from sage.groups.braid import BraidGroup
|
|
94
|
+
from sage.misc.cachefunc import cached_method
|
|
95
|
+
from sage.rings.integer import Integer
|
|
96
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
from sage.libs.gap.element import GapElement
|
|
101
|
+
except ImportError:
|
|
102
|
+
GapElement = ()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
##############################################################################
|
|
106
|
+
#
|
|
107
|
+
# helper functions
|
|
108
|
+
#
|
|
109
|
+
##############################################################################
|
|
110
|
+
|
|
111
|
+
def _reduce_tietze(tietze_list):
|
|
112
|
+
r"""
|
|
113
|
+
Reduce the length of a list representing a cubic braid as much as it is
|
|
114
|
+
easily possible using the second braid relation and degree reduction.
|
|
115
|
+
|
|
116
|
+
EXAMPLES::
|
|
117
|
+
|
|
118
|
+
sage: from sage.groups.cubic_braid import _reduce_tietze
|
|
119
|
+
sage: _reduce_tietze((2, 2, -3, 5, 3, 1, 1, 5))
|
|
120
|
+
[-2, -5, -1]
|
|
121
|
+
"""
|
|
122
|
+
def eliminate_item(tietze_list):
|
|
123
|
+
"""
|
|
124
|
+
This sub method searches for an item in the Tietze expression such
|
|
125
|
+
that it together with the first entry gives a pair which can be
|
|
126
|
+
replaced by the second braid relation and the generators degree
|
|
127
|
+
reduction. If no such pair exists, it returns ``None``. Otherwise
|
|
128
|
+
the reduced tietze list is returned.
|
|
129
|
+
"""
|
|
130
|
+
l = len(tietze_list)
|
|
131
|
+
if l < 2:
|
|
132
|
+
return None
|
|
133
|
+
first = tietze_list[0]
|
|
134
|
+
second = None
|
|
135
|
+
for i in range(1, l):
|
|
136
|
+
if tietze_list[i] in (first, -first):
|
|
137
|
+
if i == 1:
|
|
138
|
+
second = tietze_list[i]
|
|
139
|
+
break
|
|
140
|
+
if all(abs(abs(tietze_list[j])-abs(first)) > 1 for j in range(1, i)):
|
|
141
|
+
# the entry on position i can be moved right to the first entry
|
|
142
|
+
# by the second braid relation
|
|
143
|
+
second = tietze_list[i]
|
|
144
|
+
break
|
|
145
|
+
if second is None:
|
|
146
|
+
return None
|
|
147
|
+
middle = tietze_list[1:i]
|
|
148
|
+
end = tietze_list[i+1:l]
|
|
149
|
+
if first == second:
|
|
150
|
+
return [-first] + middle + end
|
|
151
|
+
else:
|
|
152
|
+
return middle + end
|
|
153
|
+
|
|
154
|
+
tietze_list = list(tietze_list)
|
|
155
|
+
l = len(tietze_list)
|
|
156
|
+
for i in range(l):
|
|
157
|
+
end = tietze_list[i:l]
|
|
158
|
+
tietze_list_red = eliminate_item(end)
|
|
159
|
+
if tietze_list_red is not None:
|
|
160
|
+
start = tietze_list[:i]
|
|
161
|
+
return start + _reduce_tietze(tietze_list_red)
|
|
162
|
+
return tietze_list
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
##############################################################################
|
|
166
|
+
#
|
|
167
|
+
# Functions to create Instances of the CubicBraidGroup
|
|
168
|
+
#
|
|
169
|
+
##############################################################################
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# ----------------------------------------------------------------------------------
|
|
173
|
+
# Short-Hands for Assions groups:
|
|
174
|
+
# ----------------------------------------------------------------------------------
|
|
175
|
+
def AssionGroupS(n=None, names='s'):
|
|
176
|
+
r"""
|
|
177
|
+
Construct cubic braid groups :class:`CubicBraidGroup` which have been
|
|
178
|
+
investigated by J.Assion using the notation S(m). This function is a short hand cut
|
|
179
|
+
for setting the construction arguments ``cbg_type=CubicBraidGroup.type.AssionS``
|
|
180
|
+
and default ``names='s'``.
|
|
181
|
+
|
|
182
|
+
INPUT:
|
|
183
|
+
|
|
184
|
+
- ``n`` -- integer (optional); the number of strands
|
|
185
|
+
- ``names`` -- (default: ``'s'``) string or list/tuple/iterable of strings
|
|
186
|
+
|
|
187
|
+
.. SEEALSO::
|
|
188
|
+
|
|
189
|
+
:class:`CubicBraidGroup`
|
|
190
|
+
|
|
191
|
+
EXAMPLES::
|
|
192
|
+
|
|
193
|
+
sage: S3 = AssionGroupS(3); S3
|
|
194
|
+
Assion group on 3 strands of type S
|
|
195
|
+
sage: S3x = CubicBraidGroup(3, names='s', cbg_type=CubicBraidGroup.type.AssionS); S3x
|
|
196
|
+
Assion group on 3 strands of type S
|
|
197
|
+
sage: S3 == S3x
|
|
198
|
+
True
|
|
199
|
+
"""
|
|
200
|
+
return CubicBraidGroup(n=n, names=names, cbg_type=CubicBraidGroup.type.AssionS)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def AssionGroupU(n=None, names='u'):
|
|
204
|
+
r"""
|
|
205
|
+
Construct cubic braid groups as instance of :class:`CubicBraidGroup` which have been
|
|
206
|
+
investigated by J.Assion using the notation U(m). This function is a short hand cut
|
|
207
|
+
for setting the construction arguments ``cbg_type=CubicBraidGroup.type.AssionU``
|
|
208
|
+
and default ``names='u'``.
|
|
209
|
+
|
|
210
|
+
INPUT:
|
|
211
|
+
|
|
212
|
+
- ``n`` -- integer (optional); the number of strands
|
|
213
|
+
- ``names`` -- (default: ``'s'``) string or list/tuple/iterable of strings
|
|
214
|
+
|
|
215
|
+
.. SEEALSO::
|
|
216
|
+
|
|
217
|
+
:class:`CubicBraidGroup`
|
|
218
|
+
|
|
219
|
+
EXAMPLES::
|
|
220
|
+
|
|
221
|
+
sage: U3 = AssionGroupU(3); U3
|
|
222
|
+
Assion group on 3 strands of type U
|
|
223
|
+
sage: U3x = CubicBraidGroup(3, names='u', cbg_type=CubicBraidGroup.type.AssionU); U3x
|
|
224
|
+
Assion group on 3 strands of type U
|
|
225
|
+
sage: U3 == U3x
|
|
226
|
+
True
|
|
227
|
+
"""
|
|
228
|
+
return CubicBraidGroup(n=n, names=names, cbg_type=CubicBraidGroup.type.AssionU)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
##############################################################################
|
|
232
|
+
#
|
|
233
|
+
# Class CubicBraidElement (for elements)
|
|
234
|
+
#
|
|
235
|
+
##############################################################################
|
|
236
|
+
|
|
237
|
+
class CubicBraidElement(FinitelyPresentedGroupElement):
|
|
238
|
+
r"""
|
|
239
|
+
Elements of cubic factor groups of the braid group.
|
|
240
|
+
|
|
241
|
+
For more information see :class:`CubicBraidGroup`.
|
|
242
|
+
|
|
243
|
+
EXAMPLES::
|
|
244
|
+
|
|
245
|
+
sage: C4.<c1, c2, c3> = CubicBraidGroup(4); C4
|
|
246
|
+
Cubic Braid group on 4 strands
|
|
247
|
+
sage: ele1 = c1*c2*c3^-1*c2^-1
|
|
248
|
+
sage: ele2 = C4((1, 2, -3, -2))
|
|
249
|
+
sage: ele1 == ele2
|
|
250
|
+
True
|
|
251
|
+
"""
|
|
252
|
+
def __init__(self, parent, x, check=True):
|
|
253
|
+
"""
|
|
254
|
+
Initialize ``self``.
|
|
255
|
+
|
|
256
|
+
EXAMPLES::
|
|
257
|
+
|
|
258
|
+
sage: C6 = CubicBraidGroup(6)
|
|
259
|
+
sage: C6.inject_variables()
|
|
260
|
+
Defining c0, c1, c2, c3, c4
|
|
261
|
+
sage: c1**2*~c2*c4*c0**2*c4 # indirect doctest
|
|
262
|
+
c1^-1*c2^-1*c4^-1*c0^-1
|
|
263
|
+
"""
|
|
264
|
+
if type(x) in (tuple, list):
|
|
265
|
+
x = tuple(_reduce_tietze(tuple(x)))
|
|
266
|
+
elif isinstance(x, GapElement):
|
|
267
|
+
tietze_list = x.UnderlyingElement().TietzeWordAbstractWord().sage()
|
|
268
|
+
tietze_red = _reduce_tietze(tietze_list)
|
|
269
|
+
if tietze_red != tietze_list:
|
|
270
|
+
x = tuple(tietze_red)
|
|
271
|
+
super().__init__(parent, x, check=check)
|
|
272
|
+
|
|
273
|
+
def _richcmp_(self, other, op):
|
|
274
|
+
"""
|
|
275
|
+
Rich comparison of ``self`` with ``other``.
|
|
276
|
+
|
|
277
|
+
Overwrite comparison since the inherited one from
|
|
278
|
+
:class:`FinitelyPresentedGroupElement` (via Gap) does not terminate
|
|
279
|
+
in the case of more than 5 strands (not only infinite cases).
|
|
280
|
+
On less than 5 strands comparison is not assumed to be deterministic
|
|
281
|
+
(see the :issue:`33498` and :gap:`section 47.3-2 of the
|
|
282
|
+
Gap Reference manual <chap47>`).
|
|
283
|
+
|
|
284
|
+
Therefore, the comparison is done via the Burau representation.
|
|
285
|
+
|
|
286
|
+
EXAMPLES::
|
|
287
|
+
|
|
288
|
+
sage: CBG3 = CubicBraidGroup(3)
|
|
289
|
+
sage: sorted(CBG3) # indirect doctest, random output # needs sage.rings.number_field
|
|
290
|
+
[(c0*c1^-1)^2, c0*c1^-1*c0, c0^-1*c1*c0^-1, c0^-1*c1^-1*c0,
|
|
291
|
+
c1*c0^-1*c1, c0^-1*c1^-1*c0^-1, c0^-1*c1^-1, c1^-1*c0*c1^-1,
|
|
292
|
+
c0*c1^-1*c0^-1, c0^-1*c1, c0^-1*c1*c0, c0*c1^-1, c1*c0^-1,
|
|
293
|
+
c1^-1*c0^-1, c1^-1*c0, c1*c0, c0^-1, c0*c1*c0^-1, c0*c1*c0,
|
|
294
|
+
c0, c0*c1, c1^-1, c1, 1]
|
|
295
|
+
|
|
296
|
+
sage: C6.<c1, c2, c3, c4, c5> = CubicBraidGroup(6)
|
|
297
|
+
sage: ele1 = c1*c2*c3*c4*c5
|
|
298
|
+
sage: ele2 = c1*c2*c4*c5
|
|
299
|
+
sage: ele1 == ele2 # indirect doctest
|
|
300
|
+
False
|
|
301
|
+
sage: ele1 > ele2 # indirect doctest
|
|
302
|
+
True
|
|
303
|
+
|
|
304
|
+
TESTS::
|
|
305
|
+
|
|
306
|
+
sage: S7 = AssionGroupS(7)
|
|
307
|
+
sage: all(S7(rel).is_one() for rel in S7.relations())
|
|
308
|
+
True
|
|
309
|
+
"""
|
|
310
|
+
smat = self._matrix_()
|
|
311
|
+
omat = other._matrix_()
|
|
312
|
+
return smat._richcmp_(omat, op)
|
|
313
|
+
|
|
314
|
+
def __hash__(self):
|
|
315
|
+
r"""
|
|
316
|
+
Return a hash value for ``self``.
|
|
317
|
+
|
|
318
|
+
EXAMPLES::
|
|
319
|
+
|
|
320
|
+
sage: C3.<c1, c2> = CubicBraidGroup(3)
|
|
321
|
+
sage: hash(~c1) == hash(c1**2) # needs sage.rings.number_field
|
|
322
|
+
True
|
|
323
|
+
"""
|
|
324
|
+
return hash(self._matrix_())
|
|
325
|
+
|
|
326
|
+
@cached_method
|
|
327
|
+
def _matrix_(self):
|
|
328
|
+
r"""
|
|
329
|
+
Return ``self`` as a matrix according to its parent's default matrix
|
|
330
|
+
group.
|
|
331
|
+
|
|
332
|
+
So far, this method returns the same results as :meth:`burau_matrix`
|
|
333
|
+
in the default case.
|
|
334
|
+
|
|
335
|
+
EXAMPLES::
|
|
336
|
+
|
|
337
|
+
sage: S3.<s1, s2> = AssionGroupS(3)
|
|
338
|
+
sage: matrix(S3.an_element()) # needs sage.libs.pari
|
|
339
|
+
[2 1 1]
|
|
340
|
+
[1 0 0]
|
|
341
|
+
[0 1 0]
|
|
342
|
+
"""
|
|
343
|
+
mat_grp = self.parent().as_matrix_group()
|
|
344
|
+
return mat_grp(self).matrix()
|
|
345
|
+
|
|
346
|
+
def braid(self):
|
|
347
|
+
r"""
|
|
348
|
+
Return the canonical braid preimage of ``self`` as a :class:`Braid`.
|
|
349
|
+
|
|
350
|
+
EXAMPLES::
|
|
351
|
+
|
|
352
|
+
sage: C3.<c1, c2> = CubicBraidGroup(3)
|
|
353
|
+
sage: c1.parent()
|
|
354
|
+
Cubic Braid group on 3 strands
|
|
355
|
+
sage: c1.braid().parent()
|
|
356
|
+
Braid group on 3 strands
|
|
357
|
+
"""
|
|
358
|
+
braid_group = self.parent().braid_group()
|
|
359
|
+
return braid_group(self)
|
|
360
|
+
|
|
361
|
+
@cached_method
|
|
362
|
+
def burau_matrix(self, root_bur=None, domain=None, characteristic=None,
|
|
363
|
+
var='t', reduced=False):
|
|
364
|
+
r"""
|
|
365
|
+
Return the Burau matrix of the cubic braid coset.
|
|
366
|
+
|
|
367
|
+
This method uses the same method belonging to :class:`Braid`, but
|
|
368
|
+
reduces the indeterminate to a primitive sixth (resp. twelfth in case
|
|
369
|
+
``reduced='unitary'``) root of unity.
|
|
370
|
+
|
|
371
|
+
INPUT (all arguments are optional keywords):
|
|
372
|
+
|
|
373
|
+
- ``root_bur`` -- six (resp. twelfth) root of unity in some field
|
|
374
|
+
(default: root of unity over `\QQ`)
|
|
375
|
+
- ``domain`` -- (default: cyclotomic field of order 3 and degree 2, resp.
|
|
376
|
+
the domain of ``root_bur`` if given) base ring for the Burau matrix
|
|
377
|
+
- ``characteristic`` -- integer giving the characteristic of the
|
|
378
|
+
domain (default: 0 or the characteristic of ``domain`` if given)
|
|
379
|
+
- ``var`` -- string used for the indeterminate name in case ``root_bur``
|
|
380
|
+
must be constructed in a splitting field
|
|
381
|
+
- ``reduced`` -- boolean or string (default: ``False``); for more
|
|
382
|
+
information see the documentation of :meth:`burau_matrix` of
|
|
383
|
+
:class:`Braid`
|
|
384
|
+
|
|
385
|
+
OUTPUT:
|
|
386
|
+
|
|
387
|
+
The Burau matrix of the cubic braid coset with entries in the
|
|
388
|
+
domain given by the options. In case the option ``reduced='unitary'``
|
|
389
|
+
is given a triple consisting of the Burau matrix, its adjoined and
|
|
390
|
+
the Hermitian form is returned.
|
|
391
|
+
|
|
392
|
+
EXAMPLES::
|
|
393
|
+
|
|
394
|
+
sage: C3.<c1, c2> = CubicBraidGroup(3)
|
|
395
|
+
sage: ele = c1*c2*c1
|
|
396
|
+
|
|
397
|
+
sage: # needs sage.rings.number_field
|
|
398
|
+
sage: BuMa = ele.burau_matrix(); BuMa
|
|
399
|
+
[ -zeta3 1 zeta3]
|
|
400
|
+
[ -zeta3 zeta3 + 1 0]
|
|
401
|
+
[ 1 0 0]
|
|
402
|
+
sage: BuMa.base_ring()
|
|
403
|
+
Cyclotomic Field of order 3 and degree 2
|
|
404
|
+
sage: BuMa == ele.burau_matrix(characteristic=0)
|
|
405
|
+
True
|
|
406
|
+
sage: BuMa = ele.burau_matrix(domain=QQ); BuMa
|
|
407
|
+
[-t + 1 1 t - 1]
|
|
408
|
+
[-t + 1 t 0]
|
|
409
|
+
[ 1 0 0]
|
|
410
|
+
sage: BuMa.base_ring()
|
|
411
|
+
Number Field in t with defining polynomial t^2 - t + 1
|
|
412
|
+
sage: BuMa = ele.burau_matrix(domain = QQ[I, sqrt(3)]); BuMa # needs sage.symbolic
|
|
413
|
+
[ 1/2*sqrt3*I + 1/2 1 -1/2*sqrt3*I - 1/2]
|
|
414
|
+
[ 1/2*sqrt3*I + 1/2 -1/2*sqrt3*I + 1/2 0]
|
|
415
|
+
[ 1 0 0]
|
|
416
|
+
sage: BuMa.base_ring() # needs sage.symbolic
|
|
417
|
+
Number Field in I with defining polynomial x^2 + 1 over its base field
|
|
418
|
+
|
|
419
|
+
sage: # needs sage.libs.pari
|
|
420
|
+
sage: BuMa = ele.burau_matrix(characteristic=7); BuMa
|
|
421
|
+
[3 1 4]
|
|
422
|
+
[3 5 0]
|
|
423
|
+
[1 0 0]
|
|
424
|
+
sage: BuMa.base_ring()
|
|
425
|
+
Finite Field of size 7
|
|
426
|
+
|
|
427
|
+
sage: # needs sage.rings.finite_rings
|
|
428
|
+
sage: BuMa = ele.burau_matrix(characteristic=2); BuMa
|
|
429
|
+
[t + 1 1 t + 1]
|
|
430
|
+
[t + 1 t 0]
|
|
431
|
+
[ 1 0 0]
|
|
432
|
+
sage: BuMa.base_ring()
|
|
433
|
+
Finite Field in t of size 2^2
|
|
434
|
+
sage: F4.<r64> = GF(4)
|
|
435
|
+
sage: BuMa = ele.burau_matrix(root_bur=r64); BuMa
|
|
436
|
+
[r64 + 1 1 r64 + 1]
|
|
437
|
+
[r64 + 1 r64 0]
|
|
438
|
+
[ 1 0 0]
|
|
439
|
+
sage: BuMa.base_ring()
|
|
440
|
+
Finite Field in r64 of size 2^2
|
|
441
|
+
sage: BuMa = ele.burau_matrix(domain=GF(5)); BuMa
|
|
442
|
+
[2*t + 2 1 3*t + 3]
|
|
443
|
+
[2*t + 2 3*t + 4 0]
|
|
444
|
+
[ 1 0 0]
|
|
445
|
+
sage: BuMa.base_ring()
|
|
446
|
+
Finite Field in t of size 5^2
|
|
447
|
+
|
|
448
|
+
sage: # needs sage.rings.number_field
|
|
449
|
+
sage: BuMa, BuMaAd, H = ele.burau_matrix(reduced='unitary'); BuMa
|
|
450
|
+
[ 0 zeta12^3]
|
|
451
|
+
[zeta12^3 0]
|
|
452
|
+
sage: BuMa * H * BuMaAd == H
|
|
453
|
+
True
|
|
454
|
+
sage: BuMa.base_ring()
|
|
455
|
+
Cyclotomic Field of order 12 and degree 4
|
|
456
|
+
sage: BuMa, BuMaAd, H = ele.burau_matrix(domain=QQ[I, sqrt(3)], # needs sage.symbolic
|
|
457
|
+
....: reduced='unitary'); BuMa
|
|
458
|
+
[0 I]
|
|
459
|
+
[I 0]
|
|
460
|
+
sage: BuMa.base_ring() # needs sage.symbolic
|
|
461
|
+
Number Field in I with defining polynomial x^2 + 1 over its base field
|
|
462
|
+
"""
|
|
463
|
+
braid = self.braid()
|
|
464
|
+
|
|
465
|
+
from sage.misc.functional import cyclotomic_polynomial
|
|
466
|
+
min_pol_root_bur = cyclotomic_polynomial(6, var=var)
|
|
467
|
+
unitary = False
|
|
468
|
+
if isinstance(reduced, str):
|
|
469
|
+
if reduced == 'unitary':
|
|
470
|
+
unitary = True
|
|
471
|
+
min_pol_root_bur = cyclotomic_polynomial(12, var=var)
|
|
472
|
+
|
|
473
|
+
burau_ori = braid.burau_matrix(reduced=reduced)
|
|
474
|
+
|
|
475
|
+
if unitary:
|
|
476
|
+
burau_ori, burau_ori_adj, herm_form_ori = burau_ori
|
|
477
|
+
|
|
478
|
+
if domain is not None:
|
|
479
|
+
if isinstance(domain, sage.rings.abc.UniversalCyclotomicField):
|
|
480
|
+
if root_bur is None:
|
|
481
|
+
if unitary:
|
|
482
|
+
root_bur = domain.gen(12)
|
|
483
|
+
else:
|
|
484
|
+
root_bur = domain.gen(6)
|
|
485
|
+
|
|
486
|
+
if root_bur is None:
|
|
487
|
+
def find_root(domain):
|
|
488
|
+
min_pol = min_pol_root_bur.change_ring(domain)
|
|
489
|
+
root_list = min_pol.roots()
|
|
490
|
+
if not root_list:
|
|
491
|
+
domain = min_pol.splitting_field(min_pol_root_bur.variable_name())
|
|
492
|
+
min_pol = min_pol_root_bur.change_ring(domain)
|
|
493
|
+
root_list = min_pol.roots()
|
|
494
|
+
for root in root_list:
|
|
495
|
+
if root[0] == 0:
|
|
496
|
+
continue
|
|
497
|
+
root_bur = root[0]
|
|
498
|
+
if root[1] == 1:
|
|
499
|
+
break
|
|
500
|
+
return root_bur
|
|
501
|
+
|
|
502
|
+
if domain is None:
|
|
503
|
+
if characteristic is None:
|
|
504
|
+
# --------------------------------------------------------------------
|
|
505
|
+
# setting the default characteristic in order to achieve the according
|
|
506
|
+
# representations being well defined
|
|
507
|
+
# --------------------------------------------------------------------
|
|
508
|
+
cbg_type = self.parent()._cbg_type
|
|
509
|
+
if cbg_type == CubicBraidGroup.type.AssionS:
|
|
510
|
+
characteristic = 3 # making Assion type S relations vanish
|
|
511
|
+
elif cbg_type == CubicBraidGroup.type.AssionU:
|
|
512
|
+
characteristic = 2 # making Assion type U relations vanish
|
|
513
|
+
else:
|
|
514
|
+
characteristic = 0
|
|
515
|
+
try:
|
|
516
|
+
characteristic = Integer(characteristic)
|
|
517
|
+
except ValueError:
|
|
518
|
+
raise ValueError('characteristic must be in integer')
|
|
519
|
+
|
|
520
|
+
if not characteristic.is_zero() and not characteristic.is_prime():
|
|
521
|
+
raise ValueError('characteristic must be a prime')
|
|
522
|
+
if characteristic.is_zero():
|
|
523
|
+
from sage.rings.number_field.number_field import CyclotomicField
|
|
524
|
+
if unitary:
|
|
525
|
+
domain = CyclotomicField(12)
|
|
526
|
+
else:
|
|
527
|
+
domain = CyclotomicField(3)
|
|
528
|
+
else:
|
|
529
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
530
|
+
domain = GF(characteristic)
|
|
531
|
+
root_bur = find_root(domain)
|
|
532
|
+
domain = root_bur.parent()
|
|
533
|
+
|
|
534
|
+
else: # domain is not None
|
|
535
|
+
root_bur = find_root(domain)
|
|
536
|
+
|
|
537
|
+
else: # root_bur is not None
|
|
538
|
+
if domain is None:
|
|
539
|
+
domain = root_bur.parent()
|
|
540
|
+
|
|
541
|
+
if 1 not in domain:
|
|
542
|
+
raise ValueError('root_bur must belong to a domain containing 1')
|
|
543
|
+
|
|
544
|
+
min_pol_root_bur = min_pol_root_bur.change_ring(domain)
|
|
545
|
+
if not min_pol_root_bur(root_bur).is_zero():
|
|
546
|
+
raise ValueError('root_bur must vanish on %s' % (min_pol_root_bur))
|
|
547
|
+
|
|
548
|
+
def conv2domain(laur_pol):
|
|
549
|
+
l1, l2 = laur_pol.polynomial_construction()
|
|
550
|
+
p1 = l1.change_ring(domain)
|
|
551
|
+
p2 = root_bur**(l2)
|
|
552
|
+
res = p1(root_bur) * p2
|
|
553
|
+
return res
|
|
554
|
+
|
|
555
|
+
from sage.matrix.constructor import matrix
|
|
556
|
+
|
|
557
|
+
d1, d2 = burau_ori.dimensions()
|
|
558
|
+
burau_mat = matrix(d1, d2, lambda i, j: conv2domain(burau_ori[i, j]))
|
|
559
|
+
|
|
560
|
+
if unitary:
|
|
561
|
+
burau_mat_adj = matrix(d1, d2, lambda i, j: conv2domain(burau_ori_adj[i, j]))
|
|
562
|
+
herm_form = matrix(d1, d2, lambda i, j: conv2domain(herm_form_ori[i, j]))
|
|
563
|
+
return burau_mat, burau_mat_adj, herm_form
|
|
564
|
+
|
|
565
|
+
return burau_mat
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
##############################################################################
|
|
569
|
+
#
|
|
570
|
+
# Class CubicBraidGroup
|
|
571
|
+
#
|
|
572
|
+
##############################################################################
|
|
573
|
+
class CubicBraidGroup(UniqueRepresentation, FinitelyPresentedGroup):
|
|
574
|
+
r"""
|
|
575
|
+
Factor groups of the Artin braid group mapping their generators to elements
|
|
576
|
+
of order 3.
|
|
577
|
+
|
|
578
|
+
These groups are implemented as a particular case of finitely presented
|
|
579
|
+
groups similar to the :class:`BraidGroup_class`.
|
|
580
|
+
|
|
581
|
+
A cubic braid group can be created by giving the number of strands, and
|
|
582
|
+
the name of the generators in a similar way as it works for the
|
|
583
|
+
:class:`BraidGroup_class`.
|
|
584
|
+
|
|
585
|
+
INPUT:
|
|
586
|
+
|
|
587
|
+
- ``names`` -- see the corresponding documentation of :class:`BraidGroup_class`
|
|
588
|
+
- ``cbg_type`` -- (default: ``CubicBraidGroup.type.Coxeter``;
|
|
589
|
+
see explanation below) enum type :class:`CubicBraidGroup.type`
|
|
590
|
+
|
|
591
|
+
Setting the keyword ``cbg_type`` to one on the values
|
|
592
|
+
``CubicBraidGroup.type.AssionS`` or ``CubicBraidGroup.type.AssionU``,
|
|
593
|
+
the additional relations due to Assion are added:
|
|
594
|
+
|
|
595
|
+
.. MATH::
|
|
596
|
+
|
|
597
|
+
\begin{array}{lll}
|
|
598
|
+
\mbox{S:} & s_3 s_1 t_2 s_1 t_2^{-1} t_3 t_2 s_1 t_2^{-1} t_3^{-1} = 1
|
|
599
|
+
& \mbox{ for } m >= 5 \mbox{ in case } S(m), \\
|
|
600
|
+
\mbox{U:} & t_1 t_3 = 1
|
|
601
|
+
& \mbox{ for } m >= 5 \mbox{ in case } U(m),
|
|
602
|
+
\end{array}
|
|
603
|
+
|
|
604
|
+
where `t_i = (s_i s_{i+1})^3`. If ``cbg_type == CubicBraidGroup.type.Coxeter``
|
|
605
|
+
(default) only the cubic relation on the generators is active (Coxeter's
|
|
606
|
+
case of investigation). Note that for `n = 2, 3, 4`, the groups do not
|
|
607
|
+
differ between the three possible values of ``cbg_type`` (as finitely
|
|
608
|
+
presented groups). However, the ``CubicBraidGroup.type.Coxeter``,
|
|
609
|
+
``CubicBraidGroup.type.AssionS`` and ``CubicBraidGroup.type.AssionU``
|
|
610
|
+
are different, so they have different classical realizations implemented.
|
|
611
|
+
|
|
612
|
+
.. SEEALSO::
|
|
613
|
+
|
|
614
|
+
Instances can also be constructed more easily by using
|
|
615
|
+
:func:`CubicBraidGroup`, :func:`AssionGroupS` and :func:`AssionGroupU`.
|
|
616
|
+
|
|
617
|
+
EXAMPLES::
|
|
618
|
+
|
|
619
|
+
sage: U3 = CubicBraidGroup(3, cbg_type=CubicBraidGroup.type.AssionU); U3
|
|
620
|
+
Assion group on 3 strands of type U
|
|
621
|
+
sage: U3.gens()
|
|
622
|
+
(c0, c1)
|
|
623
|
+
|
|
624
|
+
Alternative possibilities defining ``U3``::
|
|
625
|
+
|
|
626
|
+
sage: U3 = AssionGroupU(3); U3
|
|
627
|
+
Assion group on 3 strands of type U
|
|
628
|
+
sage: U3.gens()
|
|
629
|
+
(u0, u1)
|
|
630
|
+
sage: U3.<u1,u2> = AssionGroupU(3); U3
|
|
631
|
+
Assion group on 3 strands of type U
|
|
632
|
+
sage: U3.gens()
|
|
633
|
+
(u1, u2)
|
|
634
|
+
|
|
635
|
+
Alternates naming the generators::
|
|
636
|
+
|
|
637
|
+
sage: U3 = AssionGroupU(3, 'a, b'); U3
|
|
638
|
+
Assion group on 3 strands of type U
|
|
639
|
+
sage: U3.gens()
|
|
640
|
+
(a, b)
|
|
641
|
+
sage: C3 = CubicBraidGroup(3, 't'); C3
|
|
642
|
+
Cubic Braid group on 3 strands
|
|
643
|
+
sage: C3.gens()
|
|
644
|
+
(t0, t1)
|
|
645
|
+
sage: U3.is_isomorphic(C3)
|
|
646
|
+
True
|
|
647
|
+
sage: U3.as_classical_group() # needs sage.rings.number_field
|
|
648
|
+
Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20),
|
|
649
|
+
(1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)]
|
|
650
|
+
of (The projective general unitary group of degree 3 over Finite Field of size 2)
|
|
651
|
+
sage: C3.as_classical_group() # needs sage.rings.number_field
|
|
652
|
+
Subgroup with 2 generators (
|
|
653
|
+
[ E(3)^2 0] [ 1 -E(12)^7]
|
|
654
|
+
[-E(12)^7 1], [ 0 E(3)^2]
|
|
655
|
+
) of General Unitary Group of degree 2 over Universal Cyclotomic Field
|
|
656
|
+
with respect to positive definite hermitian form
|
|
657
|
+
[-E(12)^7 + E(12)^11 -1]
|
|
658
|
+
[ -1 -E(12)^7 + E(12)^11]
|
|
659
|
+
|
|
660
|
+
REFERENCES:
|
|
661
|
+
|
|
662
|
+
- [Cox1957]_
|
|
663
|
+
- [Ass1978]_
|
|
664
|
+
"""
|
|
665
|
+
|
|
666
|
+
Element = CubicBraidElement
|
|
667
|
+
|
|
668
|
+
##############################################################################
|
|
669
|
+
# Enum for the type of the group
|
|
670
|
+
##############################################################################
|
|
671
|
+
|
|
672
|
+
class type(Enum):
|
|
673
|
+
r"""
|
|
674
|
+
Enum class to select the type of the group:
|
|
675
|
+
|
|
676
|
+
- ``Coxeter`` -- ``'C'`` the full cubic braid group
|
|
677
|
+
- ``AssionS`` -- ``'S'`` finite factor group of type S considered by Assion
|
|
678
|
+
- ``AssionU`` -- ``'U'`` finite factor group of type U considered by Assion
|
|
679
|
+
|
|
680
|
+
EXAMPLES::
|
|
681
|
+
|
|
682
|
+
sage: S2 = CubicBraidGroup(2, cbg_type=CubicBraidGroup.type.AssionS); S2
|
|
683
|
+
Assion group on 2 strands of type S
|
|
684
|
+
sage: U3 = CubicBraidGroup(2, cbg_type='U')
|
|
685
|
+
Traceback (most recent call last):
|
|
686
|
+
...
|
|
687
|
+
TypeError: the cbg_type must be an instance of <enum 'CubicBraidGroup.type'>
|
|
688
|
+
"""
|
|
689
|
+
Coxeter = 'C'
|
|
690
|
+
AssionS = 'S'
|
|
691
|
+
AssionU = 'U'
|
|
692
|
+
|
|
693
|
+
###########################################################################################
|
|
694
|
+
# private methods
|
|
695
|
+
###########################################################################################
|
|
696
|
+
@staticmethod
|
|
697
|
+
def __classcall_private__(cls, n=None, names='c', cbg_type=None):
|
|
698
|
+
r"""
|
|
699
|
+
Normalize input to ensure a unique representation.
|
|
700
|
+
|
|
701
|
+
EXAMPLES::
|
|
702
|
+
|
|
703
|
+
sage: C3 = CubicBraidGroup(3); C3.generators()
|
|
704
|
+
(c0, c1)
|
|
705
|
+
sage: CubicBraidGroup(3, 'g').generators()
|
|
706
|
+
(g0, g1)
|
|
707
|
+
sage: U3.<u1,u2>=CubicBraidGroup(3, cbg_type=CubicBraidGroup.type.AssionU); U3.generators()
|
|
708
|
+
(u1, u2)
|
|
709
|
+
"""
|
|
710
|
+
# this code is adapted from :func:`BraidGroup`
|
|
711
|
+
# Support Freegroup('a,b') syntax
|
|
712
|
+
if n is not None:
|
|
713
|
+
try:
|
|
714
|
+
n = Integer(n)-1
|
|
715
|
+
except TypeError:
|
|
716
|
+
names = n
|
|
717
|
+
|
|
718
|
+
n = None
|
|
719
|
+
# derive n from counting names
|
|
720
|
+
if n is None:
|
|
721
|
+
if isinstance(names, str):
|
|
722
|
+
n = len(names.split(','))
|
|
723
|
+
else:
|
|
724
|
+
names = list(names)
|
|
725
|
+
n = len(names)
|
|
726
|
+
|
|
727
|
+
from sage.structure.category_object import normalize_names
|
|
728
|
+
names = tuple(normalize_names(n, names))
|
|
729
|
+
return super().__classcall__(cls, names, cbg_type=cbg_type)
|
|
730
|
+
|
|
731
|
+
def __init__(self, names, cbg_type=None):
|
|
732
|
+
r"""
|
|
733
|
+
Python constructor.
|
|
734
|
+
|
|
735
|
+
TESTS::
|
|
736
|
+
|
|
737
|
+
sage: # needs sage.rings.number_field
|
|
738
|
+
sage: C3 = CubicBraidGroup(3) # indirect doctest
|
|
739
|
+
sage: TestSuite(C3).run()
|
|
740
|
+
sage: C4 = CubicBraidGroup(4) # indirect doctest
|
|
741
|
+
sage: TestSuite(C4).run() # long time
|
|
742
|
+
sage: C6 = CubicBraidGroup(6) # indirect doctest
|
|
743
|
+
sage: TestSuite(C6).run() # long time
|
|
744
|
+
sage: S3 = AssionGroupS(3) # indirect doctest
|
|
745
|
+
sage: TestSuite(S3).run()
|
|
746
|
+
sage: S5 = AssionGroupS(5) # indirect doctest
|
|
747
|
+
sage: TestSuite(S5).run() # long time
|
|
748
|
+
sage: U3 = AssionGroupU(3) # indirect doctest
|
|
749
|
+
sage: TestSuite(U3).run()
|
|
750
|
+
sage: U4 = AssionGroupU(4) # indirect doctest
|
|
751
|
+
sage: TestSuite(U4).run() # long time
|
|
752
|
+
sage: U5 = AssionGroupU(5) # indirect doctest
|
|
753
|
+
sage: TestSuite(U5).run() # long time
|
|
754
|
+
"""
|
|
755
|
+
n = Integer(len(names))
|
|
756
|
+
if n < 1:
|
|
757
|
+
raise ValueError("the number of strands must be an integer larger than one")
|
|
758
|
+
if cbg_type is None:
|
|
759
|
+
cbg_type = CubicBraidGroup.type.Coxeter
|
|
760
|
+
if not isinstance(cbg_type, CubicBraidGroup.type):
|
|
761
|
+
raise TypeError("the cbg_type must be an instance of %s" % CubicBraidGroup.type)
|
|
762
|
+
|
|
763
|
+
free_group = FreeGroup(names)
|
|
764
|
+
self._cbg_type = cbg_type
|
|
765
|
+
self._nstrands = n + 1
|
|
766
|
+
self._ident = self._cbg_type.value + self._nstrands.str()
|
|
767
|
+
self._braid_group = BraidGroup(names)
|
|
768
|
+
|
|
769
|
+
# internal naming of elements for convenience
|
|
770
|
+
b = [free_group([i]) for i in range(1, n+1)]
|
|
771
|
+
t = [free_group([i, i+1]) ** 3 for i in range(1, n)]
|
|
772
|
+
ti = [free_group([-i, -i-1]) ** 3 for i in range(1, n)]
|
|
773
|
+
|
|
774
|
+
# first the braid relations
|
|
775
|
+
rels = list(self._braid_group.relations())
|
|
776
|
+
|
|
777
|
+
# than the cubic relations
|
|
778
|
+
rels.extend(b[i]**3 for i in range(n))
|
|
779
|
+
|
|
780
|
+
# than Assion's relation Satz 2.2 for cbg_type=CubicBraidGroup.type.AssionS
|
|
781
|
+
# and Satz 2.4 for cbg_type=CubicBraidGroup.type.AssionU
|
|
782
|
+
if n > 3:
|
|
783
|
+
for i in range(n - 3):
|
|
784
|
+
if cbg_type == CubicBraidGroup.type.AssionU:
|
|
785
|
+
rels.append((t[i]*t[i+2])**3)
|
|
786
|
+
elif cbg_type == CubicBraidGroup.type.AssionS:
|
|
787
|
+
rels.append(b[i+2]*b[i]*t[i+1]*b[i]*ti[i+1]*t[i+2]*t[i+1]*b[i]*ti[i+1]*ti[i+2])
|
|
788
|
+
|
|
789
|
+
if cbg_type != CubicBraidGroup.type.Coxeter:
|
|
790
|
+
cat = Groups().Finite()
|
|
791
|
+
elif self._nstrands <= 5:
|
|
792
|
+
cat = ShephardGroups()
|
|
793
|
+
else:
|
|
794
|
+
cat = Groups().Infinite()
|
|
795
|
+
FinitelyPresentedGroup.__init__(self, free_group, tuple(rels), category=cat)
|
|
796
|
+
self._free_group = free_group
|
|
797
|
+
|
|
798
|
+
# ------------------------------------------------------------------------------------------------
|
|
799
|
+
# the following global pointers to classical group realizations will be set in the private method
|
|
800
|
+
# _create_classical_realization
|
|
801
|
+
# ------------------------------------------------------------------------------------------------
|
|
802
|
+
self._classical_group = None # This is the classical Group returned by as_classical_group
|
|
803
|
+
self._classical_base_group = None # this only differs for special cases for Assion groups from the former
|
|
804
|
+
self._classical_invariant_form = None # invariant form of the classical base group
|
|
805
|
+
self._classical_embedding = None # if self._classical_group different from self._classical_base_group
|
|
806
|
+
self._centralizing_matrix = None # for Assion groups: element in classical base group commuting with self
|
|
807
|
+
self._centralizing_element = None # image under nat. map of the former one in the proj. classical group
|
|
808
|
+
|
|
809
|
+
def _repr_(self):
|
|
810
|
+
r"""
|
|
811
|
+
Return a string representation.
|
|
812
|
+
|
|
813
|
+
EXAMPLES::
|
|
814
|
+
|
|
815
|
+
sage: CubicBraidGroup(2)
|
|
816
|
+
Cubic Braid group on 2 strands
|
|
817
|
+
sage: AssionGroupU(2)
|
|
818
|
+
Assion group on 2 strands of type U
|
|
819
|
+
"""
|
|
820
|
+
if self._cbg_type == CubicBraidGroup.type.Coxeter:
|
|
821
|
+
return "Cubic Braid group on %s strands" % (self.strands())
|
|
822
|
+
else:
|
|
823
|
+
return "Assion group on %s strands of type %s" % (self.strands() ,self._cbg_type.value)
|
|
824
|
+
|
|
825
|
+
def index_set(self):
|
|
826
|
+
r"""
|
|
827
|
+
Return the index set of ``self``.
|
|
828
|
+
|
|
829
|
+
This is the set of integers `0,\dots,n-2` where `n` is
|
|
830
|
+
the number of strands.
|
|
831
|
+
|
|
832
|
+
This is only used when ``self`` is a finite reflection group.
|
|
833
|
+
|
|
834
|
+
EXAMPLES::
|
|
835
|
+
|
|
836
|
+
sage: CubicBraidGroup(3).index_set()
|
|
837
|
+
[0, 1]
|
|
838
|
+
"""
|
|
839
|
+
return list(range(self.strands() - 1))
|
|
840
|
+
|
|
841
|
+
def simple_reflections(self):
|
|
842
|
+
"""
|
|
843
|
+
Return the generators of ``self``.
|
|
844
|
+
|
|
845
|
+
This is only used when ``self`` is a finite reflection group.
|
|
846
|
+
|
|
847
|
+
EXAMPLES::
|
|
848
|
+
|
|
849
|
+
sage: CubicBraidGroup(3).simple_reflections()
|
|
850
|
+
(c0, c1)
|
|
851
|
+
"""
|
|
852
|
+
return self.generators()
|
|
853
|
+
|
|
854
|
+
def degrees(self):
|
|
855
|
+
"""
|
|
856
|
+
Return the degrees of ``self``.
|
|
857
|
+
|
|
858
|
+
This only makes sense when ``self`` is a finite reflection group.
|
|
859
|
+
|
|
860
|
+
EXAMPLES::
|
|
861
|
+
|
|
862
|
+
sage: CubicBraidGroup(4).degrees()
|
|
863
|
+
(6, 9, 12)
|
|
864
|
+
"""
|
|
865
|
+
if self._cbg_type != CubicBraidGroup.type.Coxeter:
|
|
866
|
+
raise TypeError('not a finite reflection group')
|
|
867
|
+
if self.strands() > 5:
|
|
868
|
+
raise TypeError('not a finite reflection group')
|
|
869
|
+
d_table = {1: (), 2: (3,), 3: (4, 6),
|
|
870
|
+
4: (6, 9, 12), 5: (12, 18, 24, 30)}
|
|
871
|
+
return tuple(Integer(deg) for deg in d_table[self.strands()])
|
|
872
|
+
|
|
873
|
+
def codegrees(self):
|
|
874
|
+
"""
|
|
875
|
+
Return the codegrees of ``self``.
|
|
876
|
+
|
|
877
|
+
This only makes sense when ``self`` is a finite reflection group.
|
|
878
|
+
|
|
879
|
+
EXAMPLES::
|
|
880
|
+
|
|
881
|
+
sage: CubicBraidGroup(5).codegrees()
|
|
882
|
+
(0, 6, 12, 18)
|
|
883
|
+
"""
|
|
884
|
+
if self._cbg_type != CubicBraidGroup.type.Coxeter:
|
|
885
|
+
raise TypeError('not a finite reflection group')
|
|
886
|
+
if self.strands() > 5:
|
|
887
|
+
raise TypeError('not a finite reflection group')
|
|
888
|
+
d_table = {1: (), 2: (0,), 3: (0, 2),
|
|
889
|
+
4: (0, 3, 6), 5: (0, 6, 12, 18)}
|
|
890
|
+
return tuple(Integer(deg) for deg in d_table[self.strands()])
|
|
891
|
+
|
|
892
|
+
# -------------------------------------------------------------------------------
|
|
893
|
+
# Methods for test_suite
|
|
894
|
+
# -------------------------------------------------------------------------------
|
|
895
|
+
|
|
896
|
+
def _internal_test_attached_group(self, attached_group, tester):
|
|
897
|
+
r"""
|
|
898
|
+
Test conversion maps from ``self`` to the given attached Group,
|
|
899
|
+
which must have been defined using the :meth:`as_classical_group`,
|
|
900
|
+
:meth:`as_matrix_group`, :meth:`as_permutation_group` or
|
|
901
|
+
:meth:`as_reflection_group`.
|
|
902
|
+
|
|
903
|
+
INPUT:
|
|
904
|
+
|
|
905
|
+
- ``attached_group`` -- attached group to be tested as specified above
|
|
906
|
+
|
|
907
|
+
EXAMPLES::
|
|
908
|
+
|
|
909
|
+
sage: CBG2 = CubicBraidGroup(2)
|
|
910
|
+
sage: tester = CBG2._tester()
|
|
911
|
+
sage: CBG2M = CBG2.as_matrix_group() # needs sage.rings.number_field
|
|
912
|
+
sage: CBG2._internal_test_attached_group(CBG2M, tester) # needs sage.rings.number_field
|
|
913
|
+
"""
|
|
914
|
+
elem = self.an_element()
|
|
915
|
+
att_grp_elem = attached_group(elem)
|
|
916
|
+
if self.is_finite() and self.strands() <= 7: # not realistic for larger number of strands
|
|
917
|
+
att_grp_elem_back = self(att_grp_elem)
|
|
918
|
+
tester.assertEqual(att_grp_elem_back, elem)
|
|
919
|
+
|
|
920
|
+
def _test_classical_group(self, **options):
|
|
921
|
+
r"""
|
|
922
|
+
Check the classical group properties.
|
|
923
|
+
|
|
924
|
+
The following is checked:
|
|
925
|
+
|
|
926
|
+
- Construction of classical group was faithful.
|
|
927
|
+
- Coercion maps to and from classical group exist and are
|
|
928
|
+
inverse to each other.
|
|
929
|
+
|
|
930
|
+
EXAMPLES::
|
|
931
|
+
|
|
932
|
+
sage: CBG2 = CubicBraidGroup(2)
|
|
933
|
+
sage: CBG2._test_classical_group() # needs sage.rings.number_field
|
|
934
|
+
"""
|
|
935
|
+
tester = self._tester(**options)
|
|
936
|
+
classic_grp = self.as_classical_group()
|
|
937
|
+
if self.is_finite():
|
|
938
|
+
self._internal_test_attached_group(classic_grp, tester)
|
|
939
|
+
|
|
940
|
+
def _test_permutation_group(self, **options):
|
|
941
|
+
r"""
|
|
942
|
+
Check the permutation group properties.
|
|
943
|
+
|
|
944
|
+
The following is checked:
|
|
945
|
+
|
|
946
|
+
- Construction of permutation group was faithful.
|
|
947
|
+
- Coercion maps to and from permutation group exist and are
|
|
948
|
+
inverse to each other.
|
|
949
|
+
|
|
950
|
+
EXAMPLES::
|
|
951
|
+
|
|
952
|
+
sage: CBG2 = CubicBraidGroup(2)
|
|
953
|
+
sage: CBG2._test_permutation_group() # needs sage.rings.number_field
|
|
954
|
+
"""
|
|
955
|
+
if self.is_finite():
|
|
956
|
+
tester = self._tester(**options)
|
|
957
|
+
permgrp = self.as_permutation_group()
|
|
958
|
+
self._internal_test_attached_group(permgrp, tester)
|
|
959
|
+
|
|
960
|
+
def _test_matrix_group(self, **options):
|
|
961
|
+
r"""
|
|
962
|
+
Check the matrix group properties.
|
|
963
|
+
|
|
964
|
+
The following is checked:
|
|
965
|
+
|
|
966
|
+
- Construction of matrix group was faithful.
|
|
967
|
+
- Coercion maps to and from matrix group exist and are
|
|
968
|
+
inverse to each other.
|
|
969
|
+
|
|
970
|
+
EXAMPLES::
|
|
971
|
+
|
|
972
|
+
sage: CBG2 = CubicBraidGroup(2)
|
|
973
|
+
sage: CBG2._test_matrix_group()
|
|
974
|
+
"""
|
|
975
|
+
tester = self._tester(**options)
|
|
976
|
+
|
|
977
|
+
MatDEF = self.as_matrix_group()
|
|
978
|
+
self._internal_test_attached_group(MatDEF, tester)
|
|
979
|
+
|
|
980
|
+
try:
|
|
981
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
982
|
+
except ImportError:
|
|
983
|
+
return
|
|
984
|
+
|
|
985
|
+
F3 = GF(3)
|
|
986
|
+
r63 = F3(2)
|
|
987
|
+
F4 = GF(4)
|
|
988
|
+
r64 = F4.gen()
|
|
989
|
+
|
|
990
|
+
if self._cbg_type != CubicBraidGroup.type.AssionU or self.strands() < 5: # not well defined else-wise
|
|
991
|
+
matrix_grpF3 = self.as_matrix_group(root_bur=r63)
|
|
992
|
+
self._internal_test_attached_group(matrix_grpF3, tester)
|
|
993
|
+
|
|
994
|
+
if self._cbg_type != CubicBraidGroup.type.AssionS or self.strands() < 5: # not well defined else-wise
|
|
995
|
+
matrix_grpF4 = self.as_matrix_group(root_bur=r64)
|
|
996
|
+
self._internal_test_attached_group(matrix_grpF4, tester)
|
|
997
|
+
|
|
998
|
+
if self.strands() < 5 or self._cbg_type == CubicBraidGroup.type.Coxeter:
|
|
999
|
+
matrix_grpF5 = self.as_matrix_group(characteristic=5)
|
|
1000
|
+
self._internal_test_attached_group(matrix_grpF5, tester)
|
|
1001
|
+
|
|
1002
|
+
matrix_grpF7 = self.as_matrix_group(domain=GF(7))
|
|
1003
|
+
self._internal_test_attached_group(matrix_grpF7, tester)
|
|
1004
|
+
return
|
|
1005
|
+
|
|
1006
|
+
def _test_reflection_group(self, **options):
|
|
1007
|
+
r"""
|
|
1008
|
+
Check the reflection group properties.
|
|
1009
|
+
|
|
1010
|
+
The following is checked:
|
|
1011
|
+
|
|
1012
|
+
- Construction of reflection group was faithful.
|
|
1013
|
+
- Coercion maps to and from reflection group exist and are
|
|
1014
|
+
inverse to each other.
|
|
1015
|
+
|
|
1016
|
+
EXAMPLES::
|
|
1017
|
+
|
|
1018
|
+
sage: CBG2 = CubicBraidGroup(2)
|
|
1019
|
+
sage: CBG2._test_reflection_group()
|
|
1020
|
+
"""
|
|
1021
|
+
if self._cbg_type == CubicBraidGroup.type.Coxeter and self.is_finite() and self.strands() > 2:
|
|
1022
|
+
from sage.combinat.root_system.reflection_group_real import is_chevie_available
|
|
1023
|
+
if is_chevie_available():
|
|
1024
|
+
tester = self._tester(**options)
|
|
1025
|
+
reflgrp = self.as_reflection_group()
|
|
1026
|
+
self._internal_test_attached_group(reflgrp, tester)
|
|
1027
|
+
|
|
1028
|
+
# -------------------------------------------------------------------------------
|
|
1029
|
+
# -------------------------------------------------------------------------------
|
|
1030
|
+
# local utility-methods
|
|
1031
|
+
# -------------------------------------------------------------------------------
|
|
1032
|
+
# -------------------------------------------------------------------------------
|
|
1033
|
+
def _create_classical_realization(self, just_embedded=False):
|
|
1034
|
+
r"""
|
|
1035
|
+
Internal method to create the classical groups attached to ``self``.
|
|
1036
|
+
|
|
1037
|
+
This methods sets the following attributes of ``self``:
|
|
1038
|
+
|
|
1039
|
+
- self._classical_group This is the classical group returned by as_classical_group method.
|
|
1040
|
+
- self._classical_base_group this only differs in special cases for Assion groups from the former.
|
|
1041
|
+
- self._classical_invariant_form invariant form of the classical base group.
|
|
1042
|
+
- self._centralizing_matrix for Assion groups: element in classical base group commuting with ``self``.
|
|
1043
|
+
- self._centralizing_element image under natural map of the former one in the projective classical group.
|
|
1044
|
+
- self._classical_embedding as subgroup of classical base group (if different from classical group).
|
|
1045
|
+
|
|
1046
|
+
EXAMPLES::
|
|
1047
|
+
|
|
1048
|
+
sage: AU2 = AssionGroupU(2)
|
|
1049
|
+
sage: AU2._classical_group is None
|
|
1050
|
+
True
|
|
1051
|
+
sage: AU2._classical_embedding is None
|
|
1052
|
+
True
|
|
1053
|
+
sage: AU2._classical_invariant_form is None
|
|
1054
|
+
True
|
|
1055
|
+
sage: AU2._create_classical_realization()
|
|
1056
|
+
sage: AU2._classical_group
|
|
1057
|
+
General Unitary Group of degree 1 over Finite Field in a of size 2^2
|
|
1058
|
+
sage: AU2._classical_embedding is AU2._classical_group
|
|
1059
|
+
True
|
|
1060
|
+
sage: AU2._classical_invariant_form
|
|
1061
|
+
[1]
|
|
1062
|
+
"""
|
|
1063
|
+
|
|
1064
|
+
# -------------------------------------------------------------------------------
|
|
1065
|
+
# Set up data of the classical Assion group (generic part)
|
|
1066
|
+
# -------------------------------------------------------------------------------
|
|
1067
|
+
|
|
1068
|
+
def set_classical_realization(self, base_group, proj_group, centralizing_matrix, transvec_matrices):
|
|
1069
|
+
r"""
|
|
1070
|
+
Internal method to create classical group for Assion groups.
|
|
1071
|
+
|
|
1072
|
+
This is a local function of :meth:`_create_classical_realization`.
|
|
1073
|
+
|
|
1074
|
+
It handles the common part of symplectic and unitary version and
|
|
1075
|
+
creates conversion maps.
|
|
1076
|
+
|
|
1077
|
+
INPUT:
|
|
1078
|
+
|
|
1079
|
+
- ``base_group`` -- the symplectic or unitary groups Sp(m,3) resp. GU(m,2)
|
|
1080
|
+
- ``proj_group`` -- the corresponding projective group of base_group
|
|
1081
|
+
- ``centralizing_matrix`` -- the centralizing matrix according to Assion
|
|
1082
|
+
- ``transvec_matrices`` -- list of transvection matrices according to Assion
|
|
1083
|
+
|
|
1084
|
+
OUTPUT: no output, but the function sets the attributes of ``self`` described above
|
|
1085
|
+
"""
|
|
1086
|
+
centralizing_element = None
|
|
1087
|
+
|
|
1088
|
+
# ------------------------------------------------------------------------------
|
|
1089
|
+
# Setting the List of Braid Images
|
|
1090
|
+
# ------------------------------------------------------------------------------
|
|
1091
|
+
im_gens = [base_group(m) for m in transvec_matrices]
|
|
1092
|
+
|
|
1093
|
+
# ------------------------------------------------------------------------------
|
|
1094
|
+
# By the work of Assion no check on the group homomorphism is needed, at all.
|
|
1095
|
+
# But to take care of software bugs they are performed in cases where they are
|
|
1096
|
+
# not really expansive.
|
|
1097
|
+
# ------------------------------------------------------------------------------
|
|
1098
|
+
check = False
|
|
1099
|
+
if self.strands() < 7:
|
|
1100
|
+
check = True
|
|
1101
|
+
|
|
1102
|
+
# ------------------------------------------------------------------------------
|
|
1103
|
+
# Do the projective group realization if needed
|
|
1104
|
+
# ------------------------------------------------------------------------------
|
|
1105
|
+
embedding = self._classical_embedding
|
|
1106
|
+
classical_group = None
|
|
1107
|
+
if proj_group is None:
|
|
1108
|
+
classical_group = base_group
|
|
1109
|
+
hom_to_classic = self.hom(im_gens, check=check)
|
|
1110
|
+
classical_group.register_conversion(hom_to_classic)
|
|
1111
|
+
embedding = classical_group
|
|
1112
|
+
else:
|
|
1113
|
+
if embedding is None:
|
|
1114
|
+
im_gens.pop()
|
|
1115
|
+
embedding = base_group.subgroup(im_gens, check=check)
|
|
1116
|
+
embedding.register_conversion(self.hom(embedding.gens(), check=check))
|
|
1117
|
+
hom_to_base = self.hom(im_gens, check=check, codomain=base_group)
|
|
1118
|
+
base_group.register_conversion(hom_to_base)
|
|
1119
|
+
if not just_embedded:
|
|
1120
|
+
transvec_matrices.pop()
|
|
1121
|
+
nat_hom = base_group.hom(proj_group.gens(), check=check)
|
|
1122
|
+
centralizing_element = nat_hom(centralizing_matrix)
|
|
1123
|
+
classical_group_gens = [nat_hom(m) for m in transvec_matrices]
|
|
1124
|
+
classical_group = proj_group.subgroup(classical_group_gens, canonicalize=False)
|
|
1125
|
+
hom_to_classic = self.hom(classical_group.gens(), check=check)
|
|
1126
|
+
classical_group.register_conversion(hom_to_classic)
|
|
1127
|
+
|
|
1128
|
+
# ------------------------------------------------------------------------------
|
|
1129
|
+
# register constructed items
|
|
1130
|
+
# ------------------------------------------------------------------------------
|
|
1131
|
+
self._classical_group = classical_group
|
|
1132
|
+
self._classical_base_group = base_group
|
|
1133
|
+
self._classical_invariant_form = base_group.invariant_form()
|
|
1134
|
+
self._centralizing_matrix = centralizing_matrix
|
|
1135
|
+
self._centralizing_element = centralizing_element
|
|
1136
|
+
self._classical_embedding = embedding
|
|
1137
|
+
|
|
1138
|
+
# -------------------------------------------------------------------------------
|
|
1139
|
+
# local methods to set up the classical group (specific part)
|
|
1140
|
+
# -------------------------------------------------------------------------------
|
|
1141
|
+
# Case for symplectic groups
|
|
1142
|
+
# -------------------------------------------------------------------------------
|
|
1143
|
+
|
|
1144
|
+
def create_sympl_realization(self, m):
|
|
1145
|
+
r"""
|
|
1146
|
+
Internal method to create classical group for symplectic
|
|
1147
|
+
Assion groups (`cbg_type == CubicBraidGroup.type.AssionS`).
|
|
1148
|
+
|
|
1149
|
+
INPUT:
|
|
1150
|
+
|
|
1151
|
+
- ``m`` -- integer; the dimension of the classical groups
|
|
1152
|
+
vector-space of operation
|
|
1153
|
+
|
|
1154
|
+
The function calculates the centralizing matrix and the
|
|
1155
|
+
transvections as given by Assion and then uses
|
|
1156
|
+
``set_classical_realization`` to complete the construction.
|
|
1157
|
+
"""
|
|
1158
|
+
# -----------------------------------------------------------
|
|
1159
|
+
# getting the invariant bilinear form of the group
|
|
1160
|
+
# and setting constants.
|
|
1161
|
+
# -----------------------------------------------------------
|
|
1162
|
+
n = self.strands()
|
|
1163
|
+
|
|
1164
|
+
from sage.groups.matrix_gps.symplectic import Sp
|
|
1165
|
+
base_group = Sp(m, 3)
|
|
1166
|
+
proj_group = None
|
|
1167
|
+
if m == n:
|
|
1168
|
+
from sage.groups.perm_gps.permgroup_named import PSp
|
|
1169
|
+
proj_group = PSp(m, 3)
|
|
1170
|
+
|
|
1171
|
+
bform = base_group.invariant_form()
|
|
1172
|
+
bas = bform.column_space().basis()
|
|
1173
|
+
|
|
1174
|
+
mhalf = m // 2
|
|
1175
|
+
|
|
1176
|
+
# -----------------------------------------------------------
|
|
1177
|
+
# computing a hyperbolic decomposition basis with respect
|
|
1178
|
+
# to the invariant bilinear form.
|
|
1179
|
+
# -----------------------------------------------------------
|
|
1180
|
+
xbas = [bas[mhalf - i - 1] for i in range(mhalf)]
|
|
1181
|
+
ybas = [bas[mhalf + i] for i in range(mhalf)]
|
|
1182
|
+
|
|
1183
|
+
# -----------------------------------------------------------
|
|
1184
|
+
# computing the List of transvection vectors according to
|
|
1185
|
+
# the Assion paper, page 292.
|
|
1186
|
+
# -----------------------------------------------------------
|
|
1187
|
+
transvections = [xbas[0]] # t_1 = x_1
|
|
1188
|
+
for i in range(mhalf-1):
|
|
1189
|
+
transvections.append(ybas[i]) # t_{2i} = y_i
|
|
1190
|
+
transvections.append(xbas[i] + xbas[i+1]) # t_{2i+1} = x_j + x_(j+1)
|
|
1191
|
+
transvections.append(ybas[mhalf-1]) # t_n = y_m
|
|
1192
|
+
|
|
1193
|
+
# -----------------------------------------------------------
|
|
1194
|
+
# Conversion-Map from transvection vector to transvection
|
|
1195
|
+
# matrix.
|
|
1196
|
+
# -----------------------------------------------------------
|
|
1197
|
+
from sage.matrix.constructor import matrix
|
|
1198
|
+
|
|
1199
|
+
def transvec2mat(v, bas=bas, bform=bform, fact=1):
|
|
1200
|
+
t = [x + fact*(x * bform * v) * v for x in bas]
|
|
1201
|
+
return matrix(bform.base_ring(), t)
|
|
1202
|
+
|
|
1203
|
+
# ------------------------------------------------------------------------------
|
|
1204
|
+
# setting the centralizing matrix for the case of projective group realization
|
|
1205
|
+
# ------------------------------------------------------------------------------
|
|
1206
|
+
centralizing_vector = xbas[mhalf-1]
|
|
1207
|
+
centralizing_matrix = base_group(transvec2mat(centralizing_vector, fact=1))
|
|
1208
|
+
transvec_matrices = [transvec2mat(v) for v in transvections]
|
|
1209
|
+
|
|
1210
|
+
set_classical_realization(self, base_group, proj_group, centralizing_matrix, transvec_matrices)
|
|
1211
|
+
|
|
1212
|
+
# -------------------------------------------------------------------------------
|
|
1213
|
+
# Case for unitary groups
|
|
1214
|
+
# -------------------------------------------------------------------------------
|
|
1215
|
+
|
|
1216
|
+
def create_unitary_realization(self, m):
|
|
1217
|
+
"""
|
|
1218
|
+
Internal method to create classical group for
|
|
1219
|
+
unitary Assion groups (`cbg_type == CubicBraidGroup.type.AssionU`).
|
|
1220
|
+
|
|
1221
|
+
INPUT:
|
|
1222
|
+
|
|
1223
|
+
- ``m`` -- integer; the dimension of the classical groups
|
|
1224
|
+
vector-space of operation
|
|
1225
|
+
|
|
1226
|
+
The function calculates the centralizing_matrix and the
|
|
1227
|
+
transvections as given by Assion and then uses
|
|
1228
|
+
``set_classical_realization`` to complete the construction.
|
|
1229
|
+
"""
|
|
1230
|
+
# ---------------------------------------------------------------------
|
|
1231
|
+
# getting the invariant bilinear form of the group
|
|
1232
|
+
# and setting constants
|
|
1233
|
+
# ---------------------------------------------------------------------
|
|
1234
|
+
n = self.strands()
|
|
1235
|
+
|
|
1236
|
+
from sage.groups.matrix_gps.unitary import GU
|
|
1237
|
+
base_group = GU(m, 2)
|
|
1238
|
+
proj_group = None
|
|
1239
|
+
if m == n:
|
|
1240
|
+
from sage.groups.perm_gps.permgroup_named import PGU
|
|
1241
|
+
proj_group = PGU(m, 2)
|
|
1242
|
+
|
|
1243
|
+
bform = base_group.invariant_form()
|
|
1244
|
+
bas = bform.column_space().basis()
|
|
1245
|
+
F = bform.base_ring()
|
|
1246
|
+
a = F.gen()
|
|
1247
|
+
|
|
1248
|
+
mthird = m // 3
|
|
1249
|
+
|
|
1250
|
+
# -----------------------------------------------------------
|
|
1251
|
+
# computing a orthonormal basis with respect
|
|
1252
|
+
# to the invariant bilinear form.
|
|
1253
|
+
# -----------------------------------------------------------
|
|
1254
|
+
xbas = []
|
|
1255
|
+
for i in range(m):
|
|
1256
|
+
if 2*i == m-1:
|
|
1257
|
+
xbas.append(bas[i])
|
|
1258
|
+
else:
|
|
1259
|
+
xbas.append(a*bas[i] + a.frobenius()*bas[m-1 - i])
|
|
1260
|
+
|
|
1261
|
+
# -----------------------------------------------------------
|
|
1262
|
+
# computing the List of transvection vectors according to
|
|
1263
|
+
# Assion paper, page 293.
|
|
1264
|
+
# -----------------------------------------------------------
|
|
1265
|
+
transvections = [xbas[0]] # t_1 = x_1
|
|
1266
|
+
if m > 1:
|
|
1267
|
+
transvections.append(xbas[0]+xbas[1]+xbas[2]) # t_2 = x_1 + x_2 + x_3
|
|
1268
|
+
for j in range(mthird):
|
|
1269
|
+
pos = 3*(j+1)-1
|
|
1270
|
+
transvections.append(xbas[pos-1]) # t_{3i} = x_{3i-1}
|
|
1271
|
+
if pos + 1 < m:
|
|
1272
|
+
transvections.append(xbas[pos-1]+xbas[pos]+xbas[pos+1]) # t_{3i+1} = x_{3i-1} + x_{3i} + x_{3i+1}
|
|
1273
|
+
if pos + 3 < m:
|
|
1274
|
+
transvections.append(xbas[pos+1]+xbas[pos+2]+xbas[pos+3]) # t_{3i+2} = x_{3i+1} + x_{3i+2} + x_{3i+3}
|
|
1275
|
+
|
|
1276
|
+
# -----------------------------------------------------------
|
|
1277
|
+
# Conversion-Map from transvection vector to transvection
|
|
1278
|
+
# matrix.
|
|
1279
|
+
# -----------------------------------------------------------
|
|
1280
|
+
from sage.matrix.constructor import matrix
|
|
1281
|
+
|
|
1282
|
+
def transvec2mat(v, bas=bas, bform=bform, fact=a):
|
|
1283
|
+
# note x does not change under conjugation, since it belongs to standard basis
|
|
1284
|
+
t = [x + fact * (x * bform * v.conjugate()) * v for x in bas]
|
|
1285
|
+
return matrix(F, t)
|
|
1286
|
+
|
|
1287
|
+
# ------------------------------------------------------------------------------
|
|
1288
|
+
# setting the centralizing matrix for the case of projective group realization.
|
|
1289
|
+
# ------------------------------------------------------------------------------
|
|
1290
|
+
centralizing_vector = xbas[m-2]+xbas[m-1]
|
|
1291
|
+
centralizing_matrix = base_group(transvec2mat(centralizing_vector, fact=1))
|
|
1292
|
+
transvec_matrices = [transvec2mat(v) for v in transvections]
|
|
1293
|
+
|
|
1294
|
+
set_classical_realization(self, base_group, proj_group, centralizing_matrix, transvec_matrices)
|
|
1295
|
+
|
|
1296
|
+
# ----------------------------------------------------------------
|
|
1297
|
+
# local functions declaration section finishes here
|
|
1298
|
+
# ----------------------------------------------------------------
|
|
1299
|
+
|
|
1300
|
+
# ----------------------------------------------------------------
|
|
1301
|
+
# initialization of constants
|
|
1302
|
+
# ----------------------------------------------------------------
|
|
1303
|
+
|
|
1304
|
+
n = self.strands()
|
|
1305
|
+
|
|
1306
|
+
# -------------------------------------------------------------------------------
|
|
1307
|
+
# Setting the Classical group
|
|
1308
|
+
# -------------------------------------------------------------------------------
|
|
1309
|
+
if self._cbg_type == CubicBraidGroup.type.AssionS:
|
|
1310
|
+
dim_sympl_group = n-1 # S(n-1) = Sp(n-1, 3)
|
|
1311
|
+
if n % 2 == 0:
|
|
1312
|
+
dim_sympl_group = n # S(n-1) = subgroup of PSp(n, 3)
|
|
1313
|
+
create_sympl_realization(self, dim_sympl_group)
|
|
1314
|
+
elif self._cbg_type == CubicBraidGroup.type.AssionU:
|
|
1315
|
+
dim_unitary_group = n-1 # U(n-1) = GU(n-1, 2)
|
|
1316
|
+
if n % 3 == 0:
|
|
1317
|
+
dim_unitary_group = n # U(n-1) = subgroup PGU(n, 3)
|
|
1318
|
+
create_unitary_realization(self, dim_unitary_group)
|
|
1319
|
+
else:
|
|
1320
|
+
# -----------------------------------------------------------------------------------------------
|
|
1321
|
+
# connection between Coxeter realization and unitary Burau representation according to Squier:
|
|
1322
|
+
# -----------------------------------------------------------------------------------------------
|
|
1323
|
+
# Notation of Coxeter: p = 3, \theta =\pi/3 = primitive 6th root of unity
|
|
1324
|
+
# i\theta = \pi/3+\pi/2 = 5\pi/6 = 5th power of primitive 12th root of unity
|
|
1325
|
+
# i\theta = z12^5 = - ~z12 where z12 = UCF.gen(12)
|
|
1326
|
+
# Let f be the unitary Form of Coxeter and J(s) the one of Squier. Then we have
|
|
1327
|
+
# J(z12) = 2 f
|
|
1328
|
+
# Let `buc` be the unitary Burau Matrix of Coxeter for the first braid generator and `bus`
|
|
1329
|
+
# the corresponding one according to Squier. Then we have:
|
|
1330
|
+
# buc_[i,i-1] = buc_[i,i+1]= - i\theta, buc_[i,i] = 1 + 2*cos(\pi/6)*i\theta
|
|
1331
|
+
# bus_[i,i-1] = bus_[i,i+1]= s, bus_[i,i] = -s^2
|
|
1332
|
+
# now 1 + 2*cos(\pi/6)*i\theta = 1 + sqrt(3)*(-sqrt(3)/2 + I/2) = 1- 3/2 + sqrt(3)I/2 = z12^4 = - ~z12^2
|
|
1333
|
+
# finally: Coxeter's Realization is the unitary Burau representation of Squier for s = ~z12
|
|
1334
|
+
# -----------------------------------------------------------------------------------------------
|
|
1335
|
+
from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
|
|
1336
|
+
|
|
1337
|
+
UCF = UniversalCyclotomicField()
|
|
1338
|
+
z12 = UCF.gen(12)
|
|
1339
|
+
classical_group = self.as_matrix_group(root_bur=~z12, domain=UCF, reduced='unitary')
|
|
1340
|
+
self._classical_group = classical_group
|
|
1341
|
+
self._classical_base_group = classical_group
|
|
1342
|
+
self._classical_embedding = classical_group
|
|
1343
|
+
if self._classical_invariant_form is None:
|
|
1344
|
+
self._classical_invariant_form = classical_group.ambient().invariant_form()
|
|
1345
|
+
|
|
1346
|
+
def _element_constructor_(self, x, **kwds):
|
|
1347
|
+
r"""
|
|
1348
|
+
Return an element of ``self``.
|
|
1349
|
+
|
|
1350
|
+
Extensions to the element constructor of :class:`FinitelyPresentedGroup`:
|
|
1351
|
+
new functionalities are:
|
|
1352
|
+
|
|
1353
|
+
- constructing element from an element of the attached classical group
|
|
1354
|
+
(embedded and not embedded)
|
|
1355
|
+
- constructing element from an element of the attached permutation group
|
|
1356
|
+
- constructing element from an element of the attached reflection group
|
|
1357
|
+
|
|
1358
|
+
INPUT:
|
|
1359
|
+
|
|
1360
|
+
- ``x`` -- can be one of the following:
|
|
1361
|
+
|
|
1362
|
+
* an instance of the element class of ``self`` (but possible
|
|
1363
|
+
to a different parent)
|
|
1364
|
+
* an instance of the element class of the braid group
|
|
1365
|
+
* a tuple representing a braid in Tietze form
|
|
1366
|
+
* an instance of an element class of a parent ``P`` such that there
|
|
1367
|
+
is a map from ``self`` to ``P`` having :meth:`lift`; for example,
|
|
1368
|
+
an element of an alternative realization of ``self``, such as
|
|
1369
|
+
the classical realization
|
|
1370
|
+
* any other object which works for the element constructor
|
|
1371
|
+
of :class:`FinitelyPresentedGroup`
|
|
1372
|
+
|
|
1373
|
+
EXAMPLES::
|
|
1374
|
+
|
|
1375
|
+
sage: S3 = AssionGroupS(3)
|
|
1376
|
+
sage: S3Cl = S3.as_classical_group()
|
|
1377
|
+
sage: g = mul(S3Cl.gens())
|
|
1378
|
+
sage: S3(g) # indirect doctest
|
|
1379
|
+
s0*s1*s0^-1
|
|
1380
|
+
"""
|
|
1381
|
+
if hasattr(x, 'parent'):
|
|
1382
|
+
parent = x.parent()
|
|
1383
|
+
map_to = parent.convert_map_from(self)
|
|
1384
|
+
if map_to is not None:
|
|
1385
|
+
if hasattr(map_to, 'lift'):
|
|
1386
|
+
return map_to.lift(x)
|
|
1387
|
+
return super()._element_constructor_(x)
|
|
1388
|
+
|
|
1389
|
+
#######################################################################################################################
|
|
1390
|
+
# ----------------------------------------------------------------------------------
|
|
1391
|
+
# public methods
|
|
1392
|
+
# ----------------------------------------------------------------------------------
|
|
1393
|
+
#######################################################################################################################
|
|
1394
|
+
|
|
1395
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
|
1396
|
+
# strands
|
|
1397
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
|
1398
|
+
def strands(self):
|
|
1399
|
+
r"""
|
|
1400
|
+
Return the number of strands of the braid group whose image is ``self``.
|
|
1401
|
+
|
|
1402
|
+
OUTPUT: :class:`Integer`
|
|
1403
|
+
|
|
1404
|
+
EXAMPLES::
|
|
1405
|
+
|
|
1406
|
+
sage: C4 = CubicBraidGroup(4)
|
|
1407
|
+
sage: C4.strands()
|
|
1408
|
+
4
|
|
1409
|
+
"""
|
|
1410
|
+
return self._nstrands
|
|
1411
|
+
|
|
1412
|
+
# ----------------------------------------------------------------------------------
|
|
1413
|
+
# braid_group
|
|
1414
|
+
# ----------------------------------------------------------------------------------
|
|
1415
|
+
def braid_group(self):
|
|
1416
|
+
r"""
|
|
1417
|
+
Return a :class:`BraidGroup` with identical generators, such that
|
|
1418
|
+
there exists an epimorphism to ``self``.
|
|
1419
|
+
|
|
1420
|
+
OUTPUT: a :class:`BraidGroup` having conversion maps to and from
|
|
1421
|
+
``self`` (which is just a section in the latter case)
|
|
1422
|
+
|
|
1423
|
+
EXAMPLES::
|
|
1424
|
+
|
|
1425
|
+
sage: U5 = AssionGroupU(5); U5
|
|
1426
|
+
Assion group on 5 strands of type U
|
|
1427
|
+
sage: B5 = U5.braid_group(); B5
|
|
1428
|
+
Braid group on 5 strands
|
|
1429
|
+
sage: b = B5([4,3,2,-4,1])
|
|
1430
|
+
sage: u = U5([4,3,2,-4,1])
|
|
1431
|
+
sage: u == b
|
|
1432
|
+
False
|
|
1433
|
+
sage: b.burau_matrix()
|
|
1434
|
+
[ 1 - t t 0 0 0]
|
|
1435
|
+
[ 1 - t 0 t 0 0]
|
|
1436
|
+
[ 1 - t 0 0 0 t]
|
|
1437
|
+
[ 1 - t 0 0 1 -1 + t]
|
|
1438
|
+
[ 1 0 0 0 0]
|
|
1439
|
+
sage: u.burau_matrix()
|
|
1440
|
+
[t + 1 t 0 0 0]
|
|
1441
|
+
[t + 1 0 t 0 0]
|
|
1442
|
+
[t + 1 0 0 0 t]
|
|
1443
|
+
[t + 1 0 0 1 t + 1]
|
|
1444
|
+
[ 1 0 0 0 0]
|
|
1445
|
+
sage: bU = U5(b)
|
|
1446
|
+
sage: uB = B5(u)
|
|
1447
|
+
sage: bU == u
|
|
1448
|
+
True
|
|
1449
|
+
sage: uB == b
|
|
1450
|
+
True
|
|
1451
|
+
"""
|
|
1452
|
+
return self._braid_group
|
|
1453
|
+
|
|
1454
|
+
# ----------------------------------------------------------------------------------
|
|
1455
|
+
# as_matrix_group
|
|
1456
|
+
# ----------------------------------------------------------------------------------
|
|
1457
|
+
@cached_method
|
|
1458
|
+
def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var='t', reduced=False):
|
|
1459
|
+
r"""
|
|
1460
|
+
Create an epimorphic image of ``self`` as a matrix group by use of
|
|
1461
|
+
the burau representation.
|
|
1462
|
+
|
|
1463
|
+
INPUT:
|
|
1464
|
+
|
|
1465
|
+
- ``root_bur`` -- (default: root of unity over `\QQ`) six (resp. twelfth)
|
|
1466
|
+
root of unity in some field
|
|
1467
|
+
- ``domain`` -- (default: cyclotomic field of order 3 and degree 2, resp.
|
|
1468
|
+
the domain of ``root_bur`` if given) base ring for the Burau matrix
|
|
1469
|
+
- ``characteristic`` -- integer (optional); the characteristic of the
|
|
1470
|
+
domain; if none of the keywords ``root_bur``, ``domain`` and
|
|
1471
|
+
``characteristic`` are given, the default characteristic is 3
|
|
1472
|
+
(resp. 2) if ``self`` is of ``cbg_type``
|
|
1473
|
+
``CubicBraidGroup.type.AssionS`` (resp. ``CubicBraidGroup.type.AssionU``)
|
|
1474
|
+
- ``var`` -- string used for the indeterminate name in case ``root_bur``
|
|
1475
|
+
must be constructed in a splitting field
|
|
1476
|
+
- ``reduced`` -- boolean (default: ``False``); for more information
|
|
1477
|
+
see the documentation of :meth:`Braid.burau_matrix`
|
|
1478
|
+
|
|
1479
|
+
EXAMPLES::
|
|
1480
|
+
|
|
1481
|
+
sage: # needs sage.rings.finite_rings
|
|
1482
|
+
sage: C5 = CubicBraidGroup(5)
|
|
1483
|
+
sage: C5Mch5 = C5.as_matrix_group(characteristic=5); C5Mch5
|
|
1484
|
+
Matrix group over Finite Field in t of size 5^2 with 4 generators (
|
|
1485
|
+
[2*t + 2 3*t + 4 0 0 0]
|
|
1486
|
+
[ 1 0 0 0 0]
|
|
1487
|
+
[ 0 0 1 0 0]
|
|
1488
|
+
[ 0 0 0 1 0]
|
|
1489
|
+
[ 0 0 0 0 1],
|
|
1490
|
+
<BLANKLINE>
|
|
1491
|
+
[ 1 0 0 0 0]
|
|
1492
|
+
[ 0 2*t + 2 3*t + 4 0 0]
|
|
1493
|
+
[ 0 1 0 0 0]
|
|
1494
|
+
[ 0 0 0 1 0]
|
|
1495
|
+
[ 0 0 0 0 1],
|
|
1496
|
+
<BLANKLINE>
|
|
1497
|
+
[ 1 0 0 0 0]
|
|
1498
|
+
[ 0 1 0 0 0]
|
|
1499
|
+
[ 0 0 2*t + 2 3*t + 4 0]
|
|
1500
|
+
[ 0 0 1 0 0]
|
|
1501
|
+
[ 0 0 0 0 1],
|
|
1502
|
+
<BLANKLINE>
|
|
1503
|
+
[ 1 0 0 0 0]
|
|
1504
|
+
[ 0 1 0 0 0]
|
|
1505
|
+
[ 0 0 1 0 0]
|
|
1506
|
+
[ 0 0 0 2*t + 2 3*t + 4]
|
|
1507
|
+
[ 0 0 0 1 0]
|
|
1508
|
+
)
|
|
1509
|
+
sage: c = C5([3,4,-2,-3,1]); c
|
|
1510
|
+
c2*c3*c1^-1*c2^-1*c0
|
|
1511
|
+
sage: m = C5Mch5(c); m
|
|
1512
|
+
[2*t + 2 3*t + 4 0 0 0]
|
|
1513
|
+
[ 0 0 0 1 0]
|
|
1514
|
+
[2*t + 1 0 2*t + 2 3*t 3*t + 3]
|
|
1515
|
+
[2*t + 2 0 0 3*t + 4 0]
|
|
1516
|
+
[ 0 0 2*t + 2 3*t + 4 0]
|
|
1517
|
+
sage: m_back = C5(m)
|
|
1518
|
+
sage: m_back == c
|
|
1519
|
+
True
|
|
1520
|
+
sage: U5 = AssionGroupU(5); U5
|
|
1521
|
+
Assion group on 5 strands of type U
|
|
1522
|
+
sage: U5Mch3 = U5.as_matrix_group(characteristic=3)
|
|
1523
|
+
Traceback (most recent call last):
|
|
1524
|
+
...
|
|
1525
|
+
ValueError: Burau representation does not factor through the relations
|
|
1526
|
+
"""
|
|
1527
|
+
# ------------------------------------------------------------------
|
|
1528
|
+
# define matrix group by generators using the Burau representation
|
|
1529
|
+
# ------------------------------------------------------------------
|
|
1530
|
+
unitary = False
|
|
1531
|
+
if isinstance(reduced, str):
|
|
1532
|
+
if reduced == 'unitary':
|
|
1533
|
+
unitary = True
|
|
1534
|
+
gen_list = []
|
|
1535
|
+
for braid_gen in self.gens():
|
|
1536
|
+
bur_mat = braid_gen.burau_matrix(root_bur=root_bur, domain=domain,
|
|
1537
|
+
characteristic=characteristic,
|
|
1538
|
+
var=var, reduced=reduced)
|
|
1539
|
+
if unitary:
|
|
1540
|
+
bur_mat, bur_mat_ad, herm_form = bur_mat
|
|
1541
|
+
|
|
1542
|
+
if domain is None:
|
|
1543
|
+
domain = bur_mat.base_ring()
|
|
1544
|
+
|
|
1545
|
+
gen_list.append(bur_mat)
|
|
1546
|
+
|
|
1547
|
+
if unitary and herm_form.is_singular():
|
|
1548
|
+
unitary = False # since a degenerated hermitian form doesn't define a unitary group
|
|
1549
|
+
if self._classical_invariant_form is None:
|
|
1550
|
+
self._classical_invariant_form = herm_form
|
|
1551
|
+
|
|
1552
|
+
if unitary:
|
|
1553
|
+
from sage.rings.finite_rings.finite_field_base import FiniteField
|
|
1554
|
+
from sage.groups.matrix_gps.unitary import GU
|
|
1555
|
+
_, d = herm_form.dimensions()
|
|
1556
|
+
if isinstance(domain, FiniteField):
|
|
1557
|
+
base_group = GU(d, domain, var=domain.gen(), invariant_form=herm_form)
|
|
1558
|
+
else:
|
|
1559
|
+
base_group = GU(d, domain, invariant_form=herm_form)
|
|
1560
|
+
|
|
1561
|
+
matrix_group = base_group.subgroup(gen_list)
|
|
1562
|
+
else:
|
|
1563
|
+
from sage.groups.matrix_gps.finitely_generated import MatrixGroup
|
|
1564
|
+
matrix_group = MatrixGroup(gen_list, category=self.category())
|
|
1565
|
+
|
|
1566
|
+
# --------------------------------------------------------------------
|
|
1567
|
+
# check if there is a well defined group homomorphism to matrix_group
|
|
1568
|
+
# Register map from ``self`` to matrix_group.
|
|
1569
|
+
# Since GAP' check is very expansive (on time and memory), the check is performed
|
|
1570
|
+
# here.
|
|
1571
|
+
# -------------------------------------------------------------------------------
|
|
1572
|
+
hom_to_mat = self.hom(matrix_group.gens(), check=False)
|
|
1573
|
+
if not all(hom_to_mat(rel).is_one() for rel in self.relations()):
|
|
1574
|
+
raise ValueError("Burau representation does not factor through the relations")
|
|
1575
|
+
matrix_group.register_conversion(hom_to_mat)
|
|
1576
|
+
return matrix_group
|
|
1577
|
+
|
|
1578
|
+
# ----------------------------------------------------------------------------------
|
|
1579
|
+
# Although this method is available for finitely presented group
|
|
1580
|
+
# we use the classical group implementation (by performance reason) to get
|
|
1581
|
+
# the permutation_group.
|
|
1582
|
+
# ----------------------------------------------------------------------------------
|
|
1583
|
+
@cached_method
|
|
1584
|
+
def as_permutation_group(self, use_classical=True):
|
|
1585
|
+
r"""
|
|
1586
|
+
Return a permutation group isomorphic to ``self`` that has a
|
|
1587
|
+
group isomorphism from ``self`` as a conversion.
|
|
1588
|
+
|
|
1589
|
+
INPUT:
|
|
1590
|
+
|
|
1591
|
+
- ``use_classical`` -- boolean (default: ``True``); the permutation
|
|
1592
|
+
group is calculated via the attached classical matrix group as this
|
|
1593
|
+
results in a smaller degree; if ``False``, the permutation group will
|
|
1594
|
+
be calculated using ``self`` (as finitely presented group)
|
|
1595
|
+
|
|
1596
|
+
EXAMPLES::
|
|
1597
|
+
|
|
1598
|
+
sage: C3 = CubicBraidGroup(3)
|
|
1599
|
+
sage: PC3 = C3.as_permutation_group()
|
|
1600
|
+
sage: assert C3.is_isomorphic(PC3) # random (with respect to the occurrence of the info message)
|
|
1601
|
+
sage: PC3.degree()
|
|
1602
|
+
8
|
|
1603
|
+
sage: c = C3([2,1-2])
|
|
1604
|
+
sage: C3(PC3(c)) == c
|
|
1605
|
+
True
|
|
1606
|
+
"""
|
|
1607
|
+
if not self.is_finite():
|
|
1608
|
+
raise ValueError('cubic braid group is infinite!')
|
|
1609
|
+
|
|
1610
|
+
if use_classical:
|
|
1611
|
+
CG = self.as_classical_group()
|
|
1612
|
+
from sage.groups.perm_gps.permgroup import PermutationGroup_generic
|
|
1613
|
+
if isinstance(CG, PermutationGroup_generic):
|
|
1614
|
+
return CG
|
|
1615
|
+
CGM = CG.as_matrix_group()
|
|
1616
|
+
PG = CGM.as_permutation_group()
|
|
1617
|
+
img_gens = [PG(CGM(CG(gen))) for gen in self.gens()]
|
|
1618
|
+
else:
|
|
1619
|
+
PG = super().as_permutation_group()
|
|
1620
|
+
img_gens = PG.gens()
|
|
1621
|
+
|
|
1622
|
+
img_gens = [PG(gen) for gen in img_gens]
|
|
1623
|
+
hom_to_perm = self.hom(img_gens)
|
|
1624
|
+
PG.register_conversion(hom_to_perm)
|
|
1625
|
+
return PG
|
|
1626
|
+
|
|
1627
|
+
# ----------------------------------------------------------------------------------
|
|
1628
|
+
# as_classical_group
|
|
1629
|
+
# ----------------------------------------------------------------------------------
|
|
1630
|
+
def as_classical_group(self, embedded=False):
|
|
1631
|
+
r"""
|
|
1632
|
+
Create an isomorphic image of ``self`` as a classical group according
|
|
1633
|
+
to the construction given by Coxeter resp. Assion.
|
|
1634
|
+
|
|
1635
|
+
INPUT:
|
|
1636
|
+
|
|
1637
|
+
- ``embedded`` -- boolean (default: ``False``); this boolean effects the
|
|
1638
|
+
cases of Assion groups when they are realized as projective groups only.
|
|
1639
|
+
More precisely: if ``self`` is of ``cbg_type CubicBraidGroup.type.AssionS``
|
|
1640
|
+
(for example) and the number of strands ``n`` is even, than its classical
|
|
1641
|
+
group is a subgroup of ``PSp(n,3)`` (being centralized by the element
|
|
1642
|
+
``self.centralizing_element(projective=True))``. By default this group
|
|
1643
|
+
will be given. Setting ``embedded = True`` the classical realization
|
|
1644
|
+
is given as subgroup of its classical enlargement with one more strand
|
|
1645
|
+
(in this case as subgroup of ``Sp(n,3))``.
|
|
1646
|
+
|
|
1647
|
+
OUTPUT:
|
|
1648
|
+
|
|
1649
|
+
Depending on the type of ``self`` and the number of strands an
|
|
1650
|
+
instance of ``Sp(n-1,3)``, ``GU(n-1,2)``, subgroup of ``PSp(n,3)``,
|
|
1651
|
+
``PGU(n,2)``, or a subgroup of ``GU(n-1, UCF)``
|
|
1652
|
+
(``cbg_type == CubicBraidGroup.type.Coxeter``) with respect to a
|
|
1653
|
+
certain Hermitian form attached to the Burau representation
|
|
1654
|
+
(used by Coxeter and Squier). Here ``UCF`` stands for the universal
|
|
1655
|
+
cyclotomic field.
|
|
1656
|
+
|
|
1657
|
+
EXAMPLES::
|
|
1658
|
+
|
|
1659
|
+
sage: # needs sage.rings.finite_rings
|
|
1660
|
+
sage: U3 = AssionGroupU(3)
|
|
1661
|
+
sage: U3Cl = U3.as_classical_group(); U3Cl
|
|
1662
|
+
Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20),
|
|
1663
|
+
(1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] of
|
|
1664
|
+
(The projective general unitary group of degree 3 over Finite Field of size 2)
|
|
1665
|
+
sage: U3Clemb = U3.as_classical_group(embedded=True); U3Clemb
|
|
1666
|
+
Subgroup with 2 generators (
|
|
1667
|
+
[0 0 a] [a + 1 a a]
|
|
1668
|
+
[0 1 0] [ a a + 1 a]
|
|
1669
|
+
[a 0 a], [ a a a + 1]
|
|
1670
|
+
) of General Unitary Group of degree 3 over Finite Field in a of size 2^2
|
|
1671
|
+
sage: u = U3([-2,1,-2,1]); u
|
|
1672
|
+
(u1^-1*u0)^2
|
|
1673
|
+
sage: uCl = U3Cl(u); uCl
|
|
1674
|
+
(1,16)(2,9)(3,10)(4,19)(6,12)(7,20)(13,21)(14,15)
|
|
1675
|
+
sage: uCle = U3Clemb(u); uCle
|
|
1676
|
+
[a + 1 a + 1 1]
|
|
1677
|
+
[a + 1 0 a]
|
|
1678
|
+
[ 1 a a]
|
|
1679
|
+
sage: U3(uCl) == u
|
|
1680
|
+
True
|
|
1681
|
+
sage: U3(uCle) == u
|
|
1682
|
+
True
|
|
1683
|
+
sage: U4 = AssionGroupU(4)
|
|
1684
|
+
sage: U4Cl = U4.as_classical_group(); U4Cl
|
|
1685
|
+
General Unitary Group of degree 3 over Finite Field in a of size 2^2
|
|
1686
|
+
sage: U3Clemb.ambient() == U4Cl
|
|
1687
|
+
True
|
|
1688
|
+
|
|
1689
|
+
sage: # needs sage.rings.number_field
|
|
1690
|
+
sage: C4 = CubicBraidGroup(4)
|
|
1691
|
+
sage: C4Cl = C4.as_classical_group(); C4Cl
|
|
1692
|
+
Subgroup with 3 generators (
|
|
1693
|
+
[ E(3)^2 0 0] [ 1 -E(12)^7 0]
|
|
1694
|
+
[-E(12)^7 1 0] [ 0 E(3)^2 0]
|
|
1695
|
+
[ 0 0 1], [ 0 -E(12)^7 1],
|
|
1696
|
+
<BLANKLINE>
|
|
1697
|
+
[ 1 0 0]
|
|
1698
|
+
[ 0 1 -E(12)^7]
|
|
1699
|
+
[ 0 0 E(3)^2]
|
|
1700
|
+
) of General Unitary Group of degree 3 over Universal Cyclotomic Field
|
|
1701
|
+
with respect to positive definite hermitian form
|
|
1702
|
+
[-E(12)^7 + E(12)^11 -1 0]
|
|
1703
|
+
[ -1 -E(12)^7 + E(12)^11 -1]
|
|
1704
|
+
[ 0 -1 -E(12)^7 + E(12)^11]
|
|
1705
|
+
"""
|
|
1706
|
+
# -------------------------------------------------------------------------------
|
|
1707
|
+
# create the classical group if not already done
|
|
1708
|
+
# -------------------------------------------------------------------------------
|
|
1709
|
+
if self._classical_group is None:
|
|
1710
|
+
if embedded and self._classical_embedding is None:
|
|
1711
|
+
# this is separated to avoid unnecessary (for larger group exhaustive) calculations
|
|
1712
|
+
self._create_classical_realization(just_embedded=True)
|
|
1713
|
+
else:
|
|
1714
|
+
self._create_classical_realization()
|
|
1715
|
+
|
|
1716
|
+
if embedded and self._classical_embedding is not None:
|
|
1717
|
+
# ----------------------------------------------------------------------------------------
|
|
1718
|
+
# there is a difference between self._classical_group and self._classical_embedding
|
|
1719
|
+
# only in the cases where self.strands() divides by 2 (AssionGroupS) resp. 3
|
|
1720
|
+
# (AssionGroupU). In this case the embedding is the subgroup of the classical group
|
|
1721
|
+
# of one strand more (self.strands() +1) generated by the first self.strands() -1
|
|
1722
|
+
# generators
|
|
1723
|
+
# ----------------------------------------------------------------------------------------
|
|
1724
|
+
return self._classical_embedding
|
|
1725
|
+
elif self._classical_group is not None:
|
|
1726
|
+
return self._classical_group
|
|
1727
|
+
|
|
1728
|
+
raise ValueError("no classical embedding defined")
|
|
1729
|
+
|
|
1730
|
+
# ----------------------------------------------------------------------------------
|
|
1731
|
+
# as_refection_group
|
|
1732
|
+
# ----------------------------------------------------------------------------------
|
|
1733
|
+
def as_reflection_group(self):
|
|
1734
|
+
r"""
|
|
1735
|
+
Return an isomorphic image of ``self`` as irreducible complex
|
|
1736
|
+
reflection group.
|
|
1737
|
+
|
|
1738
|
+
This is possible only for the finite cubic braid groups of ``cbg_type``
|
|
1739
|
+
``CubicBraidGroup.type.Coxeter``.
|
|
1740
|
+
|
|
1741
|
+
.. NOTE::
|
|
1742
|
+
|
|
1743
|
+
This method uses the sage implementation of reflection group via
|
|
1744
|
+
the ``gap3`` ``CHEVIE`` package. These must be installed in order
|
|
1745
|
+
to use this method.
|
|
1746
|
+
|
|
1747
|
+
EXAMPLES::
|
|
1748
|
+
|
|
1749
|
+
sage: # optional - gap3
|
|
1750
|
+
sage: C3.<c1,c2> = CubicBraidGroup(3)
|
|
1751
|
+
sage: R3 = C3.as_reflection_group(); R3
|
|
1752
|
+
Irreducible complex reflection group of rank 2 and type ST4
|
|
1753
|
+
sage: R3.cartan_matrix()
|
|
1754
|
+
[-2*E(3) - E(3)^2 E(3)^2]
|
|
1755
|
+
[ -E(3)^2 -2*E(3) - E(3)^2]
|
|
1756
|
+
sage: R3.simple_roots()
|
|
1757
|
+
Finite family {1: (0, -2*E(3) - E(3)^2), 2: (2*E(3)^2, E(3)^2)}
|
|
1758
|
+
sage: R3.simple_coroots()
|
|
1759
|
+
Finite family {1: (0, 1), 2: (1/3*E(3) - 1/3*E(3)^2, 1/3*E(3) - 1/3*E(3)^2)}
|
|
1760
|
+
|
|
1761
|
+
Conversion maps::
|
|
1762
|
+
|
|
1763
|
+
sage: # optional - gap3
|
|
1764
|
+
sage: r = R3.an_element()
|
|
1765
|
+
sage: cr = C3(r); cr
|
|
1766
|
+
c1*c2
|
|
1767
|
+
sage: mr = r.matrix(); mr
|
|
1768
|
+
[ 1/3*E(3) - 1/3*E(3)^2 2/3*E(3) + 1/3*E(3)^2]
|
|
1769
|
+
[-2/3*E(3) + 2/3*E(3)^2 2/3*E(3) + 1/3*E(3)^2]
|
|
1770
|
+
sage: C3Cl = C3.as_classical_group()
|
|
1771
|
+
sage: C3Cl(cr)
|
|
1772
|
+
[ E(3)^2 -E(4)]
|
|
1773
|
+
[-E(12)^7 0]
|
|
1774
|
+
|
|
1775
|
+
The reflection groups can also be viewed as subgroups of unitary groups
|
|
1776
|
+
over the universal cyclotomic field. Note that the unitary group
|
|
1777
|
+
corresponding to the reflection group is isomorphic but different from
|
|
1778
|
+
the classical group due to different hermitian forms for the unitary
|
|
1779
|
+
groups they live in::
|
|
1780
|
+
|
|
1781
|
+
sage: # optional - gap3
|
|
1782
|
+
sage: C4 = CubicBraidGroup(4)
|
|
1783
|
+
sage: R4 = C4.as_reflection_group()
|
|
1784
|
+
sage: R4.invariant_form()
|
|
1785
|
+
[1 0 0]
|
|
1786
|
+
[0 1 0]
|
|
1787
|
+
[0 0 1]
|
|
1788
|
+
sage: _ == C4.classical_invariant_form()
|
|
1789
|
+
False
|
|
1790
|
+
"""
|
|
1791
|
+
# -------------------------------------------------------------------------------
|
|
1792
|
+
# the reflection groups are called according to the Shephard-Todd classification:
|
|
1793
|
+
# 2 strands -> G(2,1,1)
|
|
1794
|
+
# 3 strands -> G4
|
|
1795
|
+
# 4 strands -> G25
|
|
1796
|
+
# 5 strands -> G32
|
|
1797
|
+
# -------------------------------------------------------------------------------
|
|
1798
|
+
from sage.combinat.root_system.reflection_group_real import is_chevie_available
|
|
1799
|
+
if not is_chevie_available():
|
|
1800
|
+
raise ImportError("the GAP3 package 'CHEVIE' is needed to obtain the corresponding reflection groups")
|
|
1801
|
+
|
|
1802
|
+
if self._cbg_type != CubicBraidGroup.type.Coxeter or self.strands() > 5 or self.strands() < 2:
|
|
1803
|
+
raise ValueError("no reflection group defined")
|
|
1804
|
+
|
|
1805
|
+
# -------------------------------------------------------------------------------
|
|
1806
|
+
# define reflection group associated to self
|
|
1807
|
+
# -------------------------------------------------------------------------------
|
|
1808
|
+
reflection_group = None
|
|
1809
|
+
|
|
1810
|
+
from sage.combinat.root_system.reflection_group_real import ReflectionGroup
|
|
1811
|
+
|
|
1812
|
+
if self.strands() == 2:
|
|
1813
|
+
reflection_group = ReflectionGroup([2, 1, 1])
|
|
1814
|
+
elif self.strands() == 3:
|
|
1815
|
+
reflection_group = ReflectionGroup(4)
|
|
1816
|
+
elif self.strands() == 4:
|
|
1817
|
+
reflection_group = ReflectionGroup(25)
|
|
1818
|
+
elif self.strands() == 5:
|
|
1819
|
+
reflection_group = ReflectionGroup(32)
|
|
1820
|
+
|
|
1821
|
+
hom_to_refl = self.hom(reflection_group.gens())
|
|
1822
|
+
reflection_group.register_conversion(hom_to_refl)
|
|
1823
|
+
return reflection_group
|
|
1824
|
+
|
|
1825
|
+
# ----------------------------------------------------------------------------------
|
|
1826
|
+
# classical invariant form returns the invariant form of the classical realization
|
|
1827
|
+
# ----------------------------------------------------------------------------------
|
|
1828
|
+
def classical_invariant_form(self):
|
|
1829
|
+
r"""
|
|
1830
|
+
Return the invariant form of the classical realization of ``self``.
|
|
1831
|
+
|
|
1832
|
+
OUTPUT:
|
|
1833
|
+
|
|
1834
|
+
A square matrix of dimension according to the space the classical
|
|
1835
|
+
realization is operating on. In the case of the full cubic braid groups
|
|
1836
|
+
and of the Assion groups of ``cbg_type CubicBraidGroup.type.AssionU``
|
|
1837
|
+
the matrix is Hermitian. In the case of the Assion groups of
|
|
1838
|
+
``cbg_type CubicBraidGroup.type.AssionS`` it is alternating.
|
|
1839
|
+
Note that the invariant form of the full cubic braid group on more
|
|
1840
|
+
than 5 strands is degenerated (causing the group to be infinite).
|
|
1841
|
+
|
|
1842
|
+
In the case of Assion groups having projective classical groups,
|
|
1843
|
+
the invariant form corresponds to the ambient group of its
|
|
1844
|
+
classical embedding.
|
|
1845
|
+
|
|
1846
|
+
EXAMPLES::
|
|
1847
|
+
|
|
1848
|
+
sage: S3 = AssionGroupS(3)
|
|
1849
|
+
sage: S3.classical_invariant_form()
|
|
1850
|
+
[0 1]
|
|
1851
|
+
[2 0]
|
|
1852
|
+
sage: S4 = AssionGroupS(4)
|
|
1853
|
+
sage: S4.classical_invariant_form()
|
|
1854
|
+
[0 0 0 1]
|
|
1855
|
+
[0 0 1 0]
|
|
1856
|
+
[0 2 0 0]
|
|
1857
|
+
[2 0 0 0]
|
|
1858
|
+
sage: S5 = AssionGroupS(5)
|
|
1859
|
+
sage: S4.classical_invariant_form() == S5.classical_invariant_form()
|
|
1860
|
+
True
|
|
1861
|
+
sage: U4 = AssionGroupU(4)
|
|
1862
|
+
sage: U4.classical_invariant_form()
|
|
1863
|
+
[0 0 1]
|
|
1864
|
+
[0 1 0]
|
|
1865
|
+
[1 0 0]
|
|
1866
|
+
sage: C5 = CubicBraidGroup(5)
|
|
1867
|
+
sage: C5.classical_invariant_form()
|
|
1868
|
+
[-E(12)^7 + E(12)^11 -1 0 0]
|
|
1869
|
+
[ -1 -E(12)^7 + E(12)^11 -1 0]
|
|
1870
|
+
[ 0 -1 -E(12)^7 + E(12)^11 -1]
|
|
1871
|
+
[ 0 0 -1 -E(12)^7 + E(12)^11]
|
|
1872
|
+
sage: _.is_singular()
|
|
1873
|
+
False
|
|
1874
|
+
sage: C6 = CubicBraidGroup(6)
|
|
1875
|
+
sage: C6.classical_invariant_form().is_singular()
|
|
1876
|
+
True
|
|
1877
|
+
"""
|
|
1878
|
+
# -------------------------------------------------------------------------------
|
|
1879
|
+
# create the classical_invariant_form if not already done
|
|
1880
|
+
# -------------------------------------------------------------------------------
|
|
1881
|
+
if self._classical_invariant_form is None:
|
|
1882
|
+
self._create_classical_realization()
|
|
1883
|
+
|
|
1884
|
+
if self._classical_invariant_form is None:
|
|
1885
|
+
raise ValueError("no classical invariant form defined")
|
|
1886
|
+
|
|
1887
|
+
return self._classical_invariant_form
|
|
1888
|
+
|
|
1889
|
+
# ----------------------------------------------------------------------------------
|
|
1890
|
+
# centralizing element in the classical symplectic resp. unitary group
|
|
1891
|
+
# ----------------------------------------------------------------------------------
|
|
1892
|
+
def centralizing_element(self, embedded=False):
|
|
1893
|
+
r"""
|
|
1894
|
+
Return the centralizing element defined by the work of Assion
|
|
1895
|
+
(Hilfssatz 1.1.3 and 1.2.3).
|
|
1896
|
+
|
|
1897
|
+
INPUT:
|
|
1898
|
+
|
|
1899
|
+
- ``embedded`` -- boolean (default; ``False``); this boolean only effects
|
|
1900
|
+
the cases of Assion groups when they are realized as projective groups.
|
|
1901
|
+
More precisely: if ``self`` is of ``cbg_type CubicBraidGroup.type.AssionS``
|
|
1902
|
+
(for example) and the number of strands ``n`` is even, than its
|
|
1903
|
+
classical group is a subgroup of ``PSp(n,3)`` being centralized
|
|
1904
|
+
by the element return for option ``embedded=False``. Otherwise the
|
|
1905
|
+
image of this element inside the embedded classical group will be
|
|
1906
|
+
returned (see option embedded of :meth:`classical_group`).
|
|
1907
|
+
|
|
1908
|
+
OUTPUT:
|
|
1909
|
+
|
|
1910
|
+
Depending on the optional keyword a permutation as an element
|
|
1911
|
+
of ``PSp(n,3)`` (type S) or ``PGU(n,2)`` (type U) for ``n = 0 mod 2``
|
|
1912
|
+
(type S) resp. ``n = 0 mod 3`` (type U) is returned. Otherwise, the
|
|
1913
|
+
centralizing element is a matrix belonging to ``Sp(n,3)``
|
|
1914
|
+
resp. ``GU(n,2)``.
|
|
1915
|
+
|
|
1916
|
+
EXAMPLES::
|
|
1917
|
+
|
|
1918
|
+
sage: U3 = AssionGroupU(3); U3
|
|
1919
|
+
Assion group on 3 strands of type U
|
|
1920
|
+
sage: U3Cl = U3.as_classical_group(); U3Cl
|
|
1921
|
+
Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20),
|
|
1922
|
+
(1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)]
|
|
1923
|
+
of (The projective general unitary group of degree 3 over Finite Field of size 2)
|
|
1924
|
+
sage: c = U3.centralizing_element(); c
|
|
1925
|
+
(1,16)(2,9)(3,10)(4,19)(6,12)(7,20)(13,21)(14,15)
|
|
1926
|
+
sage: c in U3Cl
|
|
1927
|
+
True
|
|
1928
|
+
sage: P = U3Cl.ambient_group()
|
|
1929
|
+
sage: P.centralizer(c) == U3Cl
|
|
1930
|
+
True
|
|
1931
|
+
|
|
1932
|
+
Embedded version::
|
|
1933
|
+
|
|
1934
|
+
sage: cm = U3.centralizing_element(embedded=True); cm
|
|
1935
|
+
[a + 1 a + 1 1]
|
|
1936
|
+
[a + 1 0 a]
|
|
1937
|
+
[ 1 a a]
|
|
1938
|
+
sage: U4 = AssionGroupU(4)
|
|
1939
|
+
sage: U4Cl = U4.as_classical_group()
|
|
1940
|
+
sage: cm in U4Cl
|
|
1941
|
+
True
|
|
1942
|
+
sage: [cm * U4Cl(g) == U4Cl(g) * cm for g in U4.gens()]
|
|
1943
|
+
[True, True, False]
|
|
1944
|
+
"""
|
|
1945
|
+
# -------------------------------------------------------------------------------
|
|
1946
|
+
# create the centralizing elements if not already done
|
|
1947
|
+
# -------------------------------------------------------------------------------
|
|
1948
|
+
if self._centralizing_matrix is None:
|
|
1949
|
+
self._create_classical_realization()
|
|
1950
|
+
|
|
1951
|
+
if self._centralizing_matrix is None:
|
|
1952
|
+
raise ValueError("no centralizing element defined")
|
|
1953
|
+
else:
|
|
1954
|
+
if embedded or self._centralizing_element is None:
|
|
1955
|
+
return self._centralizing_matrix
|
|
1956
|
+
else:
|
|
1957
|
+
return self._centralizing_element
|
|
1958
|
+
|
|
1959
|
+
# ----------------------------------------------------------------------------------
|
|
1960
|
+
# calculating the order by formula
|
|
1961
|
+
# ----------------------------------------------------------------------------------
|
|
1962
|
+
def order(self):
|
|
1963
|
+
r"""
|
|
1964
|
+
To avoid long wait-time on calculations the order will be obtained
|
|
1965
|
+
using the classical realization.
|
|
1966
|
+
|
|
1967
|
+
OUTPUT: cardinality of the group as integer or infinity
|
|
1968
|
+
|
|
1969
|
+
EXAMPLES::
|
|
1970
|
+
|
|
1971
|
+
sage: S15 = AssionGroupS(15)
|
|
1972
|
+
sage: S15.order()
|
|
1973
|
+
109777561863482259035023554842176139436811616256000
|
|
1974
|
+
sage: C6 = CubicBraidGroup(6)
|
|
1975
|
+
sage: C6.order()
|
|
1976
|
+
+Infinity
|
|
1977
|
+
"""
|
|
1978
|
+
from sage.rings.infinity import infinity
|
|
1979
|
+
n = self.strands()
|
|
1980
|
+
|
|
1981
|
+
if self._cbg_type == CubicBraidGroup.type.Coxeter and n > 5:
|
|
1982
|
+
order = infinity
|
|
1983
|
+
else:
|
|
1984
|
+
order = self.as_classical_group(embedded=True).order()
|
|
1985
|
+
|
|
1986
|
+
return order
|
|
1987
|
+
|
|
1988
|
+
cardinality = order
|
|
1989
|
+
|
|
1990
|
+
def is_finite(self):
|
|
1991
|
+
r"""
|
|
1992
|
+
Return if ``self`` is a finite group or not.
|
|
1993
|
+
|
|
1994
|
+
EXAMPLES::
|
|
1995
|
+
|
|
1996
|
+
sage: CubicBraidGroup(6).is_finite()
|
|
1997
|
+
False
|
|
1998
|
+
sage: AssionGroupS(6).is_finite()
|
|
1999
|
+
True
|
|
2000
|
+
"""
|
|
2001
|
+
return not (self._cbg_type == CubicBraidGroup.type.Coxeter and self.strands() > 5)
|
|
2002
|
+
|
|
2003
|
+
# ------------------------------------------------------------------
|
|
2004
|
+
# creating a CubicBraidGroup as subgroup of self on less strands
|
|
2005
|
+
# ------------------------------------------------------------------
|
|
2006
|
+
def cubic_braid_subgroup(self, nstrands=None):
|
|
2007
|
+
r"""
|
|
2008
|
+
Return a cubic braid group as subgroup of ``self`` on the first
|
|
2009
|
+
``nstrands`` strands.
|
|
2010
|
+
|
|
2011
|
+
INPUT:
|
|
2012
|
+
|
|
2013
|
+
- ``nstrands`` -- (default: ``self.strands() - 1``) integer at least 1
|
|
2014
|
+
and at most ``self.strands()`` giving the number of strands of
|
|
2015
|
+
the subgroup
|
|
2016
|
+
|
|
2017
|
+
.. WARNING::
|
|
2018
|
+
|
|
2019
|
+
Since ``self`` is inherited from :class:`UniqueRepresentation`, the
|
|
2020
|
+
obtained instance is identical to other instances created with the
|
|
2021
|
+
same arguments (see example below). The ambient group corresponds
|
|
2022
|
+
to the last call of this method.
|
|
2023
|
+
|
|
2024
|
+
EXAMPLES::
|
|
2025
|
+
|
|
2026
|
+
sage: U5 = AssionGroupU(5)
|
|
2027
|
+
sage: U3s = U5.cubic_braid_subgroup(3)
|
|
2028
|
+
sage: u1, u2 = U3s.gens()
|
|
2029
|
+
sage: u1 in U5
|
|
2030
|
+
False
|
|
2031
|
+
sage: U5(u1) in U5.gens()
|
|
2032
|
+
True
|
|
2033
|
+
sage: U3s is AssionGroupU(3)
|
|
2034
|
+
True
|
|
2035
|
+
sage: U3s.ambient() == U5
|
|
2036
|
+
True
|
|
2037
|
+
"""
|
|
2038
|
+
if nstrands is None:
|
|
2039
|
+
nstrands = self.strands() - 1
|
|
2040
|
+
|
|
2041
|
+
n = self.strands()
|
|
2042
|
+
|
|
2043
|
+
nstrands = Integer(nstrands)
|
|
2044
|
+
|
|
2045
|
+
if nstrands >= n or nstrands <= 0:
|
|
2046
|
+
raise ValueError("nstrands must be positive and less than %s" % (self.strands()))
|
|
2047
|
+
|
|
2048
|
+
names = self.variable_names()
|
|
2049
|
+
names_red = names[:nstrands - 1]
|
|
2050
|
+
subgrp = CubicBraidGroup(names=names_red, cbg_type=self._cbg_type)
|
|
2051
|
+
subgrp._ambient = self
|
|
2052
|
+
return subgrp
|