diff --git a/doc/ref/grplib.xml b/doc/ref/grplib.xml
index cc8061fe59..e3b49e639e 100644
--- a/doc/ref/grplib.xml
+++ b/doc/ref/grplib.xml
@@ -106,7 +106,7 @@ It is possible to influence this naming with the option generatorNames,
see Section .
If this option holds a string, then the generators are named with this
string and sequential numbers starting with 1.
-If this option holds a list of sufficient length consisting of
+If this option holds a list of sufficient length consisting of distinct
nonempty strings, then the generator names are taken from this list, in order.
## is a free (nonassociative) algebra of rank rank
## over the division ring R.
-## Here name, and name1, name2, ... are optional strings
+## Here name, and name1, name2, ... are optional
+## distinct nonempty strings
## that can be used to provide names for the generators.
## A:= FreeAlgebra( Rationals, "a", "b" );
@@ -1523,7 +1524,8 @@ DeclareGlobalFunction( "FreeAlgebra" );
##
## is a free (nonassociative) algebra-with-one of rank rank
## over the division ring R.
-## Here name, and name1, name2, ... are optional strings
+## Here name, and name1, name2, ... are optional
+## distinct nonempty strings
## that can be used to provide names for the generators.
## A:= FreeAlgebraWithOne( Rationals, 4, "q" );
@@ -1555,7 +1557,8 @@ DeclareGlobalFunction( "FreeAlgebraWithOne" );
##
## is a free associative algebra of rank rank over the
## division ring R.
-## Here name, and name1, name2, ... are optional strings
+## Here name, and name1, name2, ... are optional
+## distinct nonempty strings
## that can be used to provide names for the generators.
## A:= FreeAssociativeAlgebra( GF( 5 ), 4, "a" );
@@ -1583,7 +1586,8 @@ DeclareGlobalFunction( "FreeAssociativeAlgebra" );
##
## is a free associative algebra-with-one of rank rank over the
## division ring R.
-## Here name, and name1, name2, ... are optional strings
+## Here name, and name1, name2, ... are optional
+## distinct nonempty strings
## that can be used to provide names for the generators.
## A:= FreeAssociativeAlgebraWithOne( Rationals, "a", "b", "c" );
diff --git a/lib/algebra.gi b/lib/algebra.gi
index cf086ff597..4006198931 100644
--- a/lib/algebra.gi
+++ b/lib/algebra.gi
@@ -3322,6 +3322,10 @@ BindGlobal( "FreeAlgebraConstructor", function( name, magma )
"or ", name, "( , , ... )" );
fi;
+ if not IsDuplicateFreeList(names) then
+ Error( "the given generator names must be distinct" );
+ fi;
+
M := magma( names );
# Construct the algebra as free magma algebra of a free magma over `R'.
diff --git a/lib/alglie.gd b/lib/alglie.gd
index 31cc718ee0..e2b235d778 100644
--- a/lib/alglie.gd
+++ b/lib/alglie.gd
@@ -1253,6 +1253,7 @@ DeclareAttribute(
## FreeLieAlgebra( R, name1, name2,...) returns
## a free Lie algebra over R with generators named name1,
## name2, and so on.
+## Note that any provided generator names must be distinct.
## The elements of a free Lie algebra are written on the Hall-Lyndon
## basis.
##
## 2: For given generator names
## -
-## Called with various nonempty strings,
+## Called with various distinct nonempty strings,
##
returns
## a free group on as many generators as arguments, which are labelled
## name1, name2, etc.
##
## 3: For a given list of generator names
## -
-## Called with a finite list names of
+## Called with a finite duplicate-free list names of
## nonempty strings,
##
returns
## a free group on Length(names) generators, whose
@@ -104,11 +104,12 @@ DeclareSynonym( "IsElementOfFreeGroupFamily",IsAssocWordWithInverseFamily );
## The optional argument name must be a string; its default value is
## "f",
## and the optional argument init must be a finite list of
-## nonempty strings; its default value is an empty list.
+## distinct nonempty strings; its default value is an empty list.
## The generators are initially labelled according to the list init,
## followed by
## namei for each i in the range from
-## Length(init)+1 to infinity.
+## Length(init)+1 to infinity; such a label is not
+## allowed to appear in init.
##
##
## If the optional first argument wfilt is given, then it must be either
diff --git a/lib/magma.gd b/lib/magma.gd
index 975244d64c..6d706c6647 100644
--- a/lib/magma.gd
+++ b/lib/magma.gd
@@ -818,7 +818,7 @@ DeclareGlobalFunction("FreeXArgumentProcessor");
##
## 2: For given generator names
## -
-## Called with various (at least one) nonempty strings,
+## Called with various (one or more) distinct nonempty strings,
##
returns
## a free magma on as many generators as arguments, which are labelled
## name1, name2, etc.
@@ -826,7 +826,7 @@ DeclareGlobalFunction("FreeXArgumentProcessor");
## 3: For a given list of generator names
## -
## Called with a finite nonempty list names of
-## nonempty strings,
+## distinct nonempty strings,
##
returns
## a free magma on Length(names) generators, whose
## i-th generator is labelled names[i].
@@ -843,11 +843,12 @@ DeclareGlobalFunction("FreeXArgumentProcessor");
## The optional argument name must be a string; its default value is
## "x",
## and the optional argument init must be a finite list of
-## nonempty strings; its default value is an empty list.
+## distinct nonempty strings; its default value is an empty list.
## The generators are initially labelled according to the list init,
## followed by
## namei for each i in the range from
-## Length(init)+1 to infinity.
+## Length(init)+1 to infinity; such a label is not
+## allowed to appear in init.
##
##
##
## 2: For given generator names
## -
-## Called with various nonempty strings,
+## Called with various (one or more) distinct nonempty strings,
##
returns
## a free magma-with-one on as many generators as arguments, which are
## labelled name1, name2, etc.
@@ -939,7 +940,7 @@ DeclareGlobalFunction( "FreeMagma" );
## 3: For a given list of generator names
## -
## Called with a finite list names of
-## nonempty strings,
+## distinct nonempty strings,
##
returns
## a free magma-with-one on Length(names) generators, whose
## i-th generator is labelled names[i].
@@ -956,11 +957,12 @@ DeclareGlobalFunction( "FreeMagma" );
## The optional argument name must be a string; its default value is
## "x",
## and the optional argument init must be a finite list of
-## nonempty strings; its default value is an empty list.
+## distinct nonempty strings; its default value is an empty list.
## The generators are initially labelled according to the list init,
## followed by
## namei for each i in the range from
-## Length(init)+1 to infinity.
+## Length(init)+1 to infinity; such a label is not
+## allowed to appear in init.
##
##
## IsString( opt[s] ) and not IsEmpty( opt[s] ) ) then
+ s -> IsString( opt[s] ) and not IsEmpty( opt[s] ) )
+ and IsDuplicateFreeList( opt{[ 1 .. rank ]} ) then
names := MakeImmutable( opt{[ 1 .. rank ]} );
else
ErrorNoReturn( Concatenation(
"Cannot process the `generatorNames` option: ",
"the value must be either a single string, or a list ",
- "of sufficiently many nonempty strings ",
+ "of sufficiently many distinct nonempty strings ",
"(at least ", String( rank ), ", in this case)" ) );
fi;
@@ -378,6 +380,8 @@ function(
err := "there must be only finitely many names";
elif not ForAll( names, s -> IsString( s ) and not IsEmpty( s ) ) then
err := "the names must be nonempty strings";
+ elif not IsDuplicateFreeList( names ) then
+ err := "the names must be distinct";
fi;
# Validate call of form: func( infinity[, ][, ] ).
@@ -404,8 +408,22 @@ function(
err := " must be a string";
elif not ( IsList( init ) and IsFinite( init ) ) then
err := " must be a finite list";
+ elif not IsDuplicateFreeList( init ) then
+ err := " must be duplicate-free";
elif not ForAll( init, s -> IsString( s ) and not IsEmpty( s ) ) then
err := " must consist of nonempty strings";
+ else
+ for word in init do
+ if StartsWith( word, name ) then
+ x := word{[ Length( name ) + 1 .. Length( word ) ]};
+ if not IsEmpty( x ) and ForAll( x, IsDigitChar )
+ and Int( x ) > Length( init ) then
+ err := "no member of may repeat any of the infinitely many ";
+ Append( err, "generators that begin with " );
+ break;
+ fi;
+ fi;
+ od;
fi;
if IsEmpty( err ) then
names := InfiniteListOfNames( name, init );
diff --git a/lib/monoid.gd b/lib/monoid.gd
index 223c608195..cddc41b9d7 100644
--- a/lib/monoid.gd
+++ b/lib/monoid.gd
@@ -231,7 +231,7 @@ DeclareSynonymAttr( "TrivialSubmonoid", TrivialSubmagmaWithOne );
##
## 2: For given generator names
## -
-## Called with various nonempty strings,
+## Called with various (one or more) distinct nonempty strings,
##
returns
## a free monoid on as many generators as arguments, which are labelled
## name1, name2, etc.
@@ -239,7 +239,7 @@ DeclareSynonymAttr( "TrivialSubmonoid", TrivialSubmagmaWithOne );
## 3: For a given list of generator names
## -
## Called with a finite list names of
-## nonempty strings,
+## distinct nonempty strings,
##
returns
## a free monoid on Length(names) generators, whose
## i-th generator is labelled names[i].
@@ -256,11 +256,12 @@ DeclareSynonymAttr( "TrivialSubmonoid", TrivialSubmagmaWithOne );
## The optional argument name must be a string; its default value is
## "m",
## and the optional argument init must be a finite list of
-## nonempty strings; its default value is an empty list.
+## distinct nonempty strings; its default value is an empty list.
## The generators are initially labelled according to the list init,
## followed by
## namei for each i in the range from
-## Length(init)+1 to infinity.
+## Length(init)+1 to infinity; such a label is not
+## allowed to appear in init.
##
##
##
diff --git a/lib/semigrp.gd b/lib/semigrp.gd
index 12765fa6ed..70b3b75d9a 100644
--- a/lib/semigrp.gd
+++ b/lib/semigrp.gd
@@ -300,7 +300,7 @@ DeclareAttribute("CayleyGraphDualSemigroup",IsSemigroup);
## generators, and the labels given to the generators, can be specified in
## several different ways.
## Warning: the labels of generators are only an aid for printing,
-## and do not necessarily distinguish generators;
+## and do not necessarily distinguish elements of the semigroup;
## see the examples at the end for more information.
##
##
@@ -323,7 +323,7 @@ DeclareAttribute("CayleyGraphDualSemigroup",IsSemigroup);
##
## 2: For given generator names
## -
-## Called with various (at least one) nonempty strings,
+## Called with various (one or more) distinct nonempty strings,
##
returns
## a free semigroup on as many generators as arguments, which are labelled
## name1, name2, etc.
@@ -331,7 +331,7 @@ DeclareAttribute("CayleyGraphDualSemigroup",IsSemigroup);
## 3: For a given list of generator names
## -
## Called with a nonempty finite list names of
-## nonempty strings,
+## distinct nonempty strings,
##
returns
## a free semigroup on Length(names) generators, whose
## i-th generator is labelled names[i].
@@ -417,6 +417,8 @@ DeclareAttribute("CayleyGraphDualSemigroup",IsSemigroup);
## distinguish letters.
## It is possible to create arbitrarily weird situations by choosing strange
## names for the letters.
+## However, as a small step to avoiding confusion, it is disallowed to choose
+## duplicate generator names.
##
## f := FreeGroup( "x", "x" );
diff --git a/tst/testinstall/grpfree.tst b/tst/testinstall/grpfree.tst
index 7271f9c467..ea4c456f26 100644
--- a/tst/testinstall/grpfree.tst
+++ b/tst/testinstall/grpfree.tst
@@ -167,6 +167,10 @@ gap> FreeGroup("bacon", "eggs", "beans");
gap> FreeGroup("shed");
+gap> FreeGroup("shed", "shed");
+Error, FreeGroup( , , ... ): the names must be distinct
+gap> FreeGroup("a", "b", "c", "d", "b", "e", "f");
+Error, FreeGroup( , , ... ): the names must be distinct
# FreeGroup( [ , , ... ] )
gap> FreeGroup(InfiniteListOfNames("a"));
diff --git a/tst/testinstall/mgmfree.tst b/tst/testinstall/mgmfree.tst
index 814c558adc..8d454cc27d 100644
--- a/tst/testinstall/mgmfree.tst
+++ b/tst/testinstall/mgmfree.tst
@@ -113,6 +113,10 @@ gap> FreeMagma("bacon", "eggs", "beans");
gap> FreeMagma("shed");
+gap> FreeMagma("shed", "shed");
+Error, FreeMagma( , , ... ): the names must be distinct
+gap> FreeMagma("a", "b", "c", "d", "b", "e", "f");
+Error, FreeMagma( , , ... ): the names must be distinct
# FreeMagma( [ [, , ...] ] )
gap> FreeMagma(InfiniteListOfNames("a"));
@@ -238,6 +242,10 @@ gap> FreeMagmaWithOne("bacon", "eggs", "beans");
gap> FreeMagmaWithOne("shed");
+gap> FreeMagmaWithOne("shed", "shed");
+Error, FreeMagmaWithOne( , , ... ): the names must be distinct
+gap> FreeMagmaWithOne("a", "b", "c", "d", "b", "e", "f");
+Error, FreeMagmaWithOne( , , ... ): the names must be distinct
# FreeMagmaWithOne( [ [, , ...] ] )
gap> FreeMagmaWithOne(InfiniteListOfNames("a"));
diff --git a/tst/testinstall/monofree.tst b/tst/testinstall/monofree.tst
index 7897a3c588..a99e4e5656 100644
--- a/tst/testinstall/monofree.tst
+++ b/tst/testinstall/monofree.tst
@@ -133,6 +133,10 @@ gap> FreeMonoid("bacon", "eggs", "beans");
gap> FreeMonoid("shed");
+gap> FreeMonoid("shed", "shed");
+Error, FreeMonoid( , , ... ): the names must be distinct
+gap> FreeMonoid("a", "b", "c", "d", "b", "e", "f");
+Error, FreeMonoid( , , ... ): the names must be distinct
# FreeMonoid( [ , , ... ] )
gap> FreeMonoid(InfiniteListOfNames("a"));
diff --git a/tst/testinstall/smgrpfre.tst b/tst/testinstall/smgrpfre.tst
index 4423b21e18..a94495e464 100644
--- a/tst/testinstall/smgrpfre.tst
+++ b/tst/testinstall/smgrpfre.tst
@@ -147,8 +147,8 @@ Error, usage: FreeSemigroup( [, ][, ] )
# generatorNames
gap> FreeSemigroup(5 : generatorNames := false);
Error, Cannot process the `generatorNames` option: the value must be either a \
-single string, or a list of sufficiently many nonempty strings (at least 5, in\
- this case)
+single string, or a list of sufficiently many distinct nonempty strings (at le\
+ast 5, in this case)
gap> PushOptions( rec( generatorNames := fail ) );
gap> FreeSemigroup(3 : generatorNames := "");
@@ -156,8 +156,8 @@ gap> FreeSemigroup(2 : generatorNames := "cool");
gap> FreeSemigroup(2 : generatorNames := ["red"]);
Error, Cannot process the `generatorNames` option: the value must be either a \
-single string, or a list of sufficiently many nonempty strings (at least 2, in\
- this case)
+single string, or a list of sufficiently many distinct nonempty strings (at le\
+ast 2, in this case)
gap> PushOptions( rec( generatorNames := fail ) );
gap> FreeSemigroup(2 : generatorNames := ["red", "yellow"]);