% This file was created automatically from wordass.msk.
% DO NOT EDIT!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%A  wordass.msk                 GAP documentation            Alexander Hulpke
%%
%A  @(#)$Id: wordass.msk,v 1.27 2003/10/09 16:05:35 gap Exp $
%%
%Y  (C) 1998 School Math and Comp. Sci., University of St.  Andrews, Scotland
%Y  Copyright (C) 2002 The GAP Group
%%
\Chapter{Associative Words}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Categories of Associative Words}

Associative words are used to represent elements in free groups,
semigroups and monoids in {\GAP}
(see~"Free Groups, Monoids and Semigroups").
An associative word is just a sequence of letters,
where each letter is an element of an alphabet (in the following called a
*generator*) or its inverse.
Associative words can be multiplied;
in free monoids also the computation of an identity is permitted,
in free groups also the computation of inverses
(see~"Operations for Associative Words").



\>IsAssocWord( <obj> ) C
\>IsAssocWordWithOne( <obj> ) C
\>IsAssocWordWithInverse( <obj> ) C

`IsAssocWord' is the category of associative words in free semigroups,
`IsAssocWordWithOne' is the category of associative words in free monoids
(which admit the operation `One' to compute an identity),
`IsAssocWordWithInverse' is the category of associative words in free
groups (which have an inverse).
See~"IsWord" for more general categories of words.



Different alphabets correspond to different families of associative words.
There is no relation whatsoever between words in different families.

\beginexample
gap> f:= FreeGroup( "a", "b", "c" );
<free group on the generators [ a, b, c ]>
gap> gens:= GeneratorsOfGroup(f);
[ a, b, c ]
gap> w:= gens[1]*gens[2]/gens[3]*gens[2]*gens[1]/gens[1]*gens[3]/gens[2];
a*b*c^-1*b*c*b^-1
gap> w^-1;
b*c^-1*b^-1*c*b^-1*a^-1
\endexample

Words are displayed as products of letters.
The letters are usually printed like `f1', `f2', $\ldots$,
but it is possible to give user defined names to them,
which can be arbitrary strings.
These names do not necessarily identify a unique letter (generator),
it is possible to have several letters --even in the same family--
that are displayed in the same way.
Note also that
*there is no relation between the names of letters and variable names*.
In the example above, we might have typed

\beginexample
gap> a:= f.1;; b:= f.2;; c:= f.3;;
\endexample

(*Interactively*, the function `AssignGeneratorVariables'
(see~"AssignGeneratorVariables") provides a shorthand for this.)
This allows us to define `w' more conveniently:

\beginexample
gap> w := a*b/c*b*a/a*c/b;
a*b*c^-1*b*c*b^-1
\endexample

Using homomorphisms it is possible to express elements of a group as words
in terms of generators,
see~"Expressing group elements as words in generators".


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Free Groups, Monoids and Semigroups}

Usually a family of associative words will be generated by constructing
the free object generated by them.

\>FreeGroup( [<wfilt>, ]<rank> ) F
\>FreeGroup( [<wfilt>, ]<rank>, <name> ) F
\>FreeGroup( [<wfilt>, ]<name1>, <name2>, ... ) F
\>FreeGroup( [<wfilt>, ]<names> ) F
\>FreeGroup( [<wfilt>, ]infinity, <name>, <init> ) F

Called in the first form, `FreeGroup' returns a free group on
<rank> generators.
Called in the second form, `FreeGroup' returns a free group on
<rank> generators, printed as `<name>1', `<name>2' etc.
Called in the third form, `FreeGroup' returns a free group on
as many generators as arguments, printed as <name1>, <name2> etc.
Called in the fourth form, `FreeGroup' returns a free group on
as many generators as the length of the list <names>, the $i$-th
generator being printed as `<names>[$i$]'.
Called in the fifth form, `FreeGroup' returns a free group on
infinitely many generators, where the first generators are printed
by the names in the list <init>, and the other generators by <name>
and an appended number.

If the extra argument <wfilt> is given, it must be either
`IsSyllableWordsFamily' or `IsLetterWordsFamily' or
`IsWLetterWordsFamily' or `IsBLetterWordsFamily'. The filter then
specifies the representation used for the elements of the free group
(see~"Representations for Associative Words"). If no such filter is
given, a letter representation is used.

(For interfacing to old code that omits the representation flag, use of
the syllable representation is also triggered by setting the option
`FreeGroupFamilyType' to the string ``syllable''.)


\>IsFreeGroup( <obj> ) C

Any group consisting of elements in `IsAssocWordWithInverse' lies in the
filter `IsFreeGroup';
this holds in particular for any group created with `FreeGroup'
(see~"FreeGroup"), or any subgroup of such a group.




Also see Chapter~"Finitely Presented Groups".

\>FreeMonoid( [<wfilt>, ]<rank> )!{with example} F
\>FreeMonoid( [<wfilt>, ]<rank>, <name> )!{with example} F
\>FreeMonoid( [<wfilt>, ]<name1>, <name2>, ... )!{with example} F
\>FreeMonoid( [<wfilt>, ]<names> )!{with example} F
\>FreeMonoid( [<wfilt>, ]infinity, <name>, <init> )!{with example} F

Called in the first form, `FreeMonoid' returns a free monoid on
<rank> generators.
Called in the second form, `FreeMonoid' returns a free monoid on
<rank> generators, printed as `<name>1', `<name>2' etc.,
that is, each name is the concatenation of the string <name> and an
integer from `1' to <range>.
Called in the third form, `FreeMonoid' returns a free monoid on
as many generators as arguments, printed as <name1>, <name2> etc.
Called in the fourth form, `FreeMonoid' returns a free monoid on
as many generators as the length of the list <names>, the $i$-th
generator being printed as `<names>[$i$]'.
Called in the fifth form, `FreeMonoid' returns a free monoid on
infinitely many generators, where the first generators are printed
by the names in the list <init>, and the other generators by <name>
and an appended number.

If the extra argument <wfilt> is given, it must be either
`IsSyllableWordsFamily' or `IsLetterWordsFamily' or
`IsWLetterWordsFamily' or `IsBLetterWordsFamily'. The filter then
specifies the representation used for the elements of the free group
(see~"Representations for Associative Words"). If no such filter is
given, a letter representation is used.



Also see Chapter~"Monoids".

\>FreeSemigroup( [<wfilt>, ]<rank> ) F
\>FreeSemigroup( [<wfilt>, ]<rank>, <name> ) F
\>FreeSemigroup( [<wfilt>, ]<name1>, <name2>, ... ) F
\>FreeSemigroup( [<wfilt>, ]<names> ) F
\>FreeSemigroup( [<wfilt>, ]infinity, <name>, <init> ) F

Called in the first form, `FreeSemigroup' returns a free semigroup on
<rank> generators.
Called in the second form, `FreeSemigroup' returns a free semigroup on
<rank> generators, printed as `<name>1', `<name>2' etc.,
that is, each name is the concatenation of the string <name> and an
integer from `1' to <range>.
Called in the third form, `FreeSemigroup' returns a free semigroup on
as many generators as arguments, printed as <name1>, <name2> etc.
Called in the fourth form, `FreeSemigroup' returns a free semigroup on
as many generators as the length of the list <names>, the $i$-th
generator being printed as `<names>[$i$]'.
Called in the fifth form, `FreeSemigroup' returns a free semigroup on
infinitely many generators, where the first generators are printed
by the names in the list <init>, and the other generators by <name>
and an appended number.

If the extra argument <wfilt> is given, it must be either
`IsSyllableWordsFamily' or `IsLetterWordsFamily' or
`IsWLetterWordsFamily' or `IsBLetterWordsFamily'. The filter then
specifies the representation used for the elements of the free group
(see~"Representations for Associative Words"). If no such filter is
given, a letter representation is used.



Also see Chapter~"Semigroups" and~"FreeSemigroup!with examples".

Each free object defines a unique alphabet (and a unique family of words).
Its generators are the letters of this alphabet,
thus words of length one.

\beginexample
gap> FreeGroup( 5 );
<free group on the generators [ f1, f2, f3, f4, f5 ]>
gap> FreeGroup( "a", "b" );
<free group on the generators [ a, b ]>
gap> FreeGroup( infinity );
<free group with infinity generators>
gap> FreeSemigroup( "x", "y" );
<free semigroup on the generators [ x, y ]>
gap> FreeMonoid( 7 );
<free monoid on the generators [ m1, m2, m3, m4, m5, m6, m7 ]>
\endexample

Remember that names are just a help for printing and do not necessarily
distinguish letters.
It is possible to create arbitrarily weird situations by choosing strange
names for the letters.
\beginexample
gap> f:= FreeGroup( "x", "x" );  gens:= GeneratorsOfGroup( f );;
<free group on the generators [ x, x ]>
gap> gens[1] = gens[2];
false
gap> f:= FreeGroup( "f1*f2", "f2^-1", "Group( [ f1, f2 ] )" );
<free group on the generators [ f1*f2, f2^-1, Group( [ f1, f2 ] ) ]>
gap> gens:= GeneratorsOfGroup( f );;
gap> gens[1]*gens[2];
f1*f2*f2^-1
gap> gens[1]/gens[3];
f1*f2*Group( [ f1, f2 ] )^-1
gap> gens[3]/gens[1]/gens[2];
Group( [ f1, f2 ] )*f1*f2^-1*f2^-1^-1
\endexample

\>AssignGeneratorVariables( <G> ) F

If <G> is a group, whose generators are represented by symbols (for 
example a free group, a finitely presented group or a pc group) this
function assigns these generators to global variables with the same 
names.

The aim of this function is to make it easy in interactive use to work
with (for example) a free group. It is a shorthand for a sequence of
assignments of the form

\begintt
var1:=GeneratorsOfGroup(G)[1];
var2:=GeneratorsOfGroup(G)[2];
...
varn:=GeneratorsOfGroup(G)[n];
\endtt

However, since overwriting global variables can be very dangerous, *it
is not permitted to use this function within a function*. (If -- despite
this warning -- this is done, the result is undefined.)

If the assignment overwrites existing variables a warning is given, if
any of the variables if write protected, or any of the generator names   
would not be a proper variable name, an error is raised.



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Comparison of Associative Words}

\>`<w1> = <w2>'{equality!associative words}

Two associative words are equal if they are words over the same alphabet
and if they are sequences of the same letters.
This is equivalent to saying that the external representations of the
words are equal, see~"The External Representation for Associative Words" and
"Comparison of Words".

There is no ``universal'' empty word,
every alphabet (that is, every family of words) has its own empty word.
\beginexample
gap> f:= FreeGroup( "a", "b", "b" );;
gap> gens:= GeneratorsOfGroup(f);
[ a, b, b ]
gap> gens[2] = gens[3];
false
gap> x:= gens[1]*gens[2];
a*b
gap> y:= gens[2]/gens[2]*gens[1]*gens[2];
a*b
gap> x = y;
true
gap> z:= gens[2]/gens[2]*gens[1]*gens[3];
a*b
gap> x = z;
false
\endexample

\>`<w1> \< <w2>'{smaller!associative words}

The ordering of associative words is defined by length and lexicography
(this ordering is called *short-lex* ordering),
that is, shorter words are smaller than longer words,
and words of the same length are compared w.r.t.~the lexicographical
ordering induced by the ordering of generators.
Generators are sorted according to the order in which they were created.
If the generators are invertible then each generator <g> is larger than
its inverse `<g>^-1',
and `<g>^-1' is larger than every generator that is smaller than <g>.
\beginexample
gap> f:= FreeGroup( 2 );;  gens:= GeneratorsOfGroup( f );;
gap> a:= gens[1];;  b:= gens[2];;
gap> One(f) < a^-1;  a^-1 < a;  a < b^-1;  b^-1 < b; b < a^2;  a^2 < a*b;
true
true
true
true
true
true
\endexample



\>IsShortLexLessThanOrEqual( <u>, <v> ) F

returns `IsLessThanOrEqualUnder(<ord>, <u>, <v>)' where <ord> is the 
short less ordering for the family of <u> and <v>.
(This is here for compatibility with {\GAP}~4.2.)


\>IsBasicWreathLessThanOrEqual( <u>, <v> ) F

returns `IsLessThanOrEqualUnder(<ord>, <u>, <v>)' where <ord> is the
basic wreath product ordering for the family of <u> and <v>.
(This is here for compatibility with {\GAP}~4.2.)




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Operations for Associative Words}

