# Free Groups#

Free groups and finitely presented groups are implemented as a wrapper over the corresponding GAP objects.

A free group can be created by giving the number of generators, or their names. It is also possible to create indexed generators:

sage: G.<x,y,z> = FreeGroup();  G
Free Group on generators {x, y, z}
sage: FreeGroup(3)
Free Group on generators {x0, x1, x2}
sage: FreeGroup('a,b,c')
Free Group on generators {a, b, c}
sage: FreeGroup(3,'t')
Free Group on generators {t0, t1, t2}

>>> from sage.all import *
>>> G = FreeGroup(names=('x', 'y', 'z',)); (x, y, z,) = G._first_ngens(3);  G
Free Group on generators {x, y, z}
>>> FreeGroup(Integer(3))
Free Group on generators {x0, x1, x2}
>>> FreeGroup('a,b,c')
Free Group on generators {a, b, c}
>>> FreeGroup(Integer(3),'t')
Free Group on generators {t0, t1, t2}


The elements can be created by operating with the generators, or by passing a list with the indices of the letters to the group:

EXAMPLES:

sage: G.<a,b,c> = FreeGroup()
sage: a*b*c*a
a*b*c*a
sage: G([1,2,3,1])
a*b*c*a
sage: a * b / c * b^2
a*b*c^-1*b^2
sage: G([1,1,2,-1,-3,2])
a^2*b*a^-1*c^-1*b

>>> from sage.all import *
>>> G = FreeGroup(names=('a', 'b', 'c',)); (a, b, c,) = G._first_ngens(3)
>>> a*b*c*a
a*b*c*a
>>> G([Integer(1),Integer(2),Integer(3),Integer(1)])
a*b*c*a
>>> a * b / c * b**Integer(2)
a*b*c^-1*b^2
>>> G([Integer(1),Integer(1),Integer(2),-Integer(1),-Integer(3),Integer(2)])
a^2*b*a^-1*c^-1*b


You can use call syntax to replace the generators with a set of arbitrary ring elements:

sage: g =  a * b / c * b^2
sage: g(1,2,3)
8/3
sage: M1 = identity_matrix(2)
sage: M2 = matrix([[1,1],[0,1]])
sage: M3 = matrix([[0,1],[1,0]])
sage: g([M1, M2, M3])
[1 3]
[1 2]

>>> from sage.all import *
>>> g =  a * b / c * b**Integer(2)
>>> g(Integer(1),Integer(2),Integer(3))
8/3
>>> M1 = identity_matrix(Integer(2))
>>> M2 = matrix([[Integer(1),Integer(1)],[Integer(0),Integer(1)]])
>>> M3 = matrix([[Integer(0),Integer(1)],[Integer(1),Integer(0)]])
>>> g([M1, M2, M3])
[1 3]
[1 2]


AUTHORS:

• Miguel Angel Marco Buzunariz

• Volker Braun

sage.groups.free_group.FreeGroup(n=None, names='x', index_set=None, abelian=False, **kwds)[source]#

Construct a Free Group.

INPUT:

• n – integer (default: None); the number of generators (if not specified the names are counted)

• names – string or list/tuple/iterable of strings (default: 'x'); the generator names or name prefix

• index_set – (optional) an index set for the generators; if specified then the optional keyword abelian can be used

• abelian – (default: False) whether to construct a free abelian group or a free group

Note

If you want to create a free group, it is currently preferential to use Groups().free(...) as that does not load GAP.

EXAMPLES:

sage: G.<a,b> = FreeGroup();  G
Free Group on generators {a, b}
sage: H = FreeGroup('a, b')
sage: G is H
True
sage: FreeGroup(0)
Free Group on generators {}

>>> from sage.all import *
>>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2);  G
Free Group on generators {a, b}
>>> H = FreeGroup('a, b')
>>> G is H
True
>>> FreeGroup(Integer(0))
Free Group on generators {}


