130
130
131
131
from sage .arith .misc import GCD as gcd
132
132
from sage .categories .morphism import SetMorphism
133
- from sage .functions .generalized import sign
134
133
from sage .groups .free_group import FreeGroup
135
134
from sage .groups .free_group import FreeGroupElement
136
135
from sage .groups .group import Group
143
142
from sage .rings .polynomial .laurent_polynomial_ring import LaurentPolynomialRing
144
143
from sage .rings .rational_field import QQ
145
144
from sage .sets .set import Set
146
- from sage .structure .unique_representation import UniqueRepresentation
145
+ from sage .structure .richcmp import richcmp , richcmp_method
146
+ from sage .structure .unique_representation import CachedRepresentation
147
147
148
148
149
149
class GroupMorphismWithGensImages (SetMorphism ):
@@ -362,51 +362,7 @@ def __call__(self, *values, **kwds):
362
362
return super ().__call__ (values )
363
363
364
364
365
- def wrap_FpGroup (libgap_fpgroup ):
366
- """
367
- Wrap a GAP finitely presented group.
368
-
369
- This function changes the comparison method of
370
- ``libgap_free_group`` to comparison by Python ``id``. If you want
371
- to put the LibGAP free group into a container ``(set, dict)`` then you
372
- should understand the implications of
373
- :meth:`~sage.libs.gap.element.GapElement._set_compare_by_id`. To
374
- be safe, it is recommended that you just work with the resulting
375
- Sage :class:`FinitelyPresentedGroup`.
376
-
377
- INPUT:
378
-
379
- - ``libgap_fpgroup`` -- a LibGAP finitely presented group
380
-
381
- OUTPUT: a Sage :class:`FinitelyPresentedGroup`
382
-
383
- EXAMPLES:
384
-
385
- First construct a LibGAP finitely presented group::
386
-
387
- sage: F = libgap.FreeGroup(['a', 'b'])
388
- sage: a_cubed = F.GeneratorsOfGroup()[0] ^ 3
389
- sage: P = F / libgap([ a_cubed ]); P
390
- <fp group of size infinity on the generators [ a, b ]>
391
- sage: type(P)
392
- <class 'sage.libs.gap.element.GapElement'>
393
-
394
- Now wrap it::
395
-
396
- sage: from sage.groups.finitely_presented import wrap_FpGroup
397
- sage: wrap_FpGroup(P)
398
- Finitely presented group < a, b | a^3 >
399
- """
400
- assert libgap_fpgroup .IsFpGroup ()
401
- libgap_fpgroup ._set_compare_by_id ()
402
- from sage .groups .free_group import wrap_FreeGroup
403
- free_group = wrap_FreeGroup (libgap_fpgroup .FreeGroupOfFpGroup ())
404
- relations = tuple (free_group (rel .UnderlyingElement ())
405
- for rel in libgap_fpgroup .RelatorsOfFpGroup ())
406
- return FinitelyPresentedGroup (free_group , relations )
407
-
408
-
409
- class RewritingSystem :
365
+ class RewritingSystem ():
410
366
"""
411
367
A class that wraps GAP's rewriting systems.
412
368
@@ -730,7 +686,8 @@ def make_confluent(self):
730
686
raise ValueError ('could not make the system confluent' )
731
687
732
688
733
- class FinitelyPresentedGroup (GroupMixinLibGAP , UniqueRepresentation , Group , ParentLibGAP ):
689
+ @richcmp_method
690
+ class FinitelyPresentedGroup (GroupMixinLibGAP , CachedRepresentation , Group , ParentLibGAP ):
734
691
"""
735
692
A class that wraps GAP's Finitely Presented Groups.
736
693
@@ -739,7 +696,9 @@ class FinitelyPresentedGroup(GroupMixinLibGAP, UniqueRepresentation, Group, Pare
739
696
You should use
740
697
:meth:`~sage.groups.free_group.FreeGroup_class.quotient` to
741
698
construct finitely presented groups as quotients of free
742
- groups.
699
+ groups. Any class inheriting this one should define
700
+ ``__reduce__ = CachedRepresentation.__reduce__``
701
+ after importing ``CachedRepresentation``.
743
702
744
703
EXAMPLES::
745
704
@@ -770,7 +729,7 @@ class FinitelyPresentedGroup(GroupMixinLibGAP, UniqueRepresentation, Group, Pare
770
729
"""
771
730
Element = FinitelyPresentedGroupElement
772
731
773
- def __init__ (self , free_group , relations , category = None ):
732
+ def __init__ (self , free_group , relations , category = None , libgap_fpgroup = None ):
774
733
"""
775
734
The Python constructor.
776
735
@@ -786,6 +745,25 @@ def __init__(self, free_group, relations, category=None):
786
745
sage: J is H
787
746
True
788
747
748
+ sage: A5 = libgap(AlternatingGroup(5))
749
+ sage: A5gapfp = A5.IsomorphismFpGroup().Range()
750
+ sage: A5gapfp
751
+ <fp group of size 60 on the generators [ A_5.1, A_5.2 ]>
752
+ sage: A5sage = A5gapfp.sage(); A5sage;
753
+ Finitely presented group < A_5.1, A_5.2 | A_5.1^5*A_5.2^-5, A_5.1^5*(A_5.2^-1*A_5.1^-1)^2, (A_5.1^-2*A_5.2^2)^2 >
754
+ sage: A5sage.inject_variables()
755
+ Traceback (most recent call last):
756
+ ...
757
+ ValueError: variable names have not yet been set using self._assign_names(...)
758
+
759
+ Check that pickling works::
760
+
761
+ sage: G = FreeGroup(2) / [2 * (1, 2, -1, -2)]
762
+ sage: loads(dumps(G))
763
+ Finitely presented group < x0, x1 | (x0*x1*x0^-1*x1^-1)^2 >
764
+ sage: G.__reduce__()[1][1]
765
+ (Free Group on generators {x0, x1}, ((x0*x1*x0^-1*x1^-1)^2,))
766
+
789
767
sage: TestSuite(H).run()
790
768
sage: TestSuite(J).run()
791
769
"""
@@ -794,11 +772,47 @@ def __init__(self, free_group, relations, category=None):
794
772
assert isinstance (relations , tuple )
795
773
self ._free_group = free_group
796
774
self ._relations = relations
797
- self ._assign_names (free_group .variable_names ())
798
- parent_gap = free_group .gap () / libgap ([rel .gap () for rel in relations ])
799
- ParentLibGAP .__init__ (self , parent_gap )
775
+ try :
776
+ self ._assign_names (free_group .variable_names ())
777
+ except ValueError :
778
+ pass
779
+ if libgap_fpgroup is None :
780
+ libgap_fpgroup = free_group .gap () / libgap ([rel .gap () for rel in relations ])
781
+ ParentLibGAP .__init__ (self , libgap_fpgroup )
800
782
Group .__init__ (self , category = category )
801
783
784
+ def __hash__ (self ):
785
+ """
786
+ Make hashable.
787
+
788
+ EXAMPLES::
789
+
790
+ sage: G = FreeGroup(2) / [(1, 2, 2, 1)]
791
+ sage: G.__hash__() == hash((G.free_group(), G.relations()))
792
+ True
793
+ """
794
+ return hash ((self ._free_group , self ._relations ))
795
+
796
+ def __richcmp__ (self , other , op ):
797
+ """
798
+ Rich comparison of ``self`` and ``other``.
799
+
800
+ EXAMPLES::
801
+
802
+ sage: G1 = FreeGroup(2) / [(1, 2, 2, 1, 2, 1)]
803
+ sage: G2 = libgap(G1).sage()
804
+ sage: G1 == G2
805
+ True
806
+ sage: G1 is G2
807
+ False
808
+ """
809
+ if not isinstance (other , self .__class__ ):
810
+ from sage .structure .richcmp import op_NE
811
+ return (op == op_NE )
812
+ self_data = (self ._free_group , self ._relations )
813
+ other_data = (other ._free_group , other ._relations )
814
+ return richcmp (self_data , other_data , op )
815
+
802
816
def _repr_ (self ) -> str :
803
817
"""
804
818
Return a string representation.
@@ -812,7 +826,7 @@ def _repr_(self) -> str:
812
826
sage: H._repr_()
813
827
'Finitely presented group < a, b | a, b^3 >'
814
828
"""
815
- gens = ', ' .join (self .variable_names () )
829
+ gens = ', ' .join (self ._free_group . _gen_names )
816
830
rels = ', ' .join (str (r ) for r in self .relations ())
817
831
return 'Finitely presented group ' + '< ' + gens + ' | ' + rels + ' >'
818
832
@@ -1357,15 +1371,15 @@ def abelianization_map(self):
1357
1371
hom_ab_fp = ab_libgap .IsomorphismFpGroup ()
1358
1372
ab_libgap_fp = hom_ab_fp .Range ()
1359
1373
hom_simply = ab_libgap_fp .IsomorphismSimplifiedFpGroup ()
1360
- ab = wrap_FpGroup ( hom_simply .Range ())
1374
+ ab = hom_simply .Range (). sage ( )
1361
1375
images = []
1362
1376
for f in self .gens ():
1363
1377
f0 = hom_ab_libgap .Image (f )
1364
1378
f1 = hom_ab_fp .Image (f0 )
1365
1379
f2 = hom_simply .Image (f1 )
1366
1380
L = f2 .UnderlyingElement ().LetterRepAssocWord ()
1367
1381
images .append (ab ([int (j ) for j in L ]))
1368
- return self .hom (codomain = ab , im_gens = images )
1382
+ return self .hom (codomain = ab , im_gens = images , check = False )
1369
1383
1370
1384
@cached_method
1371
1385
def abelianization_to_algebra (self , ring = QQ ):
@@ -1438,12 +1452,9 @@ def simplification_isomorphism(self):
1438
1452
sage: H = G / [a*b*c, a*b^2, c*b/c^2]
1439
1453
sage: I = H.simplification_isomorphism()
1440
1454
sage: I
1441
- Generic morphism:
1455
+ Group morphism:
1442
1456
From: Finitely presented group < a, b, c | a*b*c, a*b^2, c*b*c^-2 >
1443
1457
To: Finitely presented group < b | >
1444
- Defn: a |--> b^-2
1445
- b |--> b
1446
- c |--> b
1447
1458
sage: I(a)
1448
1459
b^-2
1449
1460
sage: I(b)
@@ -1455,21 +1466,26 @@ def simplification_isomorphism(self):
1455
1466
1456
1467
sage: F = FreeGroup(1)
1457
1468
sage: G = F.quotient([F.0])
1458
- sage: G.simplification_isomorphism()
1459
- Generic morphism:
1469
+ sage: h = G.simplification_isomorphism(); h
1470
+ Group morphism:
1460
1471
From: Finitely presented group < x | x >
1461
1472
To: Finitely presented group < | >
1462
- Defn: x |--> 1
1473
+ sage: h(G.gen(0))
1474
+ 1
1463
1475
1464
1476
ALGORITHM:
1465
1477
1466
1478
Uses GAP.
1467
1479
"""
1468
1480
II = self .gap ().IsomorphismSimplifiedFpGroup ()
1469
- codomain = wrap_FpGroup (II .Range ())
1470
- phi = lambda x : codomain (II .ImageElm (x .gap ()))
1471
- HS = self .Hom (codomain )
1472
- return GroupMorphismWithGensImages (HS , phi )
1481
+ cod = II .Range ().sage ()
1482
+ phi = [cod (II .ImageElm (x )) for x in self .gap ().GeneratorsOfGroup ()]
1483
+ return self .hom (codomain = cod , im_gens = phi , check = False )
1484
+ # II = self.gap().IsomorphismSimplifiedFpGroup()
1485
+ # codomain = II.Range().sage()
1486
+ # phi = lambda x: codomain(II.ImageElm(x.gap()))
1487
+ # HS = self.Hom(codomain)
1488
+ # return GroupMorphismWithGensImages(HS, phi)
1473
1489
1474
1490
def simplified (self ):
1475
1491
"""
@@ -1543,48 +1559,44 @@ def epimorphisms(self, H):
1543
1559
sage: F = FreeGroup(3)
1544
1560
sage: G = F / [F([1, 2, 3, 1, 2, 3]), F([1, 1, 1])]
1545
1561
sage: H = AlternatingGroup(3)
1546
- sage: G.epimorphisms(H)
1547
- [Generic morphism:
1548
- From: Finitely presented group < x0, x1, x2 | x0*x1*x2*x0*x1*x2, x0^3 >
1549
- To: Alternating group of order 3!/2 as a permutation group
1550
- Defn: x0 |--> ()
1551
- x1 |--> (1,3,2)
1552
- x2 |--> (1,2,3),
1553
- Generic morphism:
1554
- From: Finitely presented group < x0, x1, x2 | x0*x1*x2*x0*x1*x2, x0^3 >
1555
- To: Alternating group of order 3!/2 as a permutation group
1556
- Defn: x0 |--> (1,3,2)
1557
- x1 |--> ()
1558
- x2 |--> (1,2,3),
1559
- Generic morphism:
1560
- From: Finitely presented group < x0, x1, x2 | x0*x1*x2*x0*x1*x2, x0^3 >
1561
- To: Alternating group of order 3!/2 as a permutation group
1562
- Defn: x0 |--> (1,3,2)
1563
- x1 |--> (1,2,3)
1564
- x2 |--> (),
1565
- Generic morphism:
1566
- From: Finitely presented group < x0, x1, x2 | x0*x1*x2*x0*x1*x2, x0^3 >
1567
- To: Alternating group of order 3!/2 as a permutation group
1568
- Defn: x0 |--> (1,2,3)
1569
- x1 |--> (1,2,3)
1570
- x2 |--> (1,2,3)]
1562
+ sage: for quo in G.epimorphisms(H):
1563
+ ....: for a in G.gens():
1564
+ ....: print(a, "|-->", quo(a))
1565
+ ....: print("-----")
1566
+ x0 |--> ()
1567
+ x1 |--> (1,3,2)
1568
+ x2 |--> (1,2,3)
1569
+ -----
1570
+ x0 |--> (1,3,2)
1571
+ x1 |--> ()
1572
+ x2 |--> (1,2,3)
1573
+ -----
1574
+ x0 |--> (1,3,2)
1575
+ x1 |--> (1,2,3)
1576
+ x2 |--> ()
1577
+ -----
1578
+ x0 |--> (1,2,3)
1579
+ x1 |--> (1,2,3)
1580
+ x2 |--> (1,2,3)
1581
+ -----
1571
1582
1572
1583
ALGORITHM:
1573
1584
1574
1585
Uses libgap's GQuotients function.
1575
1586
"""
1576
- from sage .misc .misc_c import prod
1577
- HomSpace = self .Hom (H )
1587
+ # from sage.misc.misc_c import prod
1588
+ # HomSpace = self.Hom(H)
1578
1589
Gg = libgap (self )
1579
1590
Hg = libgap (H )
1580
1591
gquotients = Gg .GQuotients (Hg )
1581
1592
res = []
1582
1593
# the following closure is needed to attach a specific value of quo to
1583
1594
# each function in the different morphisms
1584
- fmap = lambda tup : (lambda a : H (prod (tup [abs (i )- 1 ]** sign (i ) for i in a .Tietze ())))
1595
+ # fmap = lambda tup: (lambda a: H(prod(tup[abs(i)-1]**sign(i) for i in a.Tietze())))
1585
1596
for quo in gquotients :
1586
- tup = tuple (H (quo .ImageElm (i .gap ()).sage ()) for i in self .gens ())
1587
- fhom = GroupMorphismWithGensImages (HomSpace , fmap (tup ))
1597
+ # tup = tuple(H(quo.ImageElm(i.gap()).sage()) for i in self.gens())
1598
+ # fhom = GroupMorphismWithGensImages(HomSpace, fmap(tup))
1599
+ fhom = self .hom (codomain = H , im_gens = [H (quo .ImageElm (a .gap ())) for a in self .gens ()])
1588
1600
res .append (fhom )
1589
1601
return res
1590
1602
0 commit comments