passagemath-groups 10.6.41__cp314-cp314t-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. passagemath_groups/__init__.py +3 -0
  2. passagemath_groups-10.6.41.dist-info/METADATA +113 -0
  3. passagemath_groups-10.6.41.dist-info/RECORD +36 -0
  4. passagemath_groups-10.6.41.dist-info/WHEEL +5 -0
  5. passagemath_groups-10.6.41.dist-info/top_level.txt +3 -0
  6. sage/all__sagemath_groups.py +21 -0
  7. sage/geometry/all__sagemath_groups.py +1 -0
  8. sage/geometry/palp_normal_form.cpython-314t-x86_64-linux-musl.so +0 -0
  9. sage/geometry/palp_normal_form.pyx +401 -0
  10. sage/groups/abelian_gps/all.py +25 -0
  11. sage/groups/all.py +5 -0
  12. sage/groups/all__sagemath_groups.py +32 -0
  13. sage/groups/artin.py +1074 -0
  14. sage/groups/braid.py +3806 -0
  15. sage/groups/cactus_group.py +1001 -0
  16. sage/groups/cubic_braid.py +2052 -0
  17. sage/groups/finitely_presented.py +1896 -0
  18. sage/groups/finitely_presented_catalog.py +27 -0
  19. sage/groups/finitely_presented_named.py +592 -0
  20. sage/groups/fqf_orthogonal.py +579 -0
  21. sage/groups/free_group.py +944 -0
  22. sage/groups/group_exp.py +360 -0
  23. sage/groups/group_semidirect_product.py +504 -0
  24. sage/groups/kernel_subgroup.py +231 -0
  25. sage/groups/lie_gps/all.py +1 -0
  26. sage/groups/lie_gps/catalog.py +8 -0
  27. sage/groups/lie_gps/nilpotent_lie_group.py +945 -0
  28. sage/groups/misc_gps/all.py +1 -0
  29. sage/groups/misc_gps/misc_groups.py +11 -0
  30. sage/groups/misc_gps/misc_groups_catalog.py +33 -0
  31. sage/groups/raag.py +866 -0
  32. sage/groups/semimonomial_transformations/all.py +1 -0
  33. sage/groups/semimonomial_transformations/semimonomial_transformation.cpython-314t-x86_64-linux-musl.so +0 -0
  34. sage/groups/semimonomial_transformations/semimonomial_transformation.pxd +9 -0
  35. sage/groups/semimonomial_transformations/semimonomial_transformation.pyx +346 -0
  36. sage/groups/semimonomial_transformations/semimonomial_transformation_group.py +512 -0