The entry can be either a string with the names of the generators, or the number of generators and the prefix of the names to be given. The default prefix is 'x'

sage: FreeGroup(3)
Free Group on generators {x0, x1, x2}
sage: FreeGroup(3, 'g')
Free Group on generators {g0, g1, g2}
sage: FreeGroup()
Free Group on generators {x}

>>> from sage.all import *
>>> FreeGroup(Integer(3))
Free Group on generators {x0, x1, x2}
>>> FreeGroup(Integer(3), 'g')
Free Group on generators {g0, g1, g2}
>>> FreeGroup()
Free Group on generators {x}


We give two examples using the index_set option:

sage: FreeGroup(index_set=ZZ)                                                   # needs sage.combinat
Free group indexed by Integer Ring
sage: FreeGroup(index_set=ZZ, abelian=True)                                     # needs sage.combinat
Free abelian group indexed by Integer Ring

>>> from sage.all import *
>>> FreeGroup(index_set=ZZ)                                                   # needs sage.combinat
Free group indexed by Integer Ring
>>> FreeGroup(index_set=ZZ, abelian=True)                                     # needs sage.combinat
Free abelian group indexed by Integer Ring

class sage.groups.free_group.FreeGroupElement(parent, x)[source]#

Bases: ElementLibGAP

A wrapper of GAP’s Free Group elements.

INPUT:

EXAMPLES:

sage: G = FreeGroup('a, b')
sage: x = G([1, 2, -1, -2])
sage: x
a*b*a^-1*b^-1
sage: y = G([2, 2, 2, 1, -2, -2, -2])
sage: y
b^3*a*b^-3
sage: x*y
a*b*a^-1*b^2*a*b^-3
sage: y*x
b^3*a*b^-3*a*b*a^-1*b^-1
sage: x^(-1)
b*a*b^-1*a^-1
sage: x == x*y*y^(-1)
True

>>> from sage.all import *
>>> G = FreeGroup('a, b')
>>> x = G([Integer(1), Integer(2), -Integer(1), -Integer(2)])
>>> x
a*b*a^-1*b^-1
>>> y = G([Integer(2), Integer(2), Integer(2), Integer(1), -Integer(2), -Integer(2), -Integer(2)])
>>> y
b^3*a*b^-3
>>> x*y
a*b*a^-1*b^2*a*b^-3
>>> y*x
b^3*a*b^-3*a*b*a^-1*b^-1
>>> x**(-Integer(1))
b*a*b^-1*a^-1
>>> x == x*y*y**(-Integer(1))
True

Tietze()[source]#

Return the Tietze list of the element.

The Tietze list of a word is a list of integers that represent the letters in the word. A positive integer $$i$$ represents the letter corresponding to the $$i$$-th generator of the group. Negative integers represent the inverses of generators.

OUTPUT: tuple of integers

EXAMPLES:

sage: G.<a,b> = FreeGroup()
sage: a.Tietze()
(1,)
sage: x = a^2 * b^(-3) * a^(-2)
sage: x.Tietze()
(1, 1, -2, -2, -2, -1, -1)

>>> from sage.all import *
>>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2)
>>> a.Tietze()
(1,)
>>> x = a**Integer(2) * b**(-Integer(3)) * a**(-Integer(2))
>>> x.Tietze()
(1, 1, -2, -2, -2, -1, -1)

fox_derivative(gen, im_gens=None, ring=None)[source]#

Return the Fox derivative of self with respect to a given generator gen of the free group.

Let $$F$$ be a free group with free generators $$x_1, x_2, \ldots, x_n$$. Let $$j \in \left\{ 1, 2, \ldots , n \right\}$$. Let $$a_1, a_2, \ldots, a_n$$ be $$n$$ invertible elements of a ring $$A$$. Let $$a : F \to A^\times$$ be the (unique) homomorphism from $$F$$ to the multiplicative group of invertible elements of $$A$$ which sends each $$x_i$$ to $$a_i$$. Then, we can define a map $$\partial_j : F \to A$$ by the requirements that