\index{product!of words}
\index{quotient!of words}
\index{power!of words}
\index{conjugate!of a word}
\indextt{Comm!for words}
\indextt{LeftQuotient!for words}

The product of two given associative words is defined as the freely
reduced concatenation of the words;
so adjacent pairs of a generator and its inverse never occur in words.
Besides the multiplication `\*', the arithmetical operators
`One' (if the word lies in a family with identity)
and (if the generators are invertible) `Inverse', `/',`^', `Comm',
and `LeftQuotient' are applicable to associative words
(see~"Arithmetic Operations for Elements").

For the operation `MappedWord', which is applicable to arbitrary words,
see~"MappedWord".



There are two internal representations of associative words: By letters
and by syllables (see~"Representations for Associative Words"). Unless
something else is specified, words are stored in the letter
representation. Note, however, that operations to extract or act on
parts of words (letter or syllables) can carry substantially different
costs, depending on the representation the words are in.


\index{length!of a word}
\>Length( <w> )!{of an associative word} A

For an associative word <w>,
`Length' returns the number of letters in <w>.



\beginexample
gap> f := FreeGroup("a","b");; gens := GeneratorsOfGroup(f);;
gap> a := gens[1];; b := gens[2];;w := a^5*b*a^2*b^-4*a;;
gap>  w; Length( w );  Length( a^17 );  Length( w^0 );
a^5*b*a^2*b^-4*a
13
17
0
\endexample

