Path: blob/master/src/sage/groups/finitely_presented.py
8814 views
"""1Finitely Presented Groups23Finitely presented groups are constructed as quotients of4:mod:`~sage.groups.free_group`::56sage: F.<a,b,c> = FreeGroup()7sage: G = F / [a^2, b^2, c^2, a*b*c*a*b*c]8sage: G9Finitely presented group < a, b, c | a^2, b^2, c^2, (a*b*c)^2 >1011One can create their elements by mutiplying the generators or by12specifying a Tietze list (see13:meth:`~sage.groups.finitely_presented.FinitelyPresentedGroupElement.Tietze`)14as in the case of free groups::1516sage: G.gen(0) * G.gen(1)17a*b18sage: G([1,2,-1])19a*b*a^-120sage: a.parent()21Free Group on generators {a, b, c}22sage: G.inject_variables()23Defining a, b, c24sage: a.parent()25Finitely presented group < a, b, c | a^2, b^2, c^2, (a*b*c)^2 >2627Notice that, even if they are represented in the same way, the28elements of a finitely presented group and the elements of the29corresponding free group are not the same thing. However, they can be30converted from one parent to the other::3132sage: F.<a,b,c> = FreeGroup()33sage: G = F / [a^2,b^2,c^2,a*b*c*a*b*c]34sage: F([1])35a36sage: G([1])37a38sage: F([1]) is G([1])39False40sage: F([1]) == G([1])41False42sage: G(a*b/c)43a*b*c^-144sage: F(G(a*b/c))45a*b*c^-14647Finitely presented groups are implemented via GAP. You can use the48:meth:`~sage.groups.libgap_wrapper.ParentLibGAP.gap` method to access49the underlying LibGAP object::5051sage: G = FreeGroup(2)52sage: G.inject_variables()53Defining x0, x154sage: H = G / (x0^2, (x0*x1)^2, x1^2)55sage: H.gap()56<fp group on the generators [ x0, x1 ]>5758This can be useful, for example, to use GAP functions that are not yet59wrapped in Sage::6061sage: H.gap().LowerCentralSeries()62[ Group(<fp, no generators known>), Group(<fp, no generators known>) ]6364The same holds for the group elements::6566sage: G = FreeGroup(2)67sage: H = G / (G([1, 1]), G([2, 2, 2]), G([1, 2, -1, -2])); H68Finitely presented group < x0, x1 | x0^2, x1^3, x0*x1*x0^-1*x1^-1 >69sage: a = H([1])70sage: a71x072sage: a.gap()73x074sage: a.gap().Order()75276sage: type(_) # note that the above output is not a Sage integer77<type 'sage.libs.gap.element.GapElement_Integer'>7879You can use call syntax to replace the generators with a set of80arbitrary ring elements. For example, take the free abelian group81obtained by modding out the commutator subgroup of the free group::8283sage: G = FreeGroup(2)84sage: G_ab = G / [G([1, 2, -1, -2])]; G_ab85Finitely presented group < x0, x1 | x0*x1*x0^-1*x1^-1 >86sage: a,b = G_ab.gens()87sage: g = a * b88sage: M1 = matrix([[1,0],[0,2]])89sage: M2 = matrix([[0,1],[1,0]])90sage: g(3, 5)911592sage: g(M1, M1)93[1 0]94[0 4]95sage: M1*M2 == M2*M1 # matrices do not commute96False97sage: g(M1, M2)98Traceback (most recent call last):99...100ValueError: the values do not satisfy all relations of the group101102.. WARNING::103104Some methods are not guaranteed to finish since the word problem105for finitely presented groups is, in general, undecidable. In106those cases the process may run unil the available memory is107exhausted.108109REFERENCES:110111- :wikipedia:`Presentation_of_a_group`112113- :wikipedia:`Word_problem_for_groups`114115AUTHOR:116117- Miguel Angel Marco Buzunariz118"""119120##############################################################################121# Copyright (C) 2012 Miguel Angel Marco Buzunariz <[email protected]>122#123# Distributed under the terms of the GNU General Public License (GPL)124#125# The full text of the GPL is available at:126#127# http://www.gnu.org/licenses/128##############################################################################129130131from sage.groups.group import Group132from sage.groups.libgap_wrapper import ParentLibGAP, ElementLibGAP133from sage.groups.libgap_mixin import GroupMixinLibGAP134from sage.structure.unique_representation import UniqueRepresentation135from sage.libs.gap.libgap import libgap136from sage.libs.gap.element import GapElement137from sage.rings.integer import Integer138from sage.rings.integer_ring import IntegerRing139from sage.misc.cachefunc import cached_method140from sage.groups.free_group import FreeGroupElement141142from sage.structure.element import Element, MultiplicativeGroupElement143from sage.interfaces.gap import gap144from sage.rings.integer import Integer145from sage.rings.integer_ring import IntegerRing146from sage.functions.generalized import sign147from sage.matrix.constructor import matrix148149class FinitelyPresentedGroupElement(FreeGroupElement):150"""151A wrapper of GAP's Finitely Presented Group elements.152153The elements are created by passing the Tietze list that determines them.154155EXAMPLES::156157sage: G = FreeGroup('a, b')158sage: H = G / [G([1]), G([2, 2, 2])]159sage: H([1, 2, 1, -1])160a*b161sage: H([1, 2, 1, -2])162a*b*a*b^-1163sage: x = H([1, 2, -1, -2])164sage: x165a*b*a^-1*b^-1166sage: y = H([2, 2, 2, 1, -2, -2, -2])167sage: y168b^3*a*b^-3169sage: x*y170a*b*a^-1*b^2*a*b^-3171sage: x^(-1)172b*a*b^-1*a^-1173"""174175def __init__(self, parent, x, check=True):176"""177The Python constructor.178179See :class:`FinitelyPresentedGroupElement` for details.180181TESTS::182183sage: G = FreeGroup('a, b')184sage: H = G / [G([1]), G([2, 2, 2])]185sage: H([1, 2, 1, -1])186a*b187188sage: TestSuite(G).run()189sage: TestSuite(H).run()190191sage: G.<a,b> = FreeGroup()192sage: H = G / (G([1]), G([2, 2, 2]))193sage: x = H([1, 2, -1, -2])194sage: TestSuite(x).run()195sage: TestSuite(G.one()).run()196"""197if not isinstance(x, GapElement):198F = parent.free_group()199free_element = F(x)200fp_family = parent.one().gap().FamilyObj()201x = libgap.ElementOfFpGroup(fp_family, free_element.gap())202ElementLibGAP.__init__(self, parent, x)203204def __reduce__(self):205"""206Used in pickling.207208TESTS::209210sage: F.<a,b> = FreeGroup()211sage: G = F / [a*b, a^2]212sage: G.inject_variables()213Defining a, b214sage: a.__reduce__()215(Finitely presented group < a, b | a*b, a^2 >, ((1,),))216sage: (a*b*a^-1).__reduce__()217(Finitely presented group < a, b | a*b, a^2 >, ((1, 2, -1),))218219sage: F.<a,b,c> = FreeGroup('a, b, c')220sage: G = F.quotient([a*b*c/(b*c*a), a*b*c/(c*a*b)])221sage: G.__reduce__()222(<class 'sage.groups.finitely_presented.FinitelyPresentedGroup'>,223(Free Group on generators {a, b, c},224(a*b*c*a^-1*c^-1*b^-1, a*b*c*b^-1*a^-1*c^-1)))225sage: G.inject_variables()226Defining a, b, c227sage: x = a*b*c228sage: x.__reduce__()229(Finitely presented group < a, b, c | a*b*c*a^-1*c^-1*b^-1, a*b*c*b^-1*a^-1*c^-1 >,230((1, 2, 3),))231"""232return (self.parent(), tuple([self.Tietze()]))233234def _repr_(self):235"""236Return a string representation.237238OUTPUT:239240String.241242EXAMPLES::243244sage: G.<a,b> = FreeGroup()245sage: H = G / [a^2, b^3]246sage: H.gen(0)247a248sage: H.gen(0)._repr_()249'a'250sage: H.one()2511252"""253# computing that an element is actually one can be very expensive254if self.Tietze() == ():255return '1'256else:257return self.gap()._repr_()258259@cached_method260def Tietze(self):261"""262Return the Tietze list of the element.263264The Tietze list of a word is a list of integers that represent265the letters in the word. A positive integer `i` represents266the letter corresponding to the `i`-th generator of the group.267Negative integers represent the inverses of generators.268269OUTPUT:270271A tuple of integers.272273EXAMPLES::274275sage: G = FreeGroup('a, b')276sage: H = G / (G([1]), G([2, 2, 2]))277sage: H.inject_variables()278Defining a, b279sage: a.Tietze()280(1,)281sage: x = a^2*b^(-3)*a^(-2)282sage: x.Tietze()283(1, 1, -2, -2, -2, -1, -1)284"""285tl = self.gap().UnderlyingElement().TietzeWordAbstractWord()286return tuple(tl.sage())287288def __call__(self, *values, **kwds):289"""290Replace the generators of the free group with ``values``.291292INPUT:293294- ``*values`` -- a list/tuple/iterable of the same length as295the number of generators.296297- ``check=True`` -- boolean keyword (default:298``True``). Whether to verify that ``values`` satisfy the299relations in the finitely presented group.300301OUTPUT:302303The product of ``values`` in the order and with exponents304specified by ``self``.305306EXAMPLES::307308sage: G.<a,b> = FreeGroup()309sage: H = G / [a/b]; H310Finitely presented group < a, b | a*b^-1 >311sage: H.simplified()312Finitely presented group < a | >313314The generator `b` can be eliminated using the relation `a=b`. Any315values that you plug into a word must satisfy this relation::316317sage: A, B = H.gens()318sage: w = A^2 * B319sage: w(2,2)3208321sage: w(3,3)32227323sage: w(1,2)324Traceback (most recent call last):325...326ValueError: the values do not satisfy all relations of the group327sage: w(1, 2, check=False) # result depends on presentation of the group element3282329"""330values = list(values)331if kwds.get('check', True):332for rel in self.parent().relations():333rel = rel(values)334if rel != 1:335raise ValueError('the values do not satisfy all relations of the group')336return super(FinitelyPresentedGroupElement, self).__call__(values)337338339def wrap_FpGroup(libgap_fpgroup):340"""341Wrap a GAP finitely presented group.342343This function changes the comparison method of344``libgap_free_group`` to comparison by Python ``id``. If you want345to put the LibGAP free group into a container ``(set, dict)`` then you346should understand the implications of347:meth:`~sage.libs.gap.element.GapElement._set_compare_by_id`. To348be safe, it is recommended that you just work with the resulting349Sage :class:`FinitelyPresentedGroup`.350351INPUT:352353- ``libgap_fpgroup`` -- a LibGAP finitely presented group354355OUTPUT:356357A Sage :class:`FinitelyPresentedGroup`.358359EXAMPLES:360361First construct a LibGAP finitely presented group::362363sage: F = libgap.FreeGroup(['a', 'b'])364sage: a_cubed = F.GeneratorsOfGroup()[0] ^ 3365sage: P = F / libgap([ a_cubed ]); P366<fp group of size infinity on the generators [ a, b ]>367sage: type(P)368<type 'sage.libs.gap.element.GapElement'>369370Now wrap it::371372sage: from sage.groups.finitely_presented import wrap_FpGroup373sage: wrap_FpGroup(P)374Finitely presented group < a, b | a^3 >375"""376assert libgap_fpgroup.IsFpGroup()377libgap_fpgroup._set_compare_by_id()378from sage.groups.free_group import wrap_FreeGroup379free_group = wrap_FreeGroup(libgap_fpgroup.FreeGroupOfFpGroup())380relations = tuple( free_group(rel.UnderlyingElement())381for rel in libgap_fpgroup.RelatorsOfFpGroup() )382return FinitelyPresentedGroup(free_group, relations)383384385class RewritingSystem(object):386"""387A class that wraps GAP's rewriting systems.388389A rewriting system is a set of rules that allow to transform390one word in the group to an equivalent one.391392If the rewriting system is confluent, then the transformated393word is a unique reduced form of the element of the group.394395.. WARNING::396397Note that the process of making a rewriting system confluent398might not end.399400INPUT:401402- ``G`` -- a group403404REFERENCES:405406- :wikipedia:`Knuth-Bendix_completion_algorithm`407408EXAMPLES::409410sage: F.<a,b> = FreeGroup()411sage: G = F / [a*b/a/b]412sage: k = G.rewriting_system()413sage: k414Rewriting system of Finitely presented group < a, b | a*b*a^-1*b^-1 >415with rules:416a*b*a^-1*b^-1 ---> 1417418sage: k.reduce(a*b*a*b)419(a*b)^2420sage: k.make_confluent()421sage: k422Rewriting system of Finitely presented group < a, b | a*b*a^-1*b^-1 >423with rules:424b^-1*a^-1 ---> a^-1*b^-1425b^-1*a ---> a*b^-1426b*a^-1 ---> a^-1*b427b*a ---> a*b428429sage: k.reduce(a*b*a*b)430a^2*b^2431432.. TODO::433434- Include support for different orderings (currently only shortlex435is used).436437- Include the GAP package kbmag for more functionalities, including438automatic structures and faster compiled functions.439440AUTHORS:441442- Miguel Angel Marco Buzunariz (2013-12-16)443"""444def __init__(self, G):445"""446Initialize ``self``.447448EXAMPLES::449450sage: F.<a,b,c> = FreeGroup()451sage: G = F / [a^2, b^3, c^5]452sage: k = G.rewriting_system()453sage: k454Rewriting system of Finitely presented group < a, b, c | a^2, b^3, c^5 >455with rules:456a^2 ---> 1457b^3 ---> 1458c^5 ---> 1459"""460self._free_group = G.free_group()461self._fp_group = G462self._fp_group_gap = G.gap()463self._monoid_isomorphism = self._fp_group_gap.IsomorphismFpMonoid()464self._monoid = self._monoid_isomorphism.Image()465self._gap = self._monoid.KnuthBendixRewritingSystem()466467def __repr__(self):468"""469Return a string representation.470471EXAMPLES::472473sage: F.<a> = FreeGroup()474sage: G = F / [a^2]475sage: k = G.rewriting_system()476sage: k477Rewriting system of Finitely presented group < a | a^2 >478with rules:479a^2 ---> 1480"""481ret = "Rewriting system of {}\nwith rules:".format(self._fp_group)482for i in sorted(self.rules().items()): # Make sure they are sorted to the repr is unique483ret += "\n {} ---> {}".format(i[0], i[1])484return ret485486def free_group(self):487"""488The free group after which the rewriting system is defined489490EXAMPLES::491492sage: F = FreeGroup(3)493sage: G = F / [ [1,2,3], [-1,-2,-3] ]494sage: k = G.rewriting_system()495sage: k.free_group()496Free Group on generators {x0, x1, x2}497"""498return self._free_group499500def finitely_presented_group(self):501"""502The finitely presented group where the rewriting system is defined.503504EXAMPLES::505506sage: F = FreeGroup(3)507sage: G = F / [ [1,2,3], [-1,-2,-3], [1,1], [2,2] ]508sage: k = G.rewriting_system()509sage: k.make_confluent()510sage: k511Rewriting system of Finitely presented group < x0, x1, x2 | x0*x1*x2, x0^-1*x1^-1*x2^-1, x0^2, x1^2 >512with rules:513x0^-1 ---> x0514x1^-1 ---> x1515x2^-1 ---> x2516x0^2 ---> 1517x0*x1 ---> x2518x0*x2 ---> x1519x1*x0 ---> x2520x1^2 ---> 1521x1*x2 ---> x0522x2*x0 ---> x1523x2*x1 ---> x0524x2^2 ---> 1525sage: k.finitely_presented_group()526Finitely presented group < x0, x1, x2 | x0*x1*x2, x0^-1*x1^-1*x2^-1, x0^2, x1^2 >527"""528return self._fp_group529530def reduce(self, element):531"""532Applies the rules in the rewriting system to the element, to obtain533a reduced form.534535If the rewriting system is confluent, this reduced form is unique536for all words representing the same element.537538EXAMPLES::539540sage: F.<a,b> = FreeGroup()541sage: G = F/[a^2, b^3, (a*b/a)^3, b*a*b*a]542sage: k = G.rewriting_system()543sage: k.reduce(b^4)544b545sage: k.reduce(a*b*a)546a*b*a547"""548eg = self._fp_group(element).gap()549egim = self._monoid_isomorphism.Image(eg)550red = self.gap().ReducedForm(egim.UnderlyingElement())551redfpmon = self._monoid.One().FamilyObj().ElementOfFpMonoid(red)552reducfpgr = self._monoid_isomorphism.PreImagesRepresentative(redfpmon)553tz = reducfpgr.UnderlyingElement().TietzeWordAbstractWord(self._free_group.gap().GeneratorsOfGroup())554return self._fp_group(tz.sage())555556def gap(self):557"""558The gap representation of the rewriting system.559560EXAMPLES::561562sage: F.<a,b>=FreeGroup()563sage: G=F/[a*a,b*b]564sage: k=G.rewriting_system()565sage: k.gap()566Knuth Bendix Rewriting System for Monoid( [ a, A, b, B ], ... ) with rules567[ [ a^2, <identity ...> ], [ a*A, <identity ...> ],568[ A*a, <identity ...> ], [ b^2, <identity ...> ],569[ b*B, <identity ...> ], [ B*b, <identity ...> ] ]570"""571return self._gap572573def rules(self):574"""575Return the rules that form the rewritig system.576577OUTPUT:578579A dictionary containing the rules of the rewriting system.580Each key is a word in the free group, and its corresponding581value is the word to which it is reduced.582583EXAMPLES::584585sage: F.<a,b> = FreeGroup()586sage: G = F / [a*a*a,b*b*a*a]587sage: k = G.rewriting_system()588sage: k589Rewriting system of Finitely presented group < a, b | a^3, b^2*a^2 >590with rules:591a^3 ---> 1592b^2*a^2 ---> 1593594sage: k.rules()595{b^2*a^2: 1, a^3: 1}596sage: k.make_confluent()597sage: sorted(k.rules().items())598[(a^-2, a), (a^-1*b^-1, a*b), (a^-1*b, b^-1), (a^2, a^-1),599(a*b^-1, b), (b^-1*a^-1, a*b), (b^-1*a, b), (b^-2, a^-1),600(b*a^-1, b^-1), (b*a, a*b), (b^2, a)]601"""602dic = {}603grules = self.gap().Rules()604for i in grules:605a, b = i606afpmon = self._monoid.One().FamilyObj().ElementOfFpMonoid(a)607afg = self._monoid_isomorphism.PreImagesRepresentative(afpmon)608atz = afg.UnderlyingElement().TietzeWordAbstractWord(self._free_group.gap().GeneratorsOfGroup())609af = self._free_group(atz.sage())610if len(af.Tietze()) != 0:611bfpmon = self._monoid.One().FamilyObj().ElementOfFpMonoid(b)612bfg = self._monoid_isomorphism.PreImagesRepresentative(bfpmon)613btz = bfg.UnderlyingElement().TietzeWordAbstractWord(self._free_group.gap().GeneratorsOfGroup())614bf = self._free_group(btz.sage())615dic[af]=bf616return dic617618def is_confluent(self):619"""620Return ``True`` if the system is confluent and ``False`` otherwise.621622EXAMPLES::623624sage: F = FreeGroup(3)625sage: G = F / [F([1,2,1,2,1,3,-1]),F([2,2,2,1,1,2]),F([1,2,3])]626sage: k = G.rewriting_system()627sage: k.is_confluent()628False629sage: k630Rewriting system of Finitely presented group < x0, x1, x2 | (x0*x1)^2*x0*x2*x0^-1, x1^3*x0^2*x1, x0*x1*x2 >631with rules:632x0*x1*x2 ---> 1633x1^3*x0^2*x1 ---> 1634(x0*x1)^2*x0*x2*x0^-1 ---> 1635636sage: k.make_confluent()637sage: k.is_confluent()638True639sage: k640Rewriting system of Finitely presented group < x0, x1, x2 | (x0*x1)^2*x0*x2*x0^-1, x1^3*x0^2*x1, x0*x1*x2 >641with rules:642x0^-1 ---> x0643x1^-1 ---> x1644x0^2 ---> 1645x0*x1 ---> x2^-1646x0*x2^-1 ---> x1647x1*x0 ---> x2648x1^2 ---> 1649x1*x2^-1 ---> x0*x2650x1*x2 ---> x0651x2^-1*x0 ---> x0*x2652x2^-1*x1 ---> x0653x2^-2 ---> x2654x2*x0 ---> x1655x2*x1 ---> x0*x2656x2^2 ---> x2^-1657"""658return self._gap.IsConfluent().sage()659660def make_confluent(self):661"""662Applies Knuth-Bendix algorithm to try to transform the rewriting663system into a confluent one.664665Note that this method does not return any object, just changes the666rewriting sytem internally.667668.. WARNING:669670This algorithm is not granted to finish. Although it may be useful671in some occasions to run it, interrupt it manually after some time672and use then the transformed rewriting system. Even if it is not673confluent, it could be used to reduce some words.674675ALGORITHM:676677Uses GAP's ``MakeConfluent``.678679EXAMPLES::680681sage: F.<a,b> = FreeGroup()682sage: G = F / [a^2,b^3,(a*b/a)^3,b*a*b*a]683sage: k = G.rewriting_system()684sage: k685Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, (b*a)^2 >686with rules:687a^2 ---> 1688b^3 ---> 1689(b*a)^2 ---> 1690a*b^3*a^-1 ---> 1691692sage: k.make_confluent()693sage: k694Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, (b*a)^2 >695with rules:696a^-1 ---> a697a^2 ---> 1698b^-1*a ---> a*b699b^-2 ---> b700b*a ---> a*b^-1701b^2 ---> b^-1702"""703try:704self._gap.MakeConfluent()705except ValueError:706raise ValueError('could not make the system confluent')707708class FinitelyPresentedGroup(GroupMixinLibGAP, UniqueRepresentation,709Group, ParentLibGAP):710"""711A class that wraps GAP's Finitely Presented Groups.712713.. WARNING::714715You should use716:meth:`~sage.groups.free_group.FreeGroup_class.quotient` to717construct finitely presented groups as quotients of free718groups.719720EXAMPLES::721722sage: G.<a,b> = FreeGroup()723sage: H = G / [a, b^3]724sage: H725Finitely presented group < a, b | a, b^3 >726sage: H.gens()727(a, b)728729sage: F.<a,b> = FreeGroup('a, b')730sage: J = F / (F([1]), F([2, 2, 2]))731sage: J is H732True733734sage: G = FreeGroup(2)735sage: H = G / (G([1, 1]), G([2, 2, 2]))736sage: H.gens()737(x0, x1)738sage: H.gen(0)739x0740sage: H.ngens()7412742sage: H.gap()743<fp group on the generators [ x0, x1 ]>744sage: type(_)745<type 'sage.libs.gap.element.GapElement'>746"""747Element = FinitelyPresentedGroupElement748749def __init__(self, free_group, relations):750"""751The Python constructor.752753TESTS::754755sage: G = FreeGroup('a, b')756sage: H = G / (G([1]), G([2])^3)757sage: H758Finitely presented group < a, b | a, b^3 >759760sage: F = FreeGroup('a, b')761sage: J = F / (F([1]), F([2, 2, 2]))762sage: J is H763True764765sage: TestSuite(H).run()766sage: TestSuite(J).run()767"""768from sage.groups.free_group import is_FreeGroup769assert is_FreeGroup(free_group)770assert isinstance(relations, tuple)771self._free_group = free_group772self._relations = relations773self._assign_names(free_group.variable_names())774parent_gap = free_group.gap() / libgap([ rel.gap() for rel in relations])775ParentLibGAP.__init__(self, parent_gap)776Group.__init__(self)777778def __reduce__(self):779"""780Used in pickling.781782TESTS::783784sage: F = FreeGroup(4)785sage: F.inject_variables()786Defining x0, x1, x2, x3787sage: G = F.quotient([x0*x2, x3*x1*x3, x2*x1*x2])788sage: G.__reduce__()789(<class 'sage.groups.finitely_presented.FinitelyPresentedGroup'>,790(Free Group on generators {x0, x1, x2, x3},791(x0*x2, x3*x1*x3, x2*x1*x2)))792793sage: F.<a,b,c> = FreeGroup()794sage: F.inject_variables()795Defining a, b, c796sage: G = F / [a*b*c/(b*c*a), a*b*c/(c*a*b)]797sage: G.__reduce__()798(<class 'sage.groups.finitely_presented.FinitelyPresentedGroup'>,799(Free Group on generators {a, b, c},800(a*b*c*a^-1*c^-1*b^-1, a*b*c*b^-1*a^-1*c^-1)))801"""802return (FinitelyPresentedGroup, (self._free_group, self._relations))803804def _repr_(self):805"""806Return a string representation.807808OUTPUT:809810String.811812TESTS::813814sage: G.<a,b> = FreeGroup()815sage: H = G / (G([1]), G([2])^3)816sage: H # indirect doctest817Finitely presented group < a, b | a, b^3 >818sage: H._repr_()819'Finitely presented group < a, b | a, b^3 >'820"""821gens = ', '.join(self.variable_names())822rels = ', '.join([ str(r) for r in self.relations() ])823return 'Finitely presented group ' + '< '+ gens + ' | ' + rels + ' >'824825def _latex_(self):826"""827Return a LaTeX representation828829OUTPUT:830831String. A valid LaTeX math command sequence.832833TESTS::834835sage: F=FreeGroup(4)836sage: F.inject_variables()837Defining x0, x1, x2, x3838sage: G=F.quotient([x0*x2, x3*x1*x3, x2*x1*x2])839sage: G._latex_()840'\\langle x_{0}, x_{1}, x_{2}, x_{3} \\mid x_{0}\\cdot x_{2} , x_{3}\\cdot x_{1}\\cdot x_{3} , x_{2}\\cdot x_{1}\\cdot x_{2}\\rangle'841"""842r = '\\langle '843for i in range(self.ngens()):844r = r+self.gen(i)._latex_()845if i < self.ngens()-1:846r = r+', '847r = r+' \\mid '848for i in range(len(self._relations)):849r = r+(self._relations)[i]._latex_()850if i < len(self.relations())-1:851r = r+' , '852r = r+'\\rangle'853return r854855def free_group(self):856"""857Return the free group (without relations).858859OUTPUT:860861A :func:`~sage.groups.free_group.FreeGroup`.862863EXAMPLES::864865sage: G.<a,b,c> = FreeGroup()866sage: H = G / (a^2, b^3, a*b*~a*~b)867sage: H.free_group()868Free Group on generators {a, b, c}869sage: H.free_group() is G870True871"""872return self._free_group873874def relations(self):875"""876Return the relations of the group.877878OUTPUT:879880The relations as a tuple of elements of :meth:`free_group`.881882EXAMPLES::883884sage: F = FreeGroup(5, 'x')885sage: F.inject_variables()886Defining x0, x1, x2, x3, x4887sage: G = F.quotient([x0*x2, x3*x1*x3, x2*x1*x2])888sage: G.relations()889(x0*x2, x3*x1*x3, x2*x1*x2)890sage: all(rel in F for rel in G.relations())891True892"""893return self._relations894895@cached_method896def cardinality(self, limit=4096000):897"""898Compute the cardinality of ``self``.899900INPUT:901902- ``limit`` -- integer (default: 4096000). The maximal number903of cosets before the computation is aborted.904905OUTPUT:906907Integer or ``Infinity``. The number of elements in the group.908909EXAMPLES::910911sage: G.<a,b> = FreeGroup('a, b')912sage: H = G / (a^2, b^3, a*b*~a*~b)913sage: H.cardinality()9146915916sage: F.<a,b,c> = FreeGroup()917sage: J = F / (F([1]), F([2, 2, 2]))918sage: J.cardinality()919+Infinity920921ALGORITHM:922923Uses GAP.924925.. WARNING::926927This is in general not a decidable problem, so it is not928guaranteed to give an answer. If the group is infinite, or929too big, you should be prepared for a long computation930that consumes all the memory without finishing if you do931not set a sensible ``limit``.932"""933with libgap.global_context('CosetTableDefaultMaxLimit', limit):934if not libgap.IsFinite(self.gap()):935from sage.rings.infinity import Infinity936return Infinity937try:938size = self.gap().Size()939except ValueError:940raise ValueError('Coset enumeration ran out of memory, is the group finite?')941return size.sage()942943order = cardinality944945def as_permutation_group(self, limit=4096000):946"""947Return an isomorphic permutation group.948949The generators of the resulting group correspond to the images950by the isomorphism of the generators of the given group.951952INPUT:953954- ``limit`` -- integer (default: 4096000). The maximal number955of cosets before the computation is aborted.956957OUTPUT:958959A Sage960:func:`~sage.groups.perm_gps.permgroup.PermutationGroup`. If961the number of cosets exceeds the given ``limit``, a962``ValueError`` is returned.963964EXAMPLES::965966sage: G.<a,b> = FreeGroup()967sage: H = G / (a^2, b^3, a*b*~a*~b)968sage: H.as_permutation_group()969Permutation Group with generators [(1,2)(3,5)(4,6), (1,3,4)(2,5,6)]970971sage: G.<a,b> = FreeGroup()972sage: H = G / [a^3*b]973sage: H.as_permutation_group(limit=1000)974Traceback (most recent call last):975...976ValueError: Coset enumeration exceeded limit, is the group finite?977978ALGORITHM:979980Uses GAP's coset enumeration on the trivial subgroup.981982.. WARNING::983984This is in general not a decidable problem (in fact, it is985not even posible to check if the group is finite or986not). If the group is infinite, or too big, you should be987prepared for a long computation that consumes all the988memory without finishing if you do not set a sensible989``limit``.990"""991with libgap.global_context('CosetTableDefaultMaxLimit', limit):992try:993trivial_subgroup = self.gap().TrivialSubgroup()994coset_table = self.gap().CosetTable(trivial_subgroup).sage()995except ValueError:996raise ValueError('Coset enumeration exceeded limit, is the group finite?')997from sage.combinat.permutation import Permutation998from sage.groups.perm_gps.permgroup import PermutationGroup999return PermutationGroup([1000Permutation(coset_table[2*i]) for i in range(len(coset_table)/2)])10011002def direct_product(self, H, reduced=False, new_names=True):1003r"""1004Return the direct product of ``self`` with finitely presented1005group ``H``.10061007Calls GAP function ``DirectProduct``, which returns the direct1008product of a list of groups of any representation.10091010From [JohnsonPG90]_ (pg 45, proposition 4): If `G`, `H` are groups1011presented by `\langle X \mid R \rangle` and `\langle Y \mid S \rangle`1012respectively, then their direct product has the presentation1013`\langle X, Y \mid R, S, [X, Y] \rangle` where `[X, Y]` denotes the1014set of commutators `\{ x^{-1} y^{-1} x y \mid x \in X, y \in Y \}`.10151016INPUT:10171018- ``H`` -- a finitely presented group10191020- ``reduced`` -- (default: ``False``) boolean; if ``True``, then1021attempt to reduce the presentation of the product group10221023- ``new_names`` -- (default: ``True``) boolean; If ``True``, then1024lexicographical variable names are assigned to the generators of1025the group to be returned. If ``False``, the group to be returned1026keeps the generator names of the two groups forming the direct1027product. Note that one cannot ask to reduce the output and ask1028to keep the old variable names, as they they may change meaning1029in the output group if its presentation is reduced.10301031OUTPUT:10321033The direct product of ``self`` with ``H`` as a finitely1034presented group.10351036EXAMPLES::10371038sage: G = FreeGroup()1039sage: C12 = ( G / [G([1,1,1,1])] ).direct_product( G / [G([1,1,1])]); C121040Finitely presented group < a, b | a^4, b^3, a^-1*b^-1*a*b >1041sage: C12.order(), C12.as_permutation_group().is_cyclic()1042(12, True)1043sage: klein = ( G / [G([1,1])] ).direct_product( G / [G([1,1])]); klein1044Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >1045sage: klein.order(), klein.as_permutation_group().is_cyclic()1046(4, False)10471048We can keep the variable names from ``self`` and ``H`` to examine how1049new relations are formed::10501051sage: F = FreeGroup("a"); G = FreeGroup("g")1052sage: X = G / [G.0^12]; A = F / [F.0^6]1053sage: X.direct_product(A, new_names=False)1054Finitely presented group < g, a | g^12, a^6, g^-1*a^-1*g*a >1055sage: A.direct_product(X, new_names=False)1056Finitely presented group < a, g | a^6, g^12, a^-1*g^-1*a*g >10571058Or we can attempt to reduce the output group presentation::10591060sage: F = FreeGroup("a"); G = FreeGroup("g")1061sage: X = G / [G.0]; A = F / [F.0]1062sage: X.direct_product(A, new_names=True)1063Finitely presented group < a, b | a, b, a^-1*b^-1*a*b >1064sage: X.direct_product(A, reduced=True, new_names=True)1065Finitely presented group < | >10661067But we cannot do both::10681069sage: K = FreeGroup(['a','b'])1070sage: D = K / [K.0^5, K.1^8]1071sage: D.direct_product(D, reduced=True, new_names=False)1072Traceback (most recent call last):1073...1074ValueError: cannot reduce output and keep old variable names10751076TESTS::10771078sage: G = FreeGroup()1079sage: Dp = (G / [G([1,1])]).direct_product( G / [G([1,1,1,1,1,1])] )1080sage: Dp.as_permutation_group().is_isomorphic(PermutationGroup(['(1,2)','(3,4,5,6,7,8)']))1081True1082sage: C7 = G / [G.0**7]; C6 = G / [G.0**6]1083sage: C14 = G / [G.0**14]; C3 = G / [G.0**3]1084sage: C7.direct_product(C6).is_isomorphic(C14.direct_product(C3))1085True1086sage: F = FreeGroup(2); D = F / [F([1,1,1,1,1]),F([2,2]),F([1,2])**2]1087sage: D.direct_product(D).as_permutation_group().is_isomorphic(1088....: direct_product_permgroups([DihedralGroup(5),DihedralGroup(5)]))1089True10901091AUTHORS:10921093- Davis Shurbert (2013-07-20): initial version10941095REFERENCES:10961097.. [JohnsonPG90] D.L. Johnson. *Presentations of Groups*.1098Cambridge University Press. (1990).1099"""1100from sage.groups.free_group import FreeGroup, _lexi_gen11011102if not isinstance(H, FinitelyPresentedGroup):1103raise TypeError("input must be a finitely presented group")1104if reduced and not new_names:1105raise ValueError("cannot reduce output and keep old variable names")11061107fp_product = libgap.DirectProduct([self.gap(), H.gap()])1108GAP_gens = fp_product.FreeGeneratorsOfFpGroup()1109if new_names:1110name_itr = _lexi_gen() # Python generator for lexicographical variable names1111gen_names = [name_itr.next() for i in GAP_gens]1112else:1113gen_names= [str(g) for g in self.gens()] + [str(g) for g in H.gens()]1114# Build the direct product in Sage for better variable names1115ret_F = FreeGroup(gen_names)1116ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage())1117for rel_word in fp_product.RelatorsOfFpGroup()])1118ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls)1119if reduced:1120ret_fpg = ret_fpg.simplified()1121return ret_fpg11221123def semidirect_product(self, H, hom, check=True, reduced=False):1124"""1125The semidirect product of ``self`` with ``H`` via ``hom``.11261127If there exists a homomorphism `\phi` from a group `G` to the1128automorphism group of a group `H`, then we can define the semidirect1129product of `G` with `H` via `\phi` as the cartesian product of `G`1130and `H` with the operation11311132.. MATH::11331134(g_1, h_1)(g_2, h_2) = (g_1 g_2, \phi(g_2)(h_1) h_2).11351136INPUT:11371138- ``H`` -- Finitely presented group which is implicitly acted on1139by ``self`` and can be naturally embedded as a normal subgroup1140of the semidirect product.11411142- ``hom`` -- Homomorphism from ``self`` to the automorphism group1143of ``H``. Given as a pair, with generators of ``self`` in the1144first slot and the images of the corresponding generators in the1145second. These images must be automorphisms of ``H``, given again1146as a pair of generators and images.11471148- ``check`` -- Boolean (default ``True``). If ``False`` the defining1149homomorphism and automorphism images are not tested for validity.1150This test can be costly with large groups, so it can be bypassed1151if the user is confident that his morphisms are valid.11521153- ``reduced`` -- Boolean (default ``False``). If ``True`` then the1154method attempts to reduce the presentation of the output group.11551156OUTPUT:11571158The semidirect product of ``self`` with ``H`` via ``hom`` as a1159finitely presented group. See1160:meth:`PermutationGroup_generic.semidirect_product1161<sage.groups.perm_gps.permgroup.PermutationGroup_generic.semidirect_product>`1162for a more in depth explanation of a semidirect product.11631164AUTHORS:11651166- Davis Shurbert (8-1-2013)11671168EXAMPLES:11691170Group of order 12 as two isomorphic semidirect products::11711172sage: D4 = groups.presentation.Dihedral(4)1173sage: C3 = groups.presentation.Cyclic(3)1174sage: alpha1 = ([C3.gen(0)],[C3.gen(0)])1175sage: alpha2 = ([C3.gen(0)],[C3([1,1])])1176sage: S1 = D4.semidirect_product(C3, ([D4.gen(1), D4.gen(0)],[alpha1,alpha2]))1177sage: C2 = groups.presentation.Cyclic(2)1178sage: Q = groups.presentation.DiCyclic(3)1179sage: a = Q([1]); b = Q([-2])1180sage: alpha = (Q.gens(), [a,b])1181sage: S2 = C2.semidirect_product(Q, ([C2.0],[alpha]))1182sage: S1.is_isomorphic(S2)1183True11841185Dihedral groups can be constructed as semidirect products1186of cyclic groups::11871188sage: C2 = groups.presentation.Cyclic(2)1189sage: C8 = groups.presentation.Cyclic(8)1190sage: hom = (C2.gens(), [ ([C8([1])], [C8([-1])]) ])1191sage: D = C2.semidirect_product(C8, hom)1192sage: D.as_permutation_group().is_isomorphic(DihedralGroup(8))1193True11941195You can attempt to reduce the presentation of the output group::11961197sage: D = C2.semidirect_product(C8, hom); D1198Finitely presented group < a, b, c, d |1199a^2, b^-1*a^-1*b*a*d^-1*c^-1, c^-1*a^-1*c*a*d^-1, d^-1*a^-1*d*a,1200b^2*c^-1, c^-1*b^-1*c*b, d^-1*b^-1*d*b, c^2*d^-1, d^-1*c^-1*d*c, d^2 >1201sage: D = C2.semidirect_product(C8, hom, reduced=True); D1202Finitely presented group < a, b | a^2, (a*b)^2, b^8 >12031204sage: C3 = groups.presentation.Cyclic(3)1205sage: C4 = groups.presentation.Cyclic(4)1206sage: hom = (C3.gens(), [(C4.gens(), C4.gens())])1207sage: C3.semidirect_product(C4, hom)1208Finitely presented group < a, b, c |1209a^3, b^-1*a^-1*b*a, c^-1*a^-1*c*a, b^2*c^-1, c^-1*b^-1*c*b, c^2 >1210sage: D = C3.semidirect_product(C4, hom, reduced=True); D1211Finitely presented group < a, b | a^3, b^4, b^-1*a^-1*b*a >1212sage: D.as_permutation_group().is_cyclic()1213True12141215You can turn off the checks for the validity of the input morphisms.1216This check is expensive but behavior is unpredictable if inputs are1217invalid and are not caught by these tests. Due to a failure in GAP1218to list elements of an automorphism group in some cases, this check1219may cause the method to timeout or raise a GAP error. For example,1220if ``H`` is the cyclic group of order 6, then ``semidirect_product``1221appears to fall into an infinite loop due to this failure.::12221223sage: C5 = groups.presentation.Cyclic(5)1224sage: C12 = groups.presentation.Cyclic(12)1225sage: hom = (C5.gens(), [(C12.gens(), C12.gens())])1226sage: C5.semidirect_product(C12, hom)1227Traceback (most recent call last):1228...1229ValueError: libGAP: Error, <elm> is not contained in the source group1230sage: sp = C5.semidirect_product(C12, hom, check=False); sp1231Finitely presented group < a, b, c, d |1232a^5, b^-1*a^-1*b*a, c^-1*a^-1*c*a, d^-1*a^-1*d*a, b^2*d^-1,1233c^-1*b^-1*c*b, d^-1*b^-1*d*b, c^3, d^-1*c^-1*d*c, d^2 >1234sage: sp.as_permutation_group().is_cyclic(), sp.order()1235(True, 60)12361237TESTS::12381239sage: C = groups.presentation.Cyclic(7)1240sage: D = groups.presentation.Dihedral(5)1241sage: id1 = ([C.0], [(D.gens(),D.gens())])1242sage: Se1 = C.semidirect_product(D, id1)1243sage: id2 = (D.gens(), [(C.gens(),C.gens()),(C.gens(),C.gens())])1244sage: Se2 = D.semidirect_product(C ,id2)1245sage: Dp1 = C.direct_product(D);1246sage: Dp1.is_isomorphic(Se1), Dp1.is_isomorphic(Se2)1247(True, True)12481249Most checks for validity of input are left to GAP to handle::12501251sage: bad_aut = ([C.0], [(D.gens(),[D.0, D.0])])1252sage: C.semidirect_product(D, bad_aut)1253Traceback (most recent call last):1254...1255ValueError: images of input homomorphism must be automorphisms1256sage: bad_hom = ([D.0, D.1], [(C.gens(),C.gens())])1257sage: D.semidirect_product(C, bad_hom)1258Traceback (most recent call last):1259...1260ValueError: libGAP: Error, <gens> and <imgs> must be lists of same length1261"""1262from sage.groups.free_group import FreeGroup, _lexi_gen12631264if not isinstance(H, FinitelyPresentedGroup):1265raise TypeError("input must be a finitely presented group")12661267GAP_self = self.gap(); GAP_H = H.gap()1268auto_grp = libgap.AutomorphismGroup(H.gap())1269self_gens = [h.gap() for h in hom[0]]1270# construct image automorphisms in GAP1271GAP_aut_imgs = [ libgap.GroupHomomorphismByImages(GAP_H, GAP_H, [g.gap() for g in gns],1272[i.gap() for i in img]) for (gns, img) in hom[1] ]12731274# check for automorphism validity in images of operation defining homomorphism,1275# and construct the defining homomorphism.1276if check:1277if not all([a in libgap.List(libgap.AutomorphismGroup(GAP_H)) for a in GAP_aut_imgs]):1278raise ValueError("images of input homomorphism must be automorphisms")1279GAP_def_hom = libgap.GroupHomomorphismByImages(GAP_self, auto_grp, self_gens, GAP_aut_imgs)1280else:1281GAP_def_hom = GAP_self.GroupHomomorphismByImagesNC( auto_grp, self_gens, GAP_aut_imgs)12821283prod = libgap.SemidirectProduct(GAP_self, GAP_def_hom, GAP_H)1284# Convert pc group to fp group1285if prod.IsPcGroup():1286prod = libgap.Image(libgap.IsomorphismFpGroupByPcgs(prod.FamilyPcgs() , 'x'))1287if not prod.IsFpGroup():1288raise NotImplementedError("unable to convert GAP output to equivalent Sage fp group")12891290# Convert GAP group object to Sage via Tietze1291# lists for readability of variable names1292GAP_gens = prod.FreeGeneratorsOfFpGroup()1293name_itr = _lexi_gen() # Python generator for lexicographical variable names1294ret_F = FreeGroup([name_itr.next() for i in GAP_gens])1295ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage())1296for rel_word in prod.RelatorsOfFpGroup()])1297ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls)1298if reduced:1299ret_fpg = ret_fpg.simplified()1300return ret_fpg13011302def _element_constructor_(self, *args, **kwds):1303"""1304Construct an element of ``self``.13051306TESTS::13071308sage: G.<a,b> = FreeGroup()1309sage: H = G / (G([1]), G([2, 2, 2]))1310sage: H([1, 2, 1, -1]) # indirect doctest1311a*b1312sage: H([1, 2, 1, -2]) # indirect doctest1313a*b*a*b^-11314"""1315if len(args)!=1:1316return self.element_class(self, *args, **kwds)1317x = args[0]1318if x==1:1319return self.one()1320try:1321P = x.parent()1322except AttributeError:1323return self.element_class(self, x, **kwds)1324if P is self._free_group:1325return self.element_class(self, x.Tietze(), **kwds)1326return self.element_class(self, x, **kwds)13271328@cached_method1329def abelian_invariants(self):1330r"""1331Return the abelian invariants of ``self``.13321333The abelian invariants are given by a list of integers1334`(i_1, \ldots, i_j)`, such that the abelianization of the group is1335isomorphic to `\ZZ / (i_1) \times \cdots \times \ZZ / (i_j)`.13361337EXAMPLES::13381339sage: G = FreeGroup(4, 'g')1340sage: G.inject_variables()1341Defining g0, g1, g2, g31342sage: H = G.quotient([g1^2, g2*g1*g2^(-1)*g1^(-1), g1*g3^(-2), g0^4])1343sage: H.abelian_invariants()1344(0, 4, 4)13451346ALGORITHM:13471348Uses GAP.1349"""1350invariants = self.gap().AbelianInvariants()1351return tuple( i.sage() for i in invariants )13521353def simplification_isomorphism(self):1354"""1355Return an isomorphism from ``self`` to a finitely presented group with1356a (hopefully) simpler presentation.13571358EXAMPLES::13591360sage: G.<a,b,c> = FreeGroup()1361sage: H = G / [a*b*c, a*b^2, c*b/c^2]1362sage: I = H.simplification_isomorphism()1363sage: I1364Generic morphism:1365From: Finitely presented group < a, b, c | a*b*c, a*b^2, c*b*c^-2 >1366To: Finitely presented group < b | >1367sage: I(a)1368b^-21369sage: I(b)1370b1371sage: I(c)1372b13731374TESTS::13751376sage: F = FreeGroup(1)1377sage: G = F.quotient([F.0])1378sage: G.simplification_isomorphism()1379Generic morphism:1380From: Finitely presented group < x | x >1381To: Finitely presented group < | >13821383ALGORITM:13841385Uses GAP.1386"""1387I = self.gap().IsomorphismSimplifiedFpGroup()1388domain = self1389codomain = wrap_FpGroup(I.Range())1390phi = lambda x: codomain(I.ImageElm(x.gap()))1391return self.hom(phi, codomain)13921393def simplified(self):1394"""1395Return an isomorphic group with a (hopefully) simpler presentation.13961397OUTPUT:13981399A new finitely presented group. Use1400:meth:`simplification_isomorphism` if you want to know the1401isomorphism.14021403EXAMPLES::14041405sage: G.<x,y> = FreeGroup()1406sage: H = G / [x ^5, y ^4, y*x*y^3*x ^3]1407sage: H1408Finitely presented group < x, y | x^5, y^4, y*x*y^3*x^3 >1409sage: H.simplified()1410Finitely presented group < x, y | y^4, y*x*y^-1*x^-2, x^5 >14111412A more complicate example::14131414sage: G.<e0, e1, e2, e3, e4, e5, e6, e7, e8, e9> = FreeGroup()1415sage: rels = [e6, e5, e3, e9, e4*e7^-1*e6, e9*e7^-1*e0,1416... e0*e1^-1*e2, e5*e1^-1*e8, e4*e3^-1*e8, e2]1417sage: H = G.quotient(rels); H1418Finitely presented group < e0, e1, e2, e3, e4, e5, e6, e7, e8, e9 |1419e6, e5, e3, e9, e4*e7^-1*e6, e9*e7^-1*e0, e0*e1^-1*e2, e5*e1^-1*e8, e4*e3^-1*e8, e2 >1420sage: H.simplified()1421Finitely presented group < e0 | e0^2 >1422"""1423return self.simplification_isomorphism().codomain()14241425def alexander_matrix(self):1426"""1427Return the Alexander matrix of the group.14281429This matrix is given by the fox derivatives of the relations1430with respect to the generators.14311432OUTPUT:14331434A group algebra-valued matrix. It depends on the (fixed)1435choice of presentation.14361437EXAMPLES::14381439sage: G.<a,b,c> = FreeGroup()1440sage: H = G.quotient([a*b/a/b, a*c/a/c, c*b/c/b])1441sage: H.alexander_matrix()1442[ B[1] - B[a*b*a^-1] B[a] - B[a*b*a^-1*b^-1] 0]1443[ B[1] - B[a*c*a^-1] 0 B[a] - B[a*c*a^-1*c^-1]]1444[ 0 B[c] - B[c*b*c^-1*b^-1] B[1] - B[c*b*c^-1]]14451446sage: G.<a,b,c,d,e> = FreeGroup()1447sage: H = G.quotient([a*b/a/b, a*c/a/c, a*d/a/d, b*c*d/(c*d*b), b*c*d/(d*b*c)])1448sage: H.alexander_matrix()1449[ B[1] - B[a*b*a^-1] B[a] - B[a*b*a^-1*b^-1] 0 0 0]1450[ B[1] - B[a*c*a^-1] 0 B[a] - B[a*c*a^-1*c^-1] 0 0]1451[ B[1] - B[a*d*a^-1] 0 0 B[a] - B[a*d*a^-1*d^-1] 0]1452[ 0 B[1] - B[b*c*d*b^-1] B[b] - B[b*c*d*b^-1*d^-1*c^-1] B[b*c] - B[b*c*d*b^-1*d^-1] 0]1453[ 0 B[1] - B[b*c*d*c^-1*b^-1] B[b] - B[b*c*d*c^-1] B[b*c] - B[b*c*d*c^-1*b^-1*d^-1] 0]1454"""1455rel = self.relations()1456gen = self._free_group.gens()1457return matrix(len(rel), len(gen),1458lambda i,j: rel[i].fox_derivative(gen[j]))14591460def rewriting_system(self):1461"""1462Return the rewriting system corresponding to the finitely presented1463group. This rewriting system can be used to reduce words with respect1464to the relations.14651466If the rewriting system is transformed into a confluent one, the1467reduction process will give as a result the (unique) reduced form1468of an element.14691470EXAMPLES::14711472sage: F.<a,b> = FreeGroup()1473sage: G = F / [a^2,b^3,(a*b/a)^3,b*a*b*a]1474sage: k = G.rewriting_system()1475sage: k1476Rewriting system of Finitely presented group < a, b | a^2, b^3, a*b^3*a^-1, (b*a)^2 >1477with rules:1478a^2 ---> 11479b^3 ---> 11480(b*a)^2 ---> 11481a*b^3*a^-1 ---> 114821483sage: G([1,1,2,2,2])1484a^2*b^31485sage: k.reduce(G([1,1,2,2,2]))148611487sage: k.reduce(G([2,2,1]))1488b^2*a1489sage: k.make_confluent()1490sage: k.reduce(G([2,2,1]))1491a*b1492"""1493return RewritingSystem(self)1494149514961497