$\partial_j (x_i) = \delta_{i, j} \qquad \qquad \text{ for all indices } i \text{ and } j$

and

$\partial_j (uv) = \partial_j(u) + a(u) \partial_j(v) \qquad \qquad \text{ for all } u, v \in F .$

This map $$\partial_j$$ is called the $$j$$-th Fox derivative on $$F$$ induced by $$(a_1, a_2, \ldots, a_n)$$.

The most well-known case is when $$A$$ is the group ring $$\ZZ [F]$$ of $$F$$ over $$\ZZ$$, and when $$a_i = x_i \in A$$. In this case, $$\partial_j$$ is simply called the $$j$$-th Fox derivative on $$F$$.

INPUT:

• gen – the generator with respect to which the derivative will be computed. If this is $$x_j$$, then the method will return $$\partial_j$$.

• im_gens (optional) – the images of the generators (given as a list or iterable). This is the list $$(a_1, a_2, \ldots, a_n)$$. If not provided, it defaults to $$(x_1, x_2, \ldots, x_n)$$ in the group ring $$\ZZ [F]$$.

• ring (optional) – the ring in which the elements of the list $$(a_1, a_2, \ldots, a_n)$$ lie. If not provided, this ring is inferred from these elements.

OUTPUT:

The fox derivative of self with respect to gen (induced by im_gens). By default, it is an element of the group algebra with integer coefficients. If im_gens are provided, the result lives in the algebra where im_gens live.

EXAMPLES:

sage: G = FreeGroup(5)
sage: G.inject_variables()
Defining x0, x1, x2, x3, x4
sage: (~x0*x1*x0*x2*~x0).fox_derivative(x0)
-x0^-1 + x0^-1*x1 - x0^-1*x1*x0*x2*x0^-1
sage: (~x0*x1*x0*x2*~x0).fox_derivative(x1)
x0^-1
sage: (~x0*x1*x0*x2*~x0).fox_derivative(x2)
x0^-1*x1*x0
sage: (~x0*x1*x0*x2*~x0).fox_derivative(x3)
0

>>> from sage.all import *
>>> G = FreeGroup(Integer(5))
>>> G.inject_variables()
Defining x0, x1, x2, x3, x4
>>> (~x0*x1*x0*x2*~x0).fox_derivative(x0)
-x0^-1 + x0^-1*x1 - x0^-1*x1*x0*x2*x0^-1
>>> (~x0*x1*x0*x2*~x0).fox_derivative(x1)
x0^-1
>>> (~x0*x1*x0*x2*~x0).fox_derivative(x2)
x0^-1*x1*x0
>>> (~x0*x1*x0*x2*~x0).fox_derivative(x3)
0


If im_gens is given, the images of the generators are mapped to them:

sage: F = FreeGroup(3)
sage: a = F([2,1,3,-1,2])
sage: a.fox_derivative(F([1]))
x1 - x1*x0*x2*x0^-1
sage: R.<t> = LaurentPolynomialRing(ZZ)
sage: a.fox_derivative(F([1]),[t,t,t])
t - t^2
sage: S.<t1,t2,t3> = LaurentPolynomialRing(ZZ)
sage: a.fox_derivative(F([1]),[t1,t2,t3])
-t2*t3 + t2
sage: R.<x,y,z> = QQ[]
sage: a.fox_derivative(F([1]),[x,y,z])
-y*z + y
sage: a.inverse().fox_derivative(F([1]),[x,y,z])
(z - 1)/(y*z)