\>ExponentSumWord( <w>, <gen> ) O

For an associative word <w> and a generator <gen>,
`ExponentSumWord' returns the number of times <gen> appears in <w>
minus the number of times its inverse appears in <w>.
If both <gen> and its inverse do not occur in <w> then $0$ is returned.
<gen> may also be the inverse of a generator.


\beginexample
gap> w;  ExponentSumWord( w, a );  ExponentSumWord( w, b );
a^5*b*a^2*b^-4*a
8
-3
gap> ExponentSumWord( (a*b*a^-1)^3, a );  ExponentSumWord( w, b^-1 );
0
3
\endexample

\>Subword( <w>, <from>, <to> ) O

For an associative word <w> and two positive integers <from> and <to>,
`Subword' returns the subword of <w> that begins at position <from>
and ends at position <to>.
Indexing is done with origin 1.


\beginexample
gap> w;  Subword( w, 3, 7 );
a^5*b*a^2*b^-4*a
a^3*b*a
\endexample

\>PositionWord( <w>, <sub>, <from> ) O

Let <w> and <sub> be associative words, and <from> a positive integer.
`PositionWord' returns the position of the first occurrence of <sub>
as a subword of <w>, starting at position <from>.
If there is no such occurrence, `fail' is returned.
Indexing is done with origin 1.

In other words, `PositionWord( <w>, <sub>, <from> )' is the smallest
integer <i> larger than or equal to <from> such that
`Subword( <w>, <i>, <i>+Length( <sub> )-1 ) = <sub>', see~"Subword".


\beginexample
gap> w;  PositionWord( w, a/b, 1 );
a^5*b*a^2*b^-4*a
8
gap> Subword( w, 8, 9 );
a*b^-1
gap> PositionWord( w, a^2, 1 );
1
gap> PositionWord( w, a^2, 2 );
2
gap> PositionWord( w, a^2, 6 );
7
gap> PositionWord( w, a^2, 8 );
fail
\endexample

\>SubstitutedWord( <w>, <from>, <to>, <by> ) O
\>SubstitutedWord( <w>, <sub>, <from>, <by> ) O

Let <w> be an associative word.

In the first form, `SubstitutedWord' returns the associative word
obtained by replacing the subword of <w> that begins at position <from>
and ends at position <to> by the associative word <by>.
<from> and <to> must be positive integers,
indexing is done with origin 1.
In other words, `SubstitutedWord( <w>, <from>, <to>, <by> )' is the
product of the three words `Subword( <w>, 1, <from>-1 )', <by>,
and `Subword( <w>, <to>+1, Length( <w> ) )', see~"Subword".

In the second form, `SubstitutedWord' returns the associative word
obtained by replacing the first occurrence of the associative word <sub>
of <w>, starting at position <from>, by the associative word <by>;
if there is no such occurrence, `fail' is returned.


\beginexample
gap> w;  SubstitutedWord( w, 3, 7, a^19 );
a^5*b*a^2*b^-4*a
a^22*b^-4*a
gap> SubstitutedWord( w, a, 6, b^7 );
a^5*b^8*a*b^-4*a
gap> SubstitutedWord( w, a*b, 6, b^7 );
fail
\endexample

\>EliminatedWord( <w>, <gen>, <by> ) O

For an associative word <w>, a generator <gen>, and an associative word
<by>, `EliminatedWord' returns the associative word obtained by
replacing each occurrence of <gen> in <w> by <by>.


\beginexample
gap> w;  EliminatedWord( w, a, a^2 );  EliminatedWord( w, a, b^-1 );
a^5*b*a^2*b^-4*a
a^10*b*a^4*b^-4*a^2
b^-11
\endexample

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Operations for Associative Words by their Syllables}

For an associative word $<w> = x_1^{n_1} x_2^{n_2} \cdots x_k^{n_k}$
over an alphabet containing $x_1, x_2, \ldots, x_k$,
such that $x_i \not= x_{i+1}^{\pm 1}$ for $1 \leq i \leq k-1$,
the subwords $x_i^{e_i}$ are uniquely determined;
these powers of generators are called the *syllables* of $w$.



\>NumberSyllables( <w> ) A

`NumberSyllables' returns the number of syllables of the associative
word <w>.


\>ExponentSyllable( <w>, <i> ) O

`ExponentSyllable' returns the exponent of the <i>-th syllable of the
associative word <w>.


\>GeneratorSyllable( <w>, <i> ) O

`GeneratorSyllable' returns the number of the generator that is involved
in the <i>-th syllable of the associative word <w>.


\>SubSyllables( <w>, <from>, <to> ) O

`SubSyllables' returns the subword of the associative word <w>
that consists of the syllables from positions <from> to <to>,
where <from> and <to> must be positive integers,
and indexing is done with origin 1.


\beginexample
gap> w;  NumberSyllables( w );
a^5*b*a^2*b^-4*a
5
gap> ExponentSyllable( w, 3 );
2
gap> GeneratorSyllable( w, 3 );
1
gap> SubSyllables( w, 2, 3 );
b*a^2
\endexample

There are two internal representations of associative words: By letters
and by syllables (see~"Representations for Associative Words"). Unless
something else is specified, words are stored in the letter
representation. Note, however, that operations to extract or act on
parts of words (letter or syllables) can carry substantially different
costs, depending on the representation the words are in.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Representations for Associative Words}

{\GAP} provides two different internal kinds of representations of
associative words.  The first one are ``syllable representations'' in which
words are stored in syllable (i.e. generator,exponent) form. (Older versions
of {\GAP} only used this representation.) The second kind are ``letter
representations'' in which each letter in a word is represented by its index
number. Negative numbers are used for inverses. Unless the syllable
representation is specified explicitly when creating the free group/monoid
or semigroup, a letter representation is used by default.

Depending on the task in mind, either of these two representations will
perform better in time or in memory use and algorithms that are syllable or
letter based (for example `GeneratorSyllable' and `Subword') perform
substantially better in the corresponding representation.
For example when creating pc groups (see~"Pc groups"), it is advantageous to
use a syllable representation while calculations in free groups usually
benefit from using a letter representation.

\>IsLetterAssocWordRep( <obj> ) R

A word in letter representation stores a list of generator/inverses
numbers (as given by `LetterRepAssocWord'). Letter access is fast,
syllable access is slow for such words.



\>IsLetterWordsFamily( <obj> ) C

A letter word family stores words by default in letter form. 



Internally, there are letter representations that use integers (4 Byte) to
represent a generator and letter representations that use single bytes to
represent a character. The latter are more memory efficient, but can only be
used if there are less than 128 generators (in which case they are used by
default).

\>IsBLetterAssocWordRep( <obj> ) R
\>IsWLetterAssocWordRep( <obj> ) R

these two subrepresentations of `IsLetterAssocWordRep' indicate whether
the word is stored as a list of bytes (in a string) or as a list of
integers)


\>IsBLetterWordsFamily( <obj> ) C
\>IsWLetterWordsFamily( <obj> ) C

These two subcategories of `IsLetterWordsFamily' specify the type of
letter representation to be used.



\>IsSyllableAssocWordRep( <obj> ) R

A word in syllable representation stores generator/exponents pairs (as
given by `ExtRepOfObj'. Syllable access is fast, letter access is slow
for such words.

\>IsSyllableWordsFamily( <obj> ) C

A syllable word family stores words by default in syllable form.


There are also different versions of syllable representations, which
compress a generator exponent pair in 8,16 or 32 bits or use a pair of
integers. Internal mechanisms try to make this as memory efficient as
possible.
\>Is8BitsFamily( <obj> ) C
\>Is16BitsFamily( <obj> ) C
\>Is32BitsFamily( <obj> ) C
\>IsInfBitsFamily( <obj> ) C



Regardless of the internal representation used, it is possible to convert a
word in a list of numbers in letter or syllable representation and vice
versa:

\>LetterRepAssocWord( <w> ) O
\>LetterRepAssocWord( <w>, <gens> ) O

The *letter representation* of an associated word is as a list of
integers, each entry corresponding to a group generator. Inverses of the
generators are represented by negative numbers. The generator numbers
are as associated to the family.

This operation returns the letter representation of the associative word
<w>.

In the second variant, the generator numbers correspond to the
generator order given in the list <gens>.

(For words stored in syllable form the letter representation has to be
comnputed.)


\>AssocWordByLetterRep( <Fam>, <lrep> [, <gens>] ) O

takes a letter representation <lrep> (see `LetterRepAssocWord',
section~"LetterRepAssocWord") and returns an associative word in
family <fam>. corresponding to this letter representation.

If <gens> is given, the numbers in the letter
rerpresentation correspond to <gens>.

\beginexample
gap> w:=AssocWordByLetterRep( FamilyObj(a), [-1,2,1,-2,-2,-2,1,1,1,1]);
a^-1*b*a*b^-3*a^4
gap> LetterRepAssocWord( w^2 );
[ -1, 2, 1, -2, -2, -2, 1, 1, 1, 2, 1, -2, -2, -2, 1, 1, 1, 1 ]
\endexample

The external representation (see section~"The External Representation for
Associative Words") can be used if a syllable representation is needed.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{The External Representation for Associative Words}

The external representation of the associative word $w$ is defined as
follows.
If $w = g_{i_1}^{e_1} * g_{i_2}^{e_2} * \cdots * g_{i_k}^{e_k}$
is a word over the alphabet $g_1, g_2, \ldots$,
i.e., $g_i$ denotes the $i$-th generator of the family of $w$,
then $w$ has external representation
$[ i_1, e_1, i_2, e_2, \ldots, i_k, e_k ]$.
The empty list describes the identity element (if exists) of the family.
Exponents may be negative if the family allows inverses.
The external representation of an associative word is guaranteed to be
freely reduced;
for example, $g_1 * g_2 * g_2^{-1} * g_1$ has the external representation
`[ 1, 2 ]'.

Regardless of the family preference for letter or syllable
representations (see~"Representations for Associative Words"),
`ExtRepOfObj' and `ObjByExtRep' can be used and interface to this
``syllable''-like representation.


\beginexample
gap> w:= ObjByExtRep( FamilyObj(a), [1,5,2,-7,1,3,2,4,1,-2] );
a^5*b^-7*a^3*b^4*a^-2
gap> ExtRepOfObj( w^2 );
[ 1, 5, 2, -7, 1, 3, 2, 4, 1, 3, 2, -7, 1, 3, 2, 4, 1, -2 ]
\endexample


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Straight Line Programs}

*Straight line programs* describe an efficient way for evaluating an
abstract word at concrete generators,
in a more efficient way than with `MappedWord' (see~"MappedWord").
For example, the associative word $ababbab$ of length $7$ can be computed
from the generators $a$, $b$ with only four multiplications,
by first computing $c = ab$, then $d = cb$, and then $cdc$;
Alternatively, one can compute $c = ab$, $e = bc$, and $aee$.
In each step of these computations, one forms words in terms of the
words computed in the previous steps.

A straight line program in {\GAP} is represented by an object in the
category `IsStraightLineProgram' (see~"IsStraightLineProgram")
that stores a list of ``lines''
each of which has one of the following three forms.
\beginlist%ordered
\item{1.}
    a nonempty dense list $l$ of integers,