@@ -0,0 +1,944 @@
1
+ # sage_setup: distribution = sagemath-groups
2
+ """
3
+ Free Groups
4
+
5
+ Free groups and finitely presented groups are implemented as a wrapper
6
+ over the corresponding GAP objects.
7
+
8
+ A free group can be created by giving the number of generators, or their names.
9
+ It is also possible to create indexed generators::
10
+
11
+ sage: G.<x,y,z> = FreeGroup(); G
12
+ Free Group on generators {x, y, z}
13
+ sage: FreeGroup(3)
14
+ Free Group on generators {x0, x1, x2}
15
+ sage: FreeGroup('a,b,c')
16
+ Free Group on generators {a, b, c}
17
+ sage: FreeGroup(3,'t')
18
+ Free Group on generators {t0, t1, t2}
19
+
20
+ The elements can be created by operating with the generators, or by passing a list
21
+ with the indices of the letters to the group:
22
+
23
+ EXAMPLES::
24
+
25
+ sage: G.<a,b,c> = FreeGroup()
26
+ sage: a*b*c*a
27
+ a*b*c*a
28
+ sage: G([1,2,3,1])
29
+ a*b*c*a
30
+ sage: a * b / c * b^2
31
+ a*b*c^-1*b^2
32
+ sage: G([1,1,2,-1,-3,2])
33
+ a^2*b*a^-1*c^-1*b
34
+
35
+ You can use call syntax to replace the generators with a set of
36
+ arbitrary ring elements::
37
+
38
+ sage: g = a * b / c * b^2
39
+ sage: g(1,2,3)
40
+ 8/3
41
+ sage: M1 = identity_matrix(2)
42
+ sage: M2 = matrix([[1,1],[0,1]])
43
+ sage: M3 = matrix([[0,1],[1,0]])
44
+ sage: g([M1, M2, M3])
45
+ [1 3]
46
+ [1 2]
47
+
48
+ AUTHORS:
49
+
50
+ - Miguel Angel Marco Buzunariz
51
+ - Volker Braun
52
+ """
53
+
54
+ # ****************************************************************************
55
+ # Copyright (C) 2012 Miguel Angel Marco Buzunariz <mmarco@unizar.es>
56
+ #
57
+ # Distributed under the terms of the GNU General Public License (GPL)
58
+ #
59
+ # The full text of the GPL is available at:
60
+ #
61
+ # https://www.gnu.org/licenses/
62
+ # ****************************************************************************
63
+
64
+ from sage.categories.groups import Groups
65
+ from sage.groups.group import Group
66
+ from sage.groups.libgap_wrapper import ParentLibGAP, ElementLibGAP
67
+ from sage.structure.unique_representation import CachedRepresentation
68
+ from sage.libs.gap.libgap import libgap
69
+ from sage.libs.gap.element import GapElement
70
+ from sage.rings.integer import Integer
71
+ from sage.rings.integer_ring import IntegerRing
72
+ from sage.misc.cachefunc import cached_method
73
+ from sage.misc.misc_c import prod
74
+ from sage.structure.sequence import Sequence
75
+ from sage.structure.element import coercion_model, parent
76
+ from sage.structure.richcmp import richcmp, richcmp_method
77
+
78
+
79
+ def is_FreeGroup(x):
80
+ """
81
+ Test whether ``x`` is a :class:`FreeGroup_class`.
82
+
83
+ INPUT:
84
+
85
+ - ``x`` -- anything
86
+
87
+ OUTPUT: boolean
88
+
89
+ EXAMPLES::
90
+
91
+ sage: from sage.groups.free_group import is_FreeGroup
92
+ sage: is_FreeGroup('a string') # needs sage.combinat
93
+ False
94
+ sage: is_FreeGroup(FreeGroup(0))
95
+ True
96
+ sage: is_FreeGroup(FreeGroup(index_set=ZZ)) # needs sage.combinat
97
+ True
98
+ """
99
+ if isinstance(x, FreeGroup_class):
100
+ return True
101
+ from sage.groups.indexed_free_group import IndexedFreeGroup
102
+ return isinstance(x, IndexedFreeGroup)
103
+
104
+
105
+ def _lexi_gen(zeroes=False):
106
+ """
107
+ Return a generator object that produces variable names suitable for the
108
+ generators of a free group.
109
+
110
+ INPUT:
111
+
112
+ - ``zeroes`` -- boolean (default: ``False``); if ``True``, the
113
+ integers appended to the output string begin at zero at the
114
+ first iteration through the alphabet
115
+
116
+ OUTPUT:
117
+
118
+ Python generator object which outputs a character from the alphabet on each
119
+ ``next()`` call in lexicographical order. The integer `i` is appended
120
+ to the output string on the `i`-th iteration through the alphabet.
121
+
122
+ EXAMPLES::
123
+
124
+ sage: from sage.groups.free_group import _lexi_gen
125
+ sage: itr = _lexi_gen()
126
+ sage: F = FreeGroup([next(itr) for i in [1..10]]); F
127
+ Free Group on generators {a, b, c, d, e, f, g, h, i, j}
128
+ sage: it = _lexi_gen()
129
+ sage: [next(it) for i in range(10)]
130
+ ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
131
+ sage: itt = _lexi_gen(True)
132
+ sage: [next(itt) for i in range(10)]
133
+ ['a0', 'b0', 'c0', 'd0', 'e0', 'f0', 'g0', 'h0', 'i0', 'j0']
134
+ sage: test = _lexi_gen()
135
+ sage: ls = [next(test) for i in range(3*26)]
136
+ sage: ls[2*26:3*26]
137
+ ['a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2', 'i2', 'j2', 'k2', 'l2', 'm2',
138
+ 'n2', 'o2', 'p2', 'q2', 'r2', 's2', 't2', 'u2', 'v2', 'w2', 'x2', 'y2', 'z2']
139
+
140
+ TESTS::
141
+
142
+ sage: from sage.groups.free_group import _lexi_gen
143
+ sage: test = _lexi_gen()
144
+ sage: ls = [next(test) for i in range(500)]
145
+ sage: ls[234], ls[260]
146
+ ('a9', 'a10')
147
+ """
148
+ count = Integer(0)
149
+ while True:
150
+ mwrap, ind = count.quo_rem(26)
151
+ if mwrap == 0 and not zeroes:
152
+ name = ''
153
+ else:
154
+ name = str(mwrap)
155
+ name = chr(ord('a') + ind) + name
156
+ yield name
157
+ count += 1
158
+
159
+
160
+ class FreeGroupElement(ElementLibGAP):
161
+ """
162
+ A wrapper of GAP's Free Group elements.
163
+
164
+ INPUT:
165
+
166
+ - ``x`` -- something that determines the group element; either a
167
+ :class:`~sage.libs.gap.element.GapElement` or the Tietze list
168
+ (see :meth:`Tietze`) of the group element
169
+
170
+ - ``parent`` -- the parent :class:`FreeGroup`
171
+
172
+ EXAMPLES::
173
+
174
+ sage: G = FreeGroup('a, b')
175
+ sage: x = G([1, 2, -1, -2])
176
+ sage: x
177
+ a*b*a^-1*b^-1
178
+ sage: y = G([2, 2, 2, 1, -2, -2, -2])
179
+ sage: y
180
+ b^3*a*b^-3
181
+ sage: x*y
182
+ a*b*a^-1*b^2*a*b^-3
183
+ sage: y*x
184
+ b^3*a*b^-3*a*b*a^-1*b^-1
185
+ sage: x^(-1)
186
+ b*a*b^-1*a^-1
187
+ sage: x == x*y*y^(-1)
188
+ True
189
+ """
190
+
191
+ def __init__(self, parent, x):
192
+ """
193
+ The Python constructor.
194
+
195
+ See :class:`FreeGroupElement` for details.
196
+
197
+ TESTS::
198
+
199
+ sage: G.<a,b> = FreeGroup()
200
+ sage: x = G([1, 2, -1, -1])
201
+ sage: x # indirect doctest
202
+ a*b*a^-2
203
+ sage: y = G([2, 2, 2, 1, -2, -2, -1])
204
+ sage: y # indirect doctest
205
+ b^3*a*b^-2*a^-1
206
+
207
+ sage: TestSuite(G).run()
208
+ sage: TestSuite(x).run()
209
+ """
210
+ if not isinstance(x, GapElement):
211
+ try:
212
+ l = x.Tietze()
213
+ except AttributeError:
214
+ l = list(x)
215
+ if len(l) > 0:
216
+ if min(l) < -parent.ngens() or parent.ngens() < max(l):
217
+ raise ValueError('generators not in the group')
218
+ if 0 in l:
219
+ raise ValueError('zero does not denote a generator')
220
+ i = 0
221
+ while i < len(l)-1:
222
+ if l[i] == -l[i+1]:
223
+ l.pop(i)
224
+ l.pop(i)
225
+ if i > 0:
226
+ i = i-1
227
+ else:
228
+ i = i+1
229
+ AbstractWordTietzeWord = libgap.eval('AbstractWordTietzeWord')
230
+ x = AbstractWordTietzeWord(l, parent.gap().GeneratorsOfGroup())
231
+ ElementLibGAP.__init__(self, parent, x)
232
+
233
+ def __hash__(self):
234
+ r"""
235
+ TESTS::
236
+
237
+ sage: G.<a,b> = FreeGroup()
238
+ sage: hash(a*b*b*~a) == hash((1, 2, 2, -1))
239
+ True
240
+ """
241
+ return hash(self.Tietze())
242
+
243
+ def _latex_(self):
244
+ r"""
245
+ Return a LaTeX representation.
246
+
247
+ OUTPUT: string; a valid LaTeX math command sequence
248
+
249
+ EXAMPLES::
250
+
251
+ sage: F.<a,b,c> = FreeGroup()
252
+ sage: f = F([1, 2, 2, -3, -1]) * c^15 * a^(-23)
253
+ sage: f._latex_()
254
+ 'a\\cdot b^{2}\\cdot c^{-1}\\cdot a^{-1}\\cdot c^{15}\\cdot a^{-23}'
255
+
256
+ sage: F = FreeGroup(3)
257
+ sage: f = F([1, 2, 2, -3, -1]) * F.gen(2)^11 * F.gen(0)^(-12)
258
+ sage: f._latex_()
259
+ 'x_{0}\\cdot x_{1}^{2}\\cdot x_{2}^{-1}\\cdot x_{0}^{-1}\\cdot x_{2}^{11}\\cdot x_{0}^{-12}'
260
+
261
+ sage: F.<a,b,c> = FreeGroup()
262
+ sage: G = F / (F([1, 2, 1, -3, 2, -1]), F([2, -1]))
263
+ sage: f = G([1, 2, 2, -3, -1]) * G.gen(2)^15 * G.gen(0)^(-23)
264
+ sage: f._latex_()
265
+ 'a\\cdot b^{2}\\cdot c^{-1}\\cdot a^{-1}\\cdot c^{15}\\cdot a^{-23}'
266
+
267
+ sage: F = FreeGroup(4)
268
+ sage: G = F.quotient((F([1, 2, 4, -3, 2, -1]), F([2, -1])))
269
+ sage: f = G([1, 2, 2, -3, -1]) * G.gen(3)^11 * G.gen(0)^(-12)
270
+ sage: f._latex_()
271
+ 'x_{0}\\cdot x_{1}^{2}\\cdot x_{2}^{-1}\\cdot x_{0}^{-1}\\cdot x_{3}^{11}\\cdot x_{0}^{-12}'
272
+ """
273
+ import re
274
+ s = self._repr_()
275
+ s = re.sub('([a-z]|[A-Z])([0-9]+)', r'\g<1>_{\g<2>}', s)
276
+ s = re.sub(r'(\^)(-)([0-9]+)', r'\g<1>{\g<2>\g<3>}', s)
277
+ s = re.sub(r'(\^)([0-9]+)', r'\g<1>{\g<2>}', s)
278
+ s = s.replace('*', r'\cdot ')
279
+ return s
280
+
281
+ def __reduce__(self):
282
+ """
283
+ Implement pickling.
284
+
285
+ TESTS::
286
+
287
+ sage: F.<a,b> = FreeGroup()
288
+ sage: a.__reduce__()
289
+ (Free Group on generators {a, b}, ((1,),))
290
+ sage: (a*b*a^-1).__reduce__()
291
+ (Free Group on generators {a, b}, ((1, 2, -1),))
292
+ """
293
+ return (self.parent(), (self.Tietze(),))
294
+
295
+ @cached_method
296
+ def Tietze(self):
297
+ """
298
+ Return the Tietze list of the element.
299
+
300
+ The Tietze list of a word is a list of integers that represent
301
+ the letters in the word. A positive integer `i` represents
302
+ the letter corresponding to the `i`-th generator of the group.
303
+ Negative integers represent the inverses of generators.
304
+
305
+ OUTPUT: tuple of integers
306
+
307
+ EXAMPLES::
308
+
309
+ sage: G.<a,b> = FreeGroup()
310
+ sage: a.Tietze()
311
+ (1,)
312
+ sage: x = a^2 * b^(-3) * a^(-2)
313
+ sage: x.Tietze()
314
+ (1, 1, -2, -2, -2, -1, -1)
315
+
316
+ TESTS::
317
+
318
+ sage: type(a.Tietze())
319
+ <... 'tuple'>
320
+ sage: type(a.Tietze()[0])
321
+ <class 'sage.rings.integer.Integer'>
322
+ """
323
+ tl = self.gap().TietzeWordAbstractWord()
324
+ return tuple(tl.sage())
325
+
326
+ def fox_derivative(self, gen, im_gens=None, ring=None):
327
+ r"""
328
+ Return the Fox derivative of ``self`` with respect to a given
329
+ generator ``gen`` of the free group.
330
+
331
+ Let `F` be a free group with free generators
332
+ `x_1, x_2, \ldots, x_n`. Let `j \in \left\{ 1, 2, \ldots ,
333
+ n \right\}`. Let `a_1, a_2, \ldots, a_n` be `n`
334
+ invertible elements of a ring `A`. Let `a : F \to A^\times`
335
+ be the (unique) homomorphism from `F` to the multiplicative
336
+ group of invertible elements of `A` which sends each `x_i`
337
+ to `a_i`. Then, we can define a map `\partial_j : F \to A`
338
+ by the requirements that
339
+
340
+ .. MATH::
341
+
342
+ \partial_j (x_i) = \delta_{i, j}
343
+ \qquad \qquad \text{ for all indices } i \text{ and } j
344
+
345
+ and
346
+
347
+ .. MATH::
348
+
349
+ \partial_j (uv) = \partial_j(u) + a(u) \partial_j(v)
350
+ \qquad \qquad \text{ for all } u, v \in F .
351
+
352
+ This map `\partial_j` is called the `j`-th Fox derivative
353
+ on `F` induced by `(a_1, a_2, \ldots, a_n)`.
354
+
355
+ The most well-known case is when `A` is the group ring
356
+ `\ZZ [F]` of `F` over `\ZZ`, and when `a_i = x_i \in A`.
357
+ In this case, `\partial_j` is simply called the `j`-th
358
+ Fox derivative on `F`.
359
+
360
+ INPUT:
361
+
362
+ - ``gen`` -- the generator with respect to which the
363
+ derivative will be computed. If this is `x_j`, then the
364
+ method will return `\partial_j`.
365
+
366
+ - ``im_gens`` -- (optional) the images of the generators
367
+ (given as a list or iterable). This is the list
368
+ `(a_1, a_2, \ldots, a_n)`.
369
+ If not provided, it defaults to
370
+ `(x_1, x_2, \ldots, x_n)` in the group ring
371
+ `\ZZ [F]`.
372
+
373
+ - ``ring`` -- (optional) the ring in which the elements
374
+ of the list `(a_1, a_2, \ldots, a_n)` lie. If not
375
+ provided, this ring is inferred from these elements.
376
+
377
+ OUTPUT:
378
+
379
+ The fox derivative of ``self`` with respect to ``gen``
380
+ (induced by ``im_gens``).
381
+ By default, it is an element of the group algebra with
382
+ integer coefficients.
383
+ If ``im_gens`` are provided, the result lives in the
384
+ algebra where ``im_gens`` live.
385
+
386
+ EXAMPLES::
387
+
388
+ sage: G = FreeGroup(5)
389
+ sage: G.inject_variables()
390
+ Defining x0, x1, x2, x3, x4
391
+ sage: (~x0*x1*x0*x2*~x0).fox_derivative(x0)
392
+ -x0^-1 + x0^-1*x1 - x0^-1*x1*x0*x2*x0^-1
393
+ sage: (~x0*x1*x0*x2*~x0).fox_derivative(x1)
394
+ x0^-1
395
+ sage: (~x0*x1*x0*x2*~x0).fox_derivative(x2)
396
+ x0^-1*x1*x0
397
+ sage: (~x0*x1*x0*x2*~x0).fox_derivative(x3)
398
+ 0
399
+
400
+ If ``im_gens`` is given, the images of the generators are
401
+ mapped to them::
402
+
403
+ sage: F = FreeGroup(3)
404
+ sage: a = F([2,1,3,-1,2])
405
+ sage: a.fox_derivative(F([1]))
406
+ x1 - x1*x0*x2*x0^-1
407
+ sage: R.<t> = LaurentPolynomialRing(ZZ)
408
+ sage: a.fox_derivative(F([1]),[t,t,t])
409
+ t - t^2
410
+ sage: S.<t1,t2,t3> = LaurentPolynomialRing(ZZ)
411
+ sage: a.fox_derivative(F([1]),[t1,t2,t3])
412
+ -t2*t3 + t2
413
+ sage: R.<x,y,z> = QQ[]
414
+ sage: a.fox_derivative(F([1]),[x,y,z])
415
+ -y*z + y
416
+ sage: a.inverse().fox_derivative(F([1]),[x,y,z])
417
+ (z - 1)/(y*z)
418
+
419
+ The optional parameter ``ring`` determines the ring `A`::
420
+
421
+ sage: u = a.fox_derivative(F([1]), [1,2,3], ring=QQ)
422
+ sage: u
423
+ -4
424
+ sage: parent(u)
425
+ Rational Field
426
+ sage: u = a.fox_derivative(F([1]), [1,2,3], ring=R)
427
+ sage: u
428
+ -4
429
+ sage: parent(u)
430
+ Multivariate Polynomial Ring in x, y, z over Rational Field
431
+
432
+ TESTS::
433
+
434
+ sage: F = FreeGroup(3)
435
+ sage: a = F([])
436
+ sage: a.fox_derivative(F([1]))
437
+ 0
438
+ sage: R.<t> = LaurentPolynomialRing(ZZ)
439
+ sage: a.fox_derivative(F([1]),[t,t,t])
440
+ 0
441
+ """
442
+ if gen not in self.parent().generators():
443
+ raise ValueError("Fox derivative can only be computed with respect to generators of the group")
444
+ l = list(self.Tietze())
445
+ if im_gens is None:
446
+ F = self.parent()
447
+ R = F.algebra(IntegerRing())
448
+ R_basis = R.basis()
449
+ symb = [R_basis[a] for a in F.gens()]
450
+ symb += reversed([R_basis[a.inverse()] for a in F.gens()])
451
+ if ring is not None:
452
+ R = ring
453
+ symb = [R(i) for i in symb]
454
+ else:
455
+ if ring is None:
456
+ R = Sequence(im_gens).universe()
457
+ else:
458
+ R = ring
459
+ symb = list(im_gens)
460
+ symb += reversed([a**(-1) for a in im_gens])
461
+ i = gen.Tietze()[0]
462
+ # so gen is the i-th generator of the free group
463
+
464
+ a = R.zero()
465
+ coef = R.one()
466
+ while l:
467
+ b = l.pop(0)
468
+ if b == i:
469
+ a += coef * R.one()
470
+ coef *= symb[b-1]
471
+ elif b == -i:
472
+ a -= coef * symb[b]
473
+ coef *= symb[b]
474
+ elif b > 0:
475
+ coef *= symb[b-1]
476
+ else:
477
+ coef *= symb[b]
478
+ return a
479
+
480
+ @cached_method
481
+ def syllables(self):
482
+ r"""
483
+ Return the syllables of the word.
484
+
485
+ Consider a free group element `g = x_1^{n_1} x_2^{n_2} \cdots
486
+ x_k^{n_k}`. The uniquely-determined subwords `x_i^{e_i}`
487
+ consisting only of powers of a single generator are called the
488
+ syllables of `g`.
489
+
490
+ OUTPUT:
491
+
492
+ The tuple of syllables. Each syllable is given as a pair
493
+ `(x_i, e_i)` consisting of a generator and a nonzero integer.
494
+
495
+ EXAMPLES::
496
+
497
+ sage: G.<a,b> = FreeGroup()
498
+ sage: w = a^2 * b^-1 * a^3
499
+ sage: w.syllables()
500
+ ((a, 2), (b, -1), (a, 3))
501
+ """
502
+ g = self.gap().UnderlyingElement()
503
+ k = g.NumberSyllables().sage()
504
+ exponent_syllable = libgap.eval('ExponentSyllable')
505
+ generator_syllable = libgap.eval('GeneratorSyllable')
506
+ result = []
507
+ gen = self.parent().gen
508
+ for i in range(k):
509
+ exponent = exponent_syllable(g, i+1).sage()
510
+ generator = gen(generator_syllable(g, i+1).sage() - 1)
511
+ result.append((generator, exponent))
512
+ return tuple(result)
513
+
514
+ def __call__(self, *values):
515
+ """
516
+ Replace the generators of the free group by corresponding
517
+ elements of the iterable ``values`` in the group element
518
+ ``self``.
519
+
520
+ INPUT:
521
+
522
+ - ``*values`` -- a sequence of values, or a
523
+ list/tuple/iterable of the same length as the number of
524
+ generators of the free group
525
+
526
+ OUTPUT: the product of ``values`` in the order and with exponents
527
+ specified by ``self``
528
+
529
+ EXAMPLES::
530
+
531
+ sage: G.<a,b> = FreeGroup()
532
+ sage: w = a^2 * b^-1 * a^3
533
+ sage: w(1, 2)
534
+ 1/2
535
+ sage: w(2, 1)
536
+ 32
537
+ sage: w.subs(b=1, a=2) # indirect doctest
538
+ 32
539
+
540
+ TESTS::
541
+
542
+ sage: w([1, 2])
543
+ 1/2
544
+ sage: w((1, 2))
545
+ 1/2
546
+ sage: w(i+1 for i in range(2))
547
+ 1/2
548
+
549
+ Check that :issue:`25017` is fixed::
550
+
551
+ sage: F = FreeGroup(2)
552
+ sage: x0, x1 = F.gens()
553
+ sage: u = F(1)
554
+ sage: parent(u.subs({x1:x0})) is F
555
+ True
556
+
557
+ sage: F = FreeGroup(2)
558
+ sage: x0, x1 = F.gens()
559
+ sage: u = x0*x1
560
+ sage: u.subs({x0:3, x1:2})
561
+ 6
562
+ sage: u.subs({x0:1r, x1:2r})
563
+ 2
564
+ sage: M0 = matrix(ZZ,2,[1,1,0,1])
565
+ sage: M1 = matrix(ZZ,2,[1,0,1,1])
566
+ sage: u.subs({x0: M0, x1: M1})
567
+ [2 1]
568
+ [1 1]
569
+
570
+ TESTS::
571
+
572
+ sage: F.<x,y> = FreeGroup()
573
+ sage: F.one().subs(x=x, y=1)
574
+ Traceback (most recent call last):
575
+ ...
576
+ TypeError: no common canonical parent for objects with parents: 'Free Group on generators {x, y}' and 'Integer Ring'
577
+ """
578
+ if len(values) == 1:
579
+ try:
580
+ values = list(values[0])
581
+ except TypeError:
582
+ pass
583
+ G = self.parent()
584
+ if len(values) != G.ngens():
585
+ raise ValueError('number of values has to match the number of generators')
586
+ replace = dict(zip(G.gens(), values))
587
+ new_parent = coercion_model.common_parent(*[parent(v) for v in values])
588
+ try:
589
+ return new_parent.prod(replace[gen] ** power
590
+ for gen, power in self.syllables())
591
+ except AttributeError:
592
+ return prod(new_parent(replace[gen]) ** power
593
+ for gen, power in self.syllables())
594
+
595
+
596
+ def FreeGroup(n=None, names='x', index_set=None, abelian=False, **kwds):
597
+ """
598
+ Construct a Free Group.
599
+
600
+ INPUT:
601
+
602
+ - ``n`` -- integer (default: ``None``); the number of
603
+ generators (if not specified the ``names`` are counted)
604
+
605
+ - ``names`` -- string or list/tuple/iterable of strings (default:
606
+ ``'x'``); the generator names or name prefix
607
+
608
+ - ``index_set`` -- (optional) an index set for the generators; if
609
+ specified then the optional keyword ``abelian`` can be used
610
+
611
+ - ``abelian`` -- boolean (default: ``False``); whether to construct a free
612
+ abelian group or a free group
613
+
614
+ .. NOTE::
615
+
616
+ If you want to create a free group, it is currently preferential to
617
+ use ``Groups().free(...)`` as that does not load GAP.
618
+
619
+ EXAMPLES::
620
+
621
+ sage: G.<a,b> = FreeGroup(); G
622
+ Free Group on generators {a, b}
623
+ sage: H = FreeGroup('a, b')
624
+ sage: G is H
625
+ True
626
+ sage: FreeGroup(0)
627
+ Free Group on generators {}
628
+
629
+ The entry can be either a string with the names of the generators,
630
+ or the number of generators and the prefix of the names to be
631
+ given. The default prefix is ``'x'`` ::
632
+
633
+ sage: FreeGroup(3)
634
+ Free Group on generators {x0, x1, x2}
635
+ sage: FreeGroup(3, 'g')
636
+ Free Group on generators {g0, g1, g2}
637
+ sage: FreeGroup()
638
+ Free Group on generators {x}
639
+
640
+ We give two examples using the ``index_set`` option::
641
+
642
+ sage: FreeGroup(index_set=ZZ) # needs sage.combinat
643
+ Free group indexed by Integer Ring
644
+ sage: FreeGroup(index_set=ZZ, abelian=True) # needs sage.combinat
645
+ Free abelian group indexed by Integer Ring
646
+
647
+ TESTS::
648
+
649
+ sage: G1 = FreeGroup(2, 'a,b')
650
+ sage: G2 = FreeGroup('a,b')
651
+ sage: G3.<a,b> = FreeGroup()
652
+ sage: G1 is G2, G2 is G3
653
+ (True, True)
654
+ """
655
+ # Support Freegroup('a,b') syntax
656
+ if n is not None:
657
+ try:
658
+ n = Integer(n)
659
+ except TypeError:
660
+ names = n
661
+ n = None
662
+ # derive n from counting names
663
+ if n is None:
664
+ if isinstance(names, str):
665
+ n = len(names.split(','))
666
+ else:
667
+ names = list(names)
668
+ n = len(names)
669
+ from sage.structure.category_object import normalize_names
670
+ names = normalize_names(n, names)
671
+ if index_set is not None or abelian:
672
+ if abelian:
673
+ from sage.groups.indexed_free_group import IndexedFreeAbelianGroup
674
+ return IndexedFreeAbelianGroup(index_set, names=names, **kwds)
675
+
676
+ from sage.groups.indexed_free_group import IndexedFreeGroup
677
+ return IndexedFreeGroup(index_set, names=names, **kwds)
678
+ return FreeGroup_class(names, **kwds)
679
+
680
+
681
+ @richcmp_method
682
+ class FreeGroup_class(CachedRepresentation, Group, ParentLibGAP):
683
+ """
684
+ A class that wraps GAP's FreeGroup.
685
+
686
+ See :func:`FreeGroup` for details.
687
+
688
+ TESTS::
689
+
690
+ sage: G = FreeGroup('a, b')
691
+ sage: TestSuite(G).run()
692
+ sage: G.category()
693
+ Category of infinite groups
694
+ """
695
+ Element = FreeGroupElement
696
+
697
+ def __init__(self, generator_names, gap_group=None):
698
+ """
699
+ Python constructor.
700
+
701
+ INPUT:
702
+
703
+ - ``generator_names`` -- tuple of strings; the names of the
704
+ generators
705
+
706
+ - ``libgap_free_group`` -- a LibGAP free group (default: ``None``);
707
+ the LibGAP free group to wrap (if ``None``, a suitable group will be
708
+ constructed)
709
+
710
+ TESTS::
711
+
712
+ sage: G.<a,b> = FreeGroup() # indirect doctest
713
+ sage: G
714
+ Free Group on generators {a, b}
715
+ sage: G.variable_names()
716
+ ('a', 'b')
717
+ """
718
+ if gap_group is None:
719
+ gap_group = libgap.FreeGroup(generator_names)
720
+ ParentLibGAP.__init__(self, gap_group)
721
+ if not generator_names:
722
+ cat = Groups().Finite()
723
+ else:
724
+ cat = Groups().Infinite()
725
+ Group.__init__(self, category=cat)
726
+ self._gen_names = generator_names
727
+ try:
728
+ self._assign_names(generator_names)
729
+ except ValueError:
730
+ pass
731
+
732
+ def __hash__(self):
733
+ """
734
+ Make hashable.
735
+
736
+ EXAMPLES::
737
+
738
+ sage: F = FreeGroup(3)
739
+ sage: F.__hash__() == hash(F._gen_names)
740
+ True
741
+ """
742
+ return hash(self._gen_names)
743
+
744
+ def __richcmp__(self, other, op):
745
+ """
746
+ Rich comparison of ``self`` and ``other``.
747
+
748
+ EXAMPLES::
749
+
750
+ sage: G1 = FreeGroup('a, b')
751
+ sage: gg = libgap.FreeGroup('x', 'y')
752
+ sage: G2 = FreeGroup('a, b', gap_group=gg)
753
+ sage: G1 == G2
754
+ True
755
+ sage: G1 is G2
756
+ False
757
+ sage: G3 = FreeGroup('x, y')
758
+ sage: G1 == G3
759
+ False
760
+ sage: G2 == G3
761
+ False
762
+ """
763
+ if not isinstance(other, self.__class__):
764
+ from sage.structure.richcmp import op_NE
765
+ return (op == op_NE)
766
+ return richcmp(self._gen_names, other._gen_names, op)
767
+
768
+ def _repr_(self):
769
+ """
770
+ TESTS::
771
+
772
+ sage: G = FreeGroup('a, b')
773
+ sage: G # indirect doctest
774
+ Free Group on generators {a, b}
775
+ sage: G._repr_()
776
+ 'Free Group on generators {a, b}'
777
+ """
778
+ return 'Free Group on generators {' + ', '.join(self._gen_names) + '}'
779
+
780
+ def rank(self):
781
+ """
782
+ Return the number of generators of ``self``.
783
+
784
+ Alias for :meth:`ngens`.
785
+
786
+ OUTPUT: integer
787
+
788
+ EXAMPLES::
789
+
790
+ sage: G = FreeGroup('a, b'); G
791
+ Free Group on generators {a, b}
792
+ sage: G.rank()
793
+ 2
794
+ sage: H = FreeGroup(3, 'x')
795
+ sage: H
796
+ Free Group on generators {x0, x1, x2}
797
+ sage: H.rank()
798
+ 3
799
+ """
800
+ return self.ngens()
801
+
802
+ def _gap_init_(self):
803
+ """
804
+ Return the string used to construct the object in gap.
805
+
806
+ EXAMPLES::
807
+
808
+ sage: G = FreeGroup(3)
809
+ sage: G._gap_init_()
810
+ 'FreeGroup(["x0", "x1", "x2"])'
811
+ """
812
+ gap_names = ['"' + s + '"' for s in self._gen_names]
813
+ gen_str = ', '.join(gap_names)
814
+ return 'FreeGroup(['+gen_str+'])'
815
+
816
+ def _element_constructor_(self, *args, **kwds):
817
+ """
818
+ TESTS::
819
+
820
+ sage: G.<a,b> = FreeGroup()
821
+ sage: G([1, 2, 1]) # indirect doctest
822
+ a*b*a
823
+ sage: G([1, 2, -2, 1, 1, -2]) # indirect doctest
824
+ a^3*b^-1
825
+
826
+ sage: G( a.gap() )
827
+ a
828
+ sage: type(_)
829
+ <class 'sage.groups.free_group.FreeGroup_class_with_category.element_class'>
830
+
831
+ Check that conversion between free groups follow the convention that
832
+ names are preserved::
833
+
834
+ sage: F = FreeGroup('a,b')
835
+ sage: G = FreeGroup('b,a')
836
+ sage: G(F.gen(0))
837
+ a
838
+ sage: F(G.gen(0))
839
+ b
840
+ sage: a,b = F.gens()
841
+ sage: G(a^2*b^-3*a^-1)
842
+ a^2*b^-3*a^-1
843
+
844
+ Check that :issue:`17246` is fixed::
845
+
846
+ sage: F = FreeGroup(0)
847
+ sage: F([])
848
+ 1
849
+
850
+ Check that 0 isn't considered the identity::
851
+
852
+ sage: F = FreeGroup('x')
853
+ sage: F(0)
854
+ Traceback (most recent call last):
855
+ ...
856
+ TypeError: 'sage.rings.integer.Integer' object is not iterable
857
+ """
858
+ if len(args) != 1:
859
+ return self.element_class(self, *args, **kwds)
860
+ x = args[0]
861
+ if x == 1 or x == [] or x == ():
862
+ return self.one()
863
+ try:
864
+ P = x.parent()
865
+ except AttributeError:
866
+ return self.element_class(self, x, **kwds)
867
+ if isinstance(P, FreeGroup_class):
868
+ names = {P._gen_names[abs(i)-1] for i in x.Tietze()}
869
+ if names.issubset(self._gen_names):
870
+ return self([i.sign()*(self._gen_names.index(P._gen_names[abs(i)-1])+1)
871
+ for i in x.Tietze()])
872
+ else:
873
+ raise ValueError('generators of %s not in the group' % x)
874
+ return self.element_class(self, x, **kwds)
875
+
876
+ def abelian_invariants(self):
877
+ r"""
878
+ Return the Abelian invariants of ``self``.
879
+
880
+ The Abelian invariants are given by a list of integers
881
+ `i_1 \dots i_j`, such that the abelianization of the
882
+ group is isomorphic to
883
+
884
+ .. MATH::
885
+
886
+ \ZZ / (i_1) \times \dots \times \ZZ / (i_j)
887
+
888
+ EXAMPLES::
889
+
890
+ sage: F.<a,b> = FreeGroup()
891
+ sage: F.abelian_invariants()
892
+ (0, 0)
893
+ """
894
+ return (0,) * self.ngens()
895
+
896
+ def quotient(self, relations, **kwds):
897
+ """
898
+ Return the quotient of ``self`` by the normal subgroup generated
899
+ by the given elements.
900
+
901
+ This quotient is a finitely presented groups with the same
902
+ generators as ``self``, and relations given by the elements of
903
+ ``relations``.
904
+
905
+ INPUT:
906
+
907
+ - ``relations`` -- list/tuple/iterable with the elements of
908
+ the free group
909
+ - further named arguments, that are passed to the constructor
910
+ of a finitely presented group
911
+
912
+ OUTPUT:
913
+
914
+ A finitely presented group, with generators corresponding to
915
+ the generators of the free group, and relations corresponding
916
+ to the elements in ``relations``.
917
+
918
+ EXAMPLES::
919
+
920
+ sage: F.<a,b> = FreeGroup()
921
+ sage: F.quotient([a*b^2*a, b^3])
922
+ Finitely presented group < a, b | a*b^2*a, b^3 >
923
+
924
+ Division is shorthand for :meth:`quotient` ::
925
+
926
+ sage: F / [a*b^2*a, b^3]
927
+ Finitely presented group < a, b | a*b^2*a, b^3 >
928
+
929
+ Relations are converted to the free group, even if they are not
930
+ elements of it (if possible) ::
931
+
932
+ sage: F1.<a,b,c,d> = FreeGroup()
933
+ sage: F2.<a,b> = FreeGroup()
934
+ sage: r = a*b/a
935
+ sage: r.parent()
936
+ Free Group on generators {a, b}
937
+ sage: F1/[r]
938
+ Finitely presented group < a, b, c, d | a*b*a^-1 >
939
+ """
940
+ from sage.groups.finitely_presented import FinitelyPresentedGroup
941
+ return FinitelyPresentedGroup(self,
942
+ tuple(map(self, relations)), **kwds)
943
+
944
+ __truediv__ = quotient