>>> from sage.all import *
>>> F = FreeGroup(Integer(3))
>>> a = F([Integer(2),Integer(1),Integer(3),-Integer(1),Integer(2)])
>>> a.fox_derivative(F([Integer(1)]))
x1 - x1*x0*x2*x0^-1
>>> R = LaurentPolynomialRing(ZZ, names=('t',)); (t,) = R._first_ngens(1)
>>> a.fox_derivative(F([Integer(1)]),[t,t,t])
t - t^2
>>> S = LaurentPolynomialRing(ZZ, names=('t1', 't2', 't3',)); (t1, t2, t3,) = S._first_ngens(3)
>>> a.fox_derivative(F([Integer(1)]),[t1,t2,t3])
-t2*t3 + t2
>>> R = QQ['x, y, z']; (x, y, z,) = R._first_ngens(3)
>>> a.fox_derivative(F([Integer(1)]),[x,y,z])
-y*z + y
>>> a.inverse().fox_derivative(F([Integer(1)]),[x,y,z])
(z - 1)/(y*z)


The optional parameter ring determines the ring $$A$$:

sage: u = a.fox_derivative(F([1]), [1,2,3], ring=QQ)
sage: u
-4
sage: parent(u)
Rational Field
sage: u = a.fox_derivative(F([1]), [1,2,3], ring=R)
sage: u
-4
sage: parent(u)
Multivariate Polynomial Ring in x, y, z over Rational Field

>>> from sage.all import *
>>> u = a.fox_derivative(F([Integer(1)]), [Integer(1),Integer(2),Integer(3)], ring=QQ)
>>> u
-4
>>> parent(u)
Rational Field
>>> u = a.fox_derivative(F([Integer(1)]), [Integer(1),Integer(2),Integer(3)], ring=R)
>>> u
-4
>>> parent(u)
Multivariate Polynomial Ring in x, y, z over Rational Field

syllables()[source]#

Return the syllables of the word.

Consider a free group element $$g = x_1^{n_1} x_2^{n_2} \cdots x_k^{n_k}$$. The uniquely-determined subwords $$x_i^{e_i}$$ consisting only of powers of a single generator are called the syllables of $$g$$.

OUTPUT:

The tuple of syllables. Each syllable is given as a pair $$(x_i, e_i)$$ consisting of a generator and a non-zero integer.

EXAMPLES:

sage: G.<a,b> = FreeGroup()
sage: w = a^2 * b^-1 * a^3
sage: w.syllables()
((a, 2), (b, -1), (a, 3))

>>> from sage.all import *
>>> G = FreeGroup(names=('a', 'b',)); (a, b,) = G._first_ngens(2)
>>> w = a**Integer(2) * b**-Integer(1) * a**Integer(3)
>>> w.syllables()
((a, 2), (b, -1), (a, 3))

class sage.groups.free_group.FreeGroup_class(generator_names, libgap_free_group=None)[source]#

A class that wraps GAP’s FreeGroup

See FreeGroup() for details.

Element[source]#

alias of FreeGroupElement

abelian_invariants()[source]#

Return the Abelian invariants of self.

The Abelian invariants are given by a list of integers $$i_1 \dots i_j$$, such that the abelianization of the group is isomorphic to

$\ZZ / (i_1) \times \dots \times \ZZ / (i_j)$

EXAMPLES:

sage: F.<a,b> = FreeGroup()
sage: F.abelian_invariants()
(0, 0)

>>> from sage.all import *
>>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
>>> F.abelian_invariants()
(0, 0)

quotient(relations, **kwds)[source]#

Return the quotient of self by the normal subgroup generated by the given elements.

This quotient is a finitely presented groups with the same generators as self, and relations given by the elements of relations.

INPUT:

• relations – a list/tuple/iterable with the elements of the free group

• further named arguments, that are passed to the constructor of a finitely presented group

OUTPUT:

A finitely presented group, with generators corresponding to the generators of the free group, and relations corresponding to the elements in relations.

EXAMPLES:

sage: F.<a,b> = FreeGroup()
sage: F.quotient([a*b^2*a, b^3])
Finitely presented group < a, b | a*b^2*a, b^3 >