\item{2.}
    a pair $[ l, i ]$
    where $l$ is a list of form 1. and $i$ is a positive integer,
\item{3.}
    a list $[ l_1, l_2, \ldots, l_k ]$
    where each $l_i$ is a list of form 1.;
    this may occur only for the last line of the program.
\endlist

The lists of integers that occur are interpreted as external
representations of associative words
(see~"The External Representation for Associative Words");
for example, the list $[ 1, 3, 2, -1 ]$ represents the word
$g_1^3 g_2^{-1}$, with $g_1$ and $g_2$ the first and second abstract
generator, respectively.

Straight line programs can be constructed using
`StraightLineProgram' (see~"StraightLineProgram").

Defining attributes for straight line programs are
`NrInputsOfStraightLineProgram' (see~"NrInputsOfStraightLineProgram")
and `LinesOfStraightLineProgram' (see~"LinesOfStraightLineProgram").
Another operation for straight line programs is
`ResultOfStraightLineProgram' (see~"ResultOfStraightLineProgram").

Special methods applicable to straight line programs are installed for
the operations `Display', `IsInternallyConsistent', `PrintObj',
and `ViewObj'.

For a straight line program <prog>, the default `Display' method prints
the interpretation of <prog> as a sequence of assignments of associative
words;
a record with components `gensnames' (with value a list of strings)
and `listname' (a string) may be entered as second argument of `Display',
in this case these names are used, the default for `gensnames' is
$[ `g1', `g2', \ldots ]$, the default for `listname' is $r$.



\>IsStraightLineProgram( <obj> ) C

Each straight line program in {\GAP} lies in the category
`IsStraightLineProgram'.


\>StraightLineProgram( <lines>[, <nrgens>] ) F
\>StraightLineProgram( <string>, <gens> ) F
\>StraightLineProgramNC( <lines>[, <nrgens>] ) F
\>StraightLineProgramNC( <string>, <gens> ) F

In the first form, <lines> must be a list of lists that defines a unique
straight line program (see~"IsStraightLineProgram");
in this case `StraightLineProgram' returns this program,
otherwise an error is signalled.
The optional argument <nrgens> specifies the number of input generators
of the program;
if a line of form 1. (that is, a list of integers) occurs in <lines>
except in the last position, this number is not determined by <lines>
and therefore *must* be specified by the argument <nrgens>;
if not then `StraightLineProgram' returns `fail'.

In the second form, <string> must be a string describing an arithmetic
expression in terms of the strings in the list <gens>,
where multiplication is denoted by concatenation, powering is denoted by
`^', and round brackets `(', `)' may be used.
Each entry in <gens> must consist only of (uppercase or lowercase)
letters (i.e., letters in `IsAlphaChar', see~"IsAlphaChar")
such that no entry is an initial part of another one.
Called with this input, `StraightLineProgramNC' returns a straight line
program that evaluates to the word corresponding to <string> when called
with generators corresponding to <gens>.

`StraightLineProgramNC' does the same as `StraightLineProgram',
except that the internal consistency of the program is not checked.


\>LinesOfStraightLineProgram( <prog> ) A

For a straight line program <prog>, `LinesOfStraightLineProgram' returns
the list of program lines.
There is no default method to compute these lines if they are not stored.


\>NrInputsOfStraightLineProgram( <prog> ) A

For a straight line program <prog>, `NrInputsOfStraightLineProgram'
returns the number of generators that are needed as input.

If a line of form 1. (that is, a list of integers) occurs in the lines of
<prog> except the last line
then the number of generators is not determined by the lines,
and must be set in the construction of the straight line program
(see~"StraightLineProgram").
So if <prog> contains a line of form 1. other than the last line
and does *not* store the number of generators
then `NrInputsOfStraightLineProgram' signals an error.


\>ResultOfStraightLineProgram( <prog>, <gens> ) O

`ResultOfStraightLineProgram' evaluates the straight line program
(see~"IsStraightLineProgram") <prog> at the group elements in the list
<gens>.

The *result* of a straight line program with lines
$p_1, p_2, \ldots, p_k$
when applied to <gens> is defined as follows.
\beginlist%ordered{a}
\item{(a)}
    First a list $r$ of intermediate results is initialized
    with a shallow copy of $<gens>$.
\item{(b)}
    For $i \< k$, before the $i$-th step, let $r$ be of length $n$.
    If $p_i$ is the external representation of an associative word
    in the first $n$ generators then the image of this word under the
    homomorphism that is given by mapping $r$ to these first $n$
    generators is added to $r$;
    if $p_i$ is a pair $[ l, j ]$, for a list $l$, then the same element
    is computed, but instead of being added to $r$,
    it replaces the $j$-th entry of $r$.
\item{(c)}
    For $i = k$, if $p_k$ is the external representation of an
    associative word then the element described in (b) is the result
    of the program,
    if $p_k$ is a pair $[ l, j ]$, for a list $l$, then the result is
    the element described by $l$,
    and if $p_k$ is a list $[ l_1, l_2, \ldots, l_k ]$ of lists
    then the result is a list of group elements, where each $l_i$ is
    treated as in (b).
\endlist

Here are some examples.
\beginexample
gap> f:= FreeGroup( "x", "y" );;  gens:= GeneratorsOfGroup( f );;
gap> x:= gens[1];;  y:= gens[2];;
gap> prg:= StraightLineProgram( [ [] ] );
<straight line program>
gap> ResultOfStraightLineProgram( prg, [] );
[  ]
\endexample
The above straight line program `prg' returns
--for *any* list of input generators-- an empty list.
\beginexample
gap> StraightLineProgram( [ [1,2,2,3], [3,-1] ] );
fail
gap> prg:= StraightLineProgram( [ [1,2,2,3], [3,-1] ], 2 );
<straight line program>
gap> LinesOfStraightLineProgram( prg );
[ [ 1, 2, 2, 3 ], [ 3, -1 ] ]
gap> prg:= StraightLineProgram( "(a^2b^3)^-1", [ "a", "b" ] );
<straight line program>
gap> LinesOfStraightLineProgram( prg );
[ [ [ 1, 2, 2, 3 ], 3 ], [ [ 3, -1 ], 4 ] ]
gap> res:= ResultOfStraightLineProgram( prg, gens );
y^-3*x^-2
gap> res = (x^2 * y^3)^-1;
true
gap> NrInputsOfStraightLineProgram( prg );
2
gap> Print( prg, "\n" );
StraightLineProgram( [ [ [ 1, 2, 2, 3 ], 3 ], [ [ 3, -1 ], 4 ] ], 2 )
gap> Display( prg );
# input:
r:= [ g1, g2 ];
# program:
r[3]:= r[1]^2*r[2]^3;
r[4]:= r[3]^-1;
# return value:
r[4]
gap> IsInternallyConsistent( StraightLineProgramNC( [ [1,2] ] ) );
true
gap> IsInternallyConsistent( StraightLineProgramNC( [ [1,2,3] ] ) );
false
gap> prg1:= StraightLineProgram( [ [1,1,2,2], [3,3,1,1] ], 2 );;
gap> prg2:= StraightLineProgram( [ [ [1,1,2,2], 2 ], [2,3,1,1] ] );;
gap> res1:= ResultOfStraightLineProgram( prg1, gens );
x*y^2*x*y^2*x*y^2*x
gap> res1 = (x*y^2)^3*x;
true
gap> res2:= ResultOfStraightLineProgram( prg2, gens );
x*y^2*x*y^2*x*y^2*x
gap> res2 = (x*y^2)^3*x;
true
gap> prg:= StraightLineProgram( [ [2,3], [ [3,1,1,4], [1,2,3,1] ] ], 2 );;
gap> res:= ResultOfStraightLineProgram( prg, gens );
[ y^3*x^4, x^2*y^3 ]
\endexample


\>StringOfResultOfStraightLineProgram( <prog>, <gensnames>[, \"LaTeX\"] ) F

`StringOfResultOfStraightLineProgram' returns a string that describes the
result of the straight line program (see~"IsStraightLineProgram") <prog>
as word(s) in terms of the strings in the list <gensnames>.
If the result of <prog> is a single element then the return value of
`StringOfResultOfStraightLineProgram' is a string consisting of the
entries of <gensnames>, opening and closing brackets `(' and `)',
and powering by integers via `^'.
If the result of <prog> is a list of elements then the return value of
`StringOfResultOfStraightLineProgram' is a comma separated concatenation
of the strings of the single elements,
enclosed in square brackets `[', `]'.



\beginexample
gap> prg:= StraightLineProgram( [ [ 1, 2, 2, 3 ], [ 3, -1 ] ], 2 );;
gap> StringOfResultOfStraightLineProgram( prg, [ "a", "b" ] );
"(a^2b^3)^-1"
gap> StringOfResultOfStraightLineProgram( prg, [ "a", "b" ], "LaTeX" );
"(a^{2}b^{3})^{-1}"
\endexample

\>CompositionOfStraightLinePrograms( <prog2>, <prog1> ) F

For two straight line programs <prog1> and <prog2>,
`CompositionOfStraightLinePrograms' returns a straight line program
<prog> with the properties that <prog1> and <prog> have the same number
of inputs, and the result of <prog> when applied to given generators
<gens> equals the result of <prog2> when this is applied to the output of
<prog1> applied to <gens>.

(Of course the number of outputs of <prog1> must be the same as the
number of inputs of <prog2>.)


\beginexample
gap> prg1:= StraightLineProgram( "a^2b", [ "a","b" ] );;
gap> prg2:= StraightLineProgram( "c^5", [ "c" ] );;
gap> comp:= CompositionOfStraightLinePrograms( prg2, prg1 );
<straight line program>
gap> StringOfResultOfStraightLineProgram( comp, [ "a", "b" ] );
"(a^2b)^5"
gap> prg:= StraightLineProgram( [ [2,3], [ [3,1,1,4], [1,2,3,1] ] ], 2 );;
gap> StringOfResultOfStraightLineProgram( prg, [ "a", "b" ] );
"[ b^3a^4, a^2b^3 ]"
gap> comp:= CompositionOfStraightLinePrograms( prg, prg );
<straight line program>
gap> StringOfResultOfStraightLineProgram( comp, [ "a", "b" ] );
"[ (a^2b^3)^3(b^3a^4)^4, (b^3a^4)^2(a^2b^3)^3 ]"
\endexample

\>IntegratedStraightLineProgram( <listofprogs> ) F

For a nonempty dense list <listofprogs> of straight line programs
that have the same number $n$, say, of inputs
(see~"NrInputsOfStraightLineProgram")
and for which the results (see~"ResultOfStraightLineProgram") are single
elements (i.e., *not* lists of elements),
`IntegratedStraightLineProgram' returns a straight line program <prog>
with $n$ inputs such that for each $n$-tuple <gens> of generators,
`ResultOfStraightLineProgram( <prog>, <gens> )' is equal to the list
`List( <listofprogs>, <p> -> ResultOfStraightLineProgram( <p>, <gens> )'.


\beginexample
gap> f:= FreeGroup( "x", "y" );;  gens:= GeneratorsOfGroup( f );;
gap> prg1:= StraightLineProgram( [ [ [ 1, 2 ], 1 ], [ 1, 2, 2, -1 ] ], 2 );;
gap> prg2:= StraightLineProgram( [ [ [ 2, 2 ], 3 ], [ 1, 3, 3, 2 ] ], 2 );;
gap> prg3:= StraightLineProgram( [ [ 2, 2 ], [ 1, 3, 3, 2 ] ], 2 );;
gap> prg:= IntegratedStraightLineProgram( [ prg1, prg2, prg3 ] );;
gap> ResultOfStraightLineProgram( prg, gens );
[ x^4*y^-1, x^3*y^4, x^3*y^4 ]
gap> prg:= IntegratedStraightLineProgram( [ prg2, prg3, prg1 ] );;
gap> ResultOfStraightLineProgram( prg, gens );
[ x^3*y^4, x^3*y^4, x^4*y^-1 ]
gap> prg:= IntegratedStraightLineProgram( [ prg3, prg1, prg2 ] );;
gap> ResultOfStraightLineProgram( prg, gens );
[ x^3*y^4, x^4*y^-1, x^3*y^4 ]
\endexample


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Straight Line Program Elements}

When computing with very large (in terms of memory) elements, for
example permutations of degree a few hundred thousands, it can be
helpful (in terms of memory usage) to represent them via straight line
programs in terms of an original generator set. (So every element takes
only small extra storage for the straight line program.)

A straight line program element has a *seed* (a list of group elements)
and a straight line program on the same number of generators as the
length of this seed, its value is the value of the evaluated straight
line program. 

At the moment, the entries of the straight line program have to be
simple lists (i.e. of the first form).

Straight line program elements are in the same categories
and families as the elements of the seed, so they should work together
with existing algorithms.

Note however, that due to the different way of storage some normally
very cheap operations (such as testing for element equality) can become
more expensive when dealing with straight line program elements. This is
essentially the tradeoff for using less memory.


\>IsStraightLineProgElm( <obj> ) R

A straight line program element is a group element given (for memory
reasons) as a straight line program. Straight line program elements are
positional objects, the first component is a record with a component
`seeds', the second component the straight line program.
we need to rank higher than default methods

\>StraightLineProgElm( <seed>, <prog> ) F

Creates a straight line program element for seed <seed> and program
<prog>.

\>StraightLineProgGens( <gens>[, <base>] ) F

returns a set of straight line program elements corresponding to the
generators in <gens>.
If <gens> is a set of permutations then <base> can be given which must
be a base for the group generated by <gens>. (Such a base will be used to
speed up equality tests.)

\>EvalStraightLineProgElm( <slpel> ) F

evaluates a straight line program element <slpel> from its seeds.

\>StretchImportantSLPElement( <elm> ) O

If <elm> is a straight line program element whose straight line
representation is very long, this operation changes the
representation of <elm> to a straight line program element, equal to
<elm>, whose seed contains the evaluation of <elm> and whose straight
line program has length 1.

For other objects nothing happens.

This operation permits to designate ``important'' elements within an
algorithm (elements that wil be referred to often), which will be
represented by guaranteed short straight line program elements.


\beginexample
gap> gens:=StraightLineProgGens([(1,2,3,4),(1,2)]);
[ <[ [ 2, 1 ] ]||(1,2,3,4)>, <[ [ 1, 1 ] ]||(1,2)> ]
gap> g:=Group(gens);;
gap> (gens[1]^3)^gens[2];
<[ [ 1, -1, 2, 3, 1, 1 ] ]||(1,2,4,3)>
gap> Size(g);
24
gap> Random(g);
<[ [ 1, -1, 2, -1, 1, 1, 2, -1, 1, -1, 2, 1, 1, 1, 2, 1, 1, -1, 2, 2, 1, 1 ], 
  [ 3, -2, 2, -2, 1, -1, 2, -2, 1, 1 ], [ 4, 1, 2, -1, 4, 1 ] ]||(1,2,3,4)>
\endexample

See also Section~"Working with large degree permutation groups".

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%E