>>> from sage.all import *
>>> F = FreeGroup(names=('a', 'b',)); (a, b,) = F._first_ngens(2)
>>> F.quotient([a*b**Integer(2)*a, b**Integer(3)])
Finitely presented group < a, b | a*b^2*a, b^3 >


Division is shorthand for quotient()

sage: F /  [a*b^2*a, b^3]
Finitely presented group < a, b | a*b^2*a, b^3 >

>>> from sage.all import *
>>> F /  [a*b**Integer(2)*a, b**Integer(3)]
Finitely presented group < a, b | a*b^2*a, b^3 >


Relations are converted to the free group, even if they are not elements of it (if possible)

sage: F1.<a,b,c,d> = FreeGroup()
sage: F2.<a,b> = FreeGroup()
sage: r = a*b/a
sage: r.parent()
Free Group on generators {a, b}
sage: F1/[r]
Finitely presented group < a, b, c, d | a*b*a^-1 >

>>> from sage.all import *
>>> F1 = FreeGroup(names=('a', 'b', 'c', 'd',)); (a, b, c, d,) = F1._first_ngens(4)
>>> F2 = FreeGroup(names=('a', 'b',)); (a, b,) = F2._first_ngens(2)
>>> r = a*b/a
>>> r.parent()
Free Group on generators {a, b}
>>> F1/[r]
Finitely presented group < a, b, c, d | a*b*a^-1 >

rank()[source]#

Return the number of generators of self.

Alias for ngens().

OUTPUT: integer

EXAMPLES:

sage: G = FreeGroup('a, b');  G
Free Group on generators {a, b}
sage: G.rank()
2
sage: H = FreeGroup(3, 'x')
sage: H
Free Group on generators {x0, x1, x2}
sage: H.rank()
3

>>> from sage.all import *
>>> G = FreeGroup('a, b');  G
Free Group on generators {a, b}
>>> G.rank()
2
>>> H = FreeGroup(Integer(3), 'x')
>>> H
Free Group on generators {x0, x1, x2}
>>> H.rank()
3

sage.groups.free_group.is_FreeGroup(x)[source]#

Test whether x is a FreeGroup_class.

INPUT:

• x – anything

OUTPUT: boolean

EXAMPLES:

sage: from sage.groups.free_group import is_FreeGroup
sage: is_FreeGroup('a string')                                                  # needs sage.combinat
False
sage: is_FreeGroup(FreeGroup(0))
True
sage: is_FreeGroup(FreeGroup(index_set=ZZ))                                     # needs sage.combinat
True

>>> from sage.all import *
>>> from sage.groups.free_group import is_FreeGroup
>>> is_FreeGroup('a string')                                                  # needs sage.combinat
False
>>> is_FreeGroup(FreeGroup(Integer(0)))
True
>>> is_FreeGroup(FreeGroup(index_set=ZZ))                                     # needs sage.combinat
True

sage.groups.free_group.wrap_FreeGroup(libgap_free_group)[source]#

Wrap a LibGAP free group.

This function changes the comparison method of libgap_free_group to comparison by Python id. If you want to put the LibGAP free group into a container (set, dict) then you should understand the implications of _set_compare_by_id(). To be safe, it is recommended that you just work with the resulting Sage FreeGroup_class.

INPUT:

• libgap_free_group – a LibGAP free group

OUTPUT: a Sage FreeGroup_class

EXAMPLES:

First construct a LibGAP free group:

sage: F = libgap.FreeGroup(['a', 'b'])
sage: type(F)
<class 'sage.libs.gap.element.GapElement'>

>>> from sage.all import *
>>> F = libgap.FreeGroup(['a', 'b'])
>>> type(F)
<class 'sage.libs.gap.element.GapElement'>


Now wrap it:

sage: from sage.groups.free_group import wrap_FreeGroup
sage: wrap_FreeGroup(F)
Free Group on generators {a, b}

>>> from sage.all import *
>>> from sage.groups.free_group import wrap_FreeGroup
>>> wrap_FreeGroup(F)
Free Group on generators {a, b}