From b0a76a42c2a0376e30e2ae08dbff9521c65e5f10 Mon Sep 17 00:00:00 2001 From: Wilf Wilson Date: Thu, 22 Apr 2021 11:19:01 +0100 Subject: [PATCH] Unify argument checking for some free objects In particular, unify argument processing/error checking in: * FreeSemigroup * FreeMonoid * FreeMagma * FreeMagmaWithOne * FreeGroup Resolves #1385. --- lib/grpfp.gi | 2 +- lib/grpfree.gi | 90 ++----------- lib/magma.gd | 48 ++++--- lib/mgmfree.gi | 250 +++++++++++++++++++++++++---------- lib/monofree.gi | 92 +++---------- lib/monoid.gd | 12 +- lib/semigrp.gd | 2 +- lib/smgrpfre.gi | 135 +++---------------- tst/testinstall/grpfree.tst | 118 +++++++++++++++++ tst/testinstall/mgmfree.tst | 246 ++++++++++++++++++++++++++++++++++ tst/testinstall/monofree.tst | 118 +++++++++++++++++ tst/testinstall/smgrpfre.tst | 12 +- 12 files changed, 758 insertions(+), 367 deletions(-) create mode 100644 tst/testinstall/mgmfree.tst diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 8ac226a671c..b53a8ccc269 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -5729,4 +5729,4 @@ InstallMethod( IndependentGeneratorsOfAbelianGroup, [ IsFpGroup and IsAbelian ], IndependentGeneratorsOfMaximalAbelianQuotientOfFpGroup ); -BindGlobal("TRIVIAL_FP_GROUP",FreeGroup(0,"TrivGp")/[]); +BindGlobal("TRIVIAL_FP_GROUP", FreeGroup(0) / [] ); diff --git a/lib/grpfree.gi b/lib/grpfree.gi index 0d26087406f..9dccc81cadd 100644 --- a/lib/grpfree.gi +++ b/lib/grpfree.gi @@ -424,80 +424,18 @@ InstallMethod( GeneratorsSmallest, ## InstallGlobalFunction( FreeGroup, function ( arg ) local names, # list of generators names - opt, - zarg, - lesy, # filter for letter or syllable words family F, # family of free group element objects - G; # free group, result + G, # free group, result + processed; - if ValueOption("FreeGroupFamilyType")="syllable" then - lesy:=IsSyllableWordsFamily; # optional -- used in PQ - else - lesy:=IsLetterWordsFamily; # default - fi; - if IsFilter(arg[1]) then - lesy:=arg[1]; - zarg:=arg{[2..Length(arg)]}; - else - zarg:=arg; - fi; - - # Get and check the argument list, and construct names if necessary. - if Length( zarg ) = 1 and zarg[1] = infinity then - names:= InfiniteListOfNames( "f" ); - elif Length( zarg ) = 2 and zarg[1] = infinity then - names:= InfiniteListOfNames( zarg[2] ); - elif Length( zarg ) = 3 and zarg[1] = infinity then - names:= InfiniteListOfNames( zarg[2], zarg[3] ); - elif Length( zarg ) = 1 and IsInt( zarg[1] ) and 0 <= zarg[1] then - names:= List( [ 1 .. zarg[1] ], - i -> Concatenation( "f", String(i) ) ); - MakeImmutable( names ); - elif Length( zarg ) = 2 and IsInt( zarg[1] ) and 0 <= zarg[1] then - names:= List( [ 1 .. zarg[1] ], - i -> Concatenation( zarg[2], String(i) ) ); - elif Length( zarg ) = 1 and IsList( zarg[1] ) and IsEmpty( zarg[1] ) then - names:= zarg[1]; - elif 1 <= Length( zarg ) and ForAll( zarg, IsString ) then - names:= zarg; - elif Length( zarg ) = 1 and IsList( zarg[1] ) - and ForAll( zarg[1], IsString ) then - names:= zarg[1]; - else - Error("usage: FreeGroup(,..) or FreeGroup()"); - fi; - - opt:=ValueOption("generatorNames"); - if opt<>fail then - if IsString(opt) then - names:= List( [ 1 .. Length(names) ], - i -> Concatenation( opt, String(i) ) ); - elif IsList(opt) and ForAll(opt,IsString) - and Length(names)<=Length(opt) then - names:=opt{[1..Length(names)]}; - MakeImmutable( names ); - else - Error("Cannot process `generatorNames` option"); - fi; - fi; - - # deal with letter words family types - if lesy=IsLetterWordsFamily then - if Length(names)>127 then - lesy:=IsWLetterWordsFamily; - else - lesy:=IsBLetterWordsFamily; - fi; - elif lesy=IsBLetterWordsFamily and Length(names)>127 then - lesy:=IsWLetterWordsFamily; - fi; + processed := FreeAlgebraCreatorArgumentProcessor( "FreeGroup", "f", arg ); + names := processed.names; # Construct the family of element objects of our group. - F:= NewFamily( "FreeGroupElementsFamily", IsAssocWordWithInverse - and IsElementOfFreeGroup, - CanEasilySortElements, # the free group can. - CanEasilySortElements # the free group can. - and lesy); + F := NewFamily( "FreeGroupElementsFamily", + IsAssocWordWithInverse and IsElementOfFreeGroup, + CanEasilySortElements, + CanEasilySortElements and processed.lesy ); # Install the data (names, no. of bits available for exponents, types). StoreInfoFreeMagma( F, names, IsAssocWordWithInverse @@ -511,22 +449,20 @@ InstallGlobalFunction( FreeGroup, function ( arg ) i -> ObjByExtRep( F, 1, 1, [ i, 1 ] ) ) ); else G:= GroupByGenerators( InfiniteListOfGenerators( F ) ); - SetIsFinitelyGeneratedGroup( G, false ); fi; + # Store the whole group in the family. SetIsWholeFamily( G, true ); + FamilyObj(G)!.wholeGroup := G; + F!.freeGroup:=G; + SetFilterObj(G,IsGroupOfFamily); # Store whether the group is trivial / abelian / solvable + SetIsFinitelyGeneratedGroup( G, IsFinite ( names ) ); SetIsTrivial( G, Length( names ) = 0 ); SetIsAbelian( G, Length( names ) <= 1 ); SetIsSolvableGroup( G, Length( names ) <= 1 ); - # Store the whole group in the family. - FamilyObj(G)!.wholeGroup := G; - F!.freeGroup:=G; - SetFilterObj(G,IsGroupOfFamily); - - # Return the free group. return G; end ); diff --git a/lib/magma.gd b/lib/magma.gd index a987a4ce2ea..d672dbef770 100644 --- a/lib/magma.gd +++ b/lib/magma.gd @@ -726,34 +726,40 @@ InParentFOA( "Centralizer", IsMagma, IsObject, DeclareAttribute ); DeclareOperation( "SquareRoots", [ IsMagma, IsMultiplicativeElement ] ); +################################################################################ +## +DeclareGlobalFunction("FreeAlgebraCreatorArgumentProcessor"); + + ############################################################################# ## -#F FreeMagma( [, ] ) -#F FreeMagma( , , ... ) -#F FreeMagma( ) -#F FreeMagma( infinity, , ) +#F FreeMagma( [ , ][, ] ) +#F FreeMagma( [ , ], , ... ) +#F FreeMagma( [ , ] ) +#F FreeMagma( [ , ]infinity[, [, ]] ) ## ## <#GAPDoc Label="FreeMagma"> ## ## FreeMagma -## -## -## -## ## ## ## Called with a positive integer rank, ## returns ## a free magma on rank generators. -## If the optional argument name is given then the generators are +## If the optional argument name (a string) is given, +## then the generators are ## printed as name1, name2 etc., ## that is, each name is the concatenation of the string name and an -## integer from 1 to range. -## The default for name is the string "m". +## integer from 1 to rank. +## The default for name is the string "x". ##

## Called in the second form, ## returns @@ -780,21 +786,21 @@ DeclareGlobalFunction( "FreeMagma" ); ############################################################################# ## -#F FreeMagmaWithOne( [, ] ) -#F FreeMagmaWithOne( , , ... ) -#F FreeMagmaWithOne( ) -#F FreeMagmaWithOne( infinity, , ) +#F FreeMagmaWithOne( [ , ][, ] ) +#F FreeMagmaWithOne( [ , ], , ... ) +#F FreeMagmaWithOne( [ , ] ) +#F FreeMagmaWithOne( [ , ]infinity[, [, ]] ) ## ## <#GAPDoc Label="FreeMagmaWithOne"> ## ## FreeMagmaWithOne -## -## -## -## ## ## @@ -804,8 +810,8 @@ DeclareGlobalFunction( "FreeMagma" ); ## If the optional argument name is given then the generators are ## printed as name1, name2 etc., ## that is, each name is the concatenation of the string name and an -## integer from 1 to range. -## The default for name is the string "m". +## integer from 1 to rank. +## The default for name is the string "x". ##

## Called in the second form, ## returns diff --git a/lib/mgmfree.gi b/lib/mgmfree.gi index 15e91b86ac1..f00dd08bb52 100644 --- a/lib/mgmfree.gi +++ b/lib/mgmfree.gi @@ -274,42 +274,181 @@ InstallMethod( MagmaGeneratorsOfFamily, ############################################################################# -## -#F FreeMagma( ) -#F FreeMagma( , ) -#F FreeMagma( , , ... ) -#F FreeMagma( ) -#F FreeMagma( infinity, , ) -## -InstallGlobalFunction( FreeMagma, - function( arg ) - local names, # list of generators names - F, # family of free magma element objects - M; # free magma, result - - # Get and check the argument list, and construct names if necessary. - if Length( arg ) = 1 and arg[1] = infinity then - names:= InfiniteListOfNames( "x" ); - elif Length( arg ) = 2 and arg[1] = infinity then - names:= InfiniteListOfNames( arg[2] ); - elif Length( arg ) = 3 and arg[1] = infinity then - names:= InfiniteListOfNames( arg[2], arg[3] ); - elif Length( arg ) = 1 and IsInt( arg[1] ) and 0 < arg[1] then - names:= List( [ 1 .. arg[1] ], - i -> Concatenation( "x", String(i) ) ); - MakeImmutable( names ); - elif Length( arg ) = 2 and IsInt( arg[1] ) and 0 < arg[1] then - names:= List( [ 1 .. arg[1] ], - i -> Concatenation( arg[2], String(i) ) ); +## Currently used by: +## FreeGroup, FreeMonoid, FreeSemigroup, FreeMagmaWithOne, FreeMagma +InstallGlobalFunction( FreeAlgebraCreatorArgumentProcessor, +function( func, name, arg ) + # func: The name of the calling function + # arg: The list of arguments passed to func that need to be processed + # name: The default prefix to use for generator names + local rank, + lesy, + opt, + init, + err, # string; helpful error message + form, # string: assumed argument form of call to + names; # list of generators names + + # FIXME this is not integrated properly, and is about to get overwritten maybe + if ValueOption( "FreeGroupFamilyType" ) = "syllable" then + lesy:=IsSyllableWordsFamily; # optional -- used in PQ + else + lesy:=IsLetterWordsFamily; # default + fi; + + # lesy: a filter for letter or syllable words family + + # TODO Does this cover all cases? + if not IsEmpty( arg ) and IsFilter( arg[1] ) then + # TODO what if optional first argument AND ValueOption is given + if ValueOption( "FreeGroupFamilyType" ) <> fail then + ErrorNoReturn("TODO"); + fi; + lesy := arg[1]; + Remove( arg, 1 ); + fi; + + # Process and validate the argument list, constructing names if necessary + err := ""; + form := fail; + names := []; + + if Length( arg ) = 0 or arg[1] = 0 + or (Length( arg ) = 1 and IsList( arg[1] ) and IsEmpty( arg[1] )) then + # rank 0 + + # func( [, ] ) + elif IsPosInt( arg[1] ) and Length( arg ) <= 2 then + + # Get default and optional arguments + rank := arg[1]; + if Length( arg ) = 2 then + name := arg[2]; + fi; + + # Error checking + if not IsString( name ) then + form := ", "; + err := " must be a string"; + + # Construct names + else + names:= List( [ 1 .. rank ], i -> Concatenation( name, String(i) ) ); MakeImmutable( names ); - elif 1 <= Length( arg ) and ForAll( arg, IsString ) then - names:= arg; - elif Length( arg ) = 1 and IsList( arg[1] ) - and not IsEmpty( arg[1] ) - and ForAll( arg[1], IsString ) then + fi; + + # func( [, , ...] ), or a list of such arguments + elif ForAll( arg, IsString ) or Length( arg ) = 1 and IsList( arg[1] ) then + if Length( arg ) = 1 and not IsString( arg[1] ) then + form := "[ , , ... ]"; names:= arg[1]; else - Error("usage: FreeMagma(,..),FreeMagma()"); + form := ", , ..."; + names:= arg; + fi; + if not ForAll( names, s -> IsString(s) and not IsEmpty(s) ) then + err := "the names must be nonempty strings"; + fi; + + # func( infinity[, [, ]] ) + elif arg[1] = infinity and Length( arg ) <= 3 then + + # Get default and optional arguments + init := []; + if Length( arg ) = 3 then + form := "infinity, , "; + name := arg[2]; + init := arg[3]; + elif Length( arg ) = 2 then + form := "infinity, "; + name := arg[2]; + fi; + + # Error checking + if not IsString( name ) then + err := " must be a string"; + fi; + if not ( IsList( init ) and ForAll( init, s -> IsString(s) and not IsEmpty(s) ) ) then + if not IsEmpty(err) then + Append(err, " and "); + fi; + Append(err, " must be a list of nonempty strings"); + fi; + + # Construct names + if IsEmpty(err) then + names := InfiniteListOfNames( name, init ); + fi; + + else + ErrorNoReturn( + StringFormatted( Concatenation( + #"Error, + "usage: {}( [, ][, ] )\n", + " {}( [, ], , ... )\n", + " {}( [, ] )\n", + " {}( [, ]infinity[, [, ]] )" + ), + func, func, func, func)); + fi; + + if not IsEmpty(err) then + ErrorNoReturn(StringFormatted("{}( {} ): {}", func, form, err)); + fi; + + # FIXME integrate this properly + opt:=ValueOption("generatorNames"); + if opt<>fail then + if IsString(opt) then + names:= List( [ 1 .. Length(names) ], + i -> Concatenation( opt, String(i) ) ); + elif IsList(opt) and ForAll(opt,IsString) + and Length(names)<=Length(opt) then + names:=opt{[1..Length(names)]}; + MakeImmutable( names ); + else + Error("Cannot process `generatorNames` option"); + fi; + fi; + + # FIXME this should also take into account the value option + # deal with letter words family types + if lesy = IsLetterWordsFamily then + if Length( names ) > 127 then + lesy := IsWLetterWordsFamily; + else + lesy := IsBLetterWordsFamily; + fi; + elif lesy = IsBLetterWordsFamily and Length( names ) > 127 then + lesy := IsWLetterWordsFamily; + fi; + + return rec( + names := names, + form := form, + lesy := lesy, + ); +end); + + +############################################################################# +## +#F FreeMagma( [ , ][, ] ) +#F FreeMagma( [ , ], , ... ) +#F FreeMagma( [ , ] ) +#F FreeMagma( [ , ]infinity[, [, ]] ) +## +InstallGlobalFunction( FreeMagma, function( arg ) + local names, # list of generators names + F, # family of free magma element objects + M, # free magma, result + processed; + + processed := FreeAlgebraCreatorArgumentProcessor("FreeMagma", "x", arg); + names := processed.names; + + if IsEmpty( names ) then + ErrorNoReturn( "free magmas of rank zero are not supported" ); fi; # Construct the family of element objects of our magma. @@ -334,43 +473,20 @@ end ); ############################################################################# ## -#F FreeMagmaWithOne( ) -#F FreeMagmaWithOne( , ) -#F FreeMagmaWithOne( , , ... ) -#F FreeMagmaWithOne( ) -#F FreeMagmaWithOne( infinity, , ) +#F FreeMagmaWithOne( [ , ][, ] ) +#F FreeMagmaWithOne( [ , ], , ... ) +#F FreeMagmaWithOne( [ , ] ) +#F FreeMagmaWithOne( [ , ]infinity[, [, ]] ) ## InstallGlobalFunction( FreeMagmaWithOne, function( arg ) - local names, # list of generators names - F, # family of free magma element objects - M; # free magma, result - - # Get and check the argument list, and construct names if necessary. - if Length( arg ) = 1 and arg[1] = infinity then - names:= InfiniteListOfNames( "x" ); - elif Length( arg ) = 2 and arg[1] = infinity then - names:= InfiniteListOfNames( arg[2] ); - elif Length( arg ) = 3 and arg[1] = infinity then - names:= InfiniteListOfNames( arg[2], arg[3] ); - elif Length( arg ) = 1 and IsInt( arg[1] ) and 0 < arg[1] then - names:= List( [ 1 .. arg[1] ], - i -> Concatenation( "x", String(i) ) ); - MakeImmutable( names ); - elif Length( arg ) = 2 and IsInt( arg[1] ) and 0 < arg[1] then - names:= List( [ 1 .. arg[1] ], - i -> Concatenation( arg[2], String(i) ) ); - MakeImmutable( names ); - elif 1 <= Length( arg ) and ForAll( arg, IsString ) then - names:= arg; - elif Length( arg ) = 1 and IsList( arg[1] ) - and not IsEmpty( arg[1]) - and ForAll( arg[1], IsString ) then - names:= arg[1]; - else - Error( "usage: FreeMagmaWithOne(,..),", - "FreeMagmaWithOne()" ); - fi; + local names, # list of generators names + F, # family of free magma element objects + M, # free magma, result + processed; + + processed := FreeAlgebraCreatorArgumentProcessor( "FreeMagmaWithOne", "x", arg ); + names := processed.names; # Handle the trivial case. if IsEmpty( names ) then diff --git a/lib/monofree.gi b/lib/monofree.gi index 05bca577757..be1766e36f6 100644 --- a/lib/monofree.gi +++ b/lib/monofree.gi @@ -176,69 +176,25 @@ InstallMethod( GeneratorsSmallest, ############################################################################# ## -#F FreeMonoid( ) -#F FreeMonoid( , ) -#F FreeMonoid( , , ... ) -#F FreeMonoid( ) -#F FreeMonoid( infinity, , ) +#F FreeMonoid( [, ][, ] ) +#F FreeMonoid( [, ], , ... ) +#F FreeMonoid( [, ] ) +#F FreeMonoid( [, ]infinity[, [, ]] ) ## InstallGlobalFunction( FreeMonoid, function( arg ) - local names, # list of generators names + local names, # list of generator names F, # family of free monoid element objects - zarg, - lesy, # filter for letter or syllable words family - M; # free monoid, result - - lesy:=IsLetterWordsFamily; # default - if IsFilter(arg[1]) then - lesy:=arg[1]; - zarg:=arg{[2..Length(arg)]}; - else - zarg:=arg; - fi; - - # Get and check the argument list, and construct names if necessary. - if Length( zarg ) = 1 and zarg[1] = infinity then - names:= InfiniteListOfNames( "m" ); - elif Length( zarg ) = 2 and zarg[1] = infinity then - names:= InfiniteListOfNames( zarg[2] ); - elif Length( zarg ) = 3 and zarg[1] = infinity then - names:= InfiniteListOfNames( zarg[2], zarg[3] ); - elif Length( zarg ) = 1 and IsInt( zarg[1] ) and 0 <= zarg[1] then - names:= List( [ 1 .. zarg[1] ], - i -> Concatenation( "m", String(i) ) ); - MakeImmutable( names ); - elif Length( zarg ) = 2 and IsInt( zarg[1] ) and 0 <= zarg[1] then - names:= List( [ 1 .. zarg[1] ], - i -> Concatenation( zarg[2], String(i) ) ); - MakeImmutable( names ); - elif Length( zarg ) = 1 and IsList( zarg[1] ) and IsEmpty( zarg[1] ) then - names:= zarg[1]; - elif 1 <= Length( zarg ) and ForAll( zarg, IsString ) then - names:= zarg; - elif Length( zarg ) = 1 and IsList( zarg[1] ) - and ForAll( zarg[1], IsString ) then - names:= zarg[1]; - else - Error("usage: FreeMonoid(,..) or FreeMonoid()"); - fi; + M, # free monoid, result + processed; - # deal with letter words family types - if lesy=IsLetterWordsFamily then - if Length(names)>127 then - lesy:=IsWLetterWordsFamily; - else - lesy:=IsBLetterWordsFamily; - fi; - elif lesy=IsBLetterWordsFamily and Length(names)>127 then - lesy:=IsWLetterWordsFamily; - fi; + processed := FreeAlgebraCreatorArgumentProcessor( "FreeMonoid", "m", arg ); + names := processed.names; # Construct the family of element objects of our monoid. - F:= NewFamily( "FreeMonoidElementsFamily", IsAssocWordWithOne, - CanEasilySortElements, # the free monoid can. - CanEasilySortElements # the free monoid can. - and lesy); + F:= NewFamily( "FreeMonoidElementsFamily", + IsAssocWordWithOne, + CanEasilySortElements, + CanEasilySortElements and processed.lesy ); # Install the data (names, no. of bits available for exponents, types). StoreInfoFreeMagma( F, names, IsAssocWordWithOne ); @@ -246,32 +202,24 @@ InstallGlobalFunction( FreeMonoid, function( arg ) # Make the monoid if IsEmpty( names ) then M:= MonoidByGenerators( [], One(F) ); - SetIsFinite(M, true); - SetIsTrivial(M, true); - SetIsCommutative(M, true); elif IsFinite( names ) then M:= MonoidByGenerators( List( [ 1 .. Length( names ) ], i -> ObjByExtRep( F, 1, 1, [ i, 1 ] ) ) ); - SetIsTrivial( M, false ); - if Length(names) > 1 then - SetIsCommutative(M, false); - fi; else M:= MonoidByGenerators( InfiniteListOfGenerators( F ) ); - SetIsTrivial( M, false ); - SetIsFinite( M, false ); - SetIsCommutative(M, false ); - SetIsFinitelyGeneratedMonoid(M, false); fi; + # store the whole monoid in the family + FamilyObj(M)!.wholeMonoid:= M; + F!.freeMonoid:=M; SetIsFreeMonoid( M, true); SetIsWholeFamily( M, true ); - # store the whole monoid in the family - FamilyObj(M)!.wholeMonoid:= M; - F!.freeMonoid:=M; + SetIsTrivial( M, IsEmpty( names ) ); + SetIsFinite( M, IsEmpty( names ) ); + SetIsFinitelyGeneratedMonoid(M, IsFinite( names ) ); + SetIsCommutative( M, Length( names ) <= 1 ); - # Return the free monoid. return M; end ); diff --git a/lib/monoid.gd b/lib/monoid.gd index 8d01a9613fd..0880890da03 100644 --- a/lib/monoid.gd +++ b/lib/monoid.gd @@ -184,11 +184,10 @@ DeclareSynonymAttr( "TrivialSubmonoid", TrivialSubmagmaWithOne ); ############################################################################# ## -#F FreeMonoid( [,] ) -#F FreeMonoid( [,], ) +#F FreeMonoid( [,][, ] ) #F FreeMonoid( [,], , ... ) #F FreeMonoid( [,] ) -#F FreeMonoid( [,]infinity, , ) +#F FreeMonoid( [,]infinity[, [, ]] ) ## ## <#GAPDoc Label="FreeMonoid"> ## @@ -199,17 +198,18 @@ DeclareSynonymAttr( "TrivialSubmonoid", TrivialSubmagmaWithOne ); ## Label="for various names"/> ## -## ## ## ## Called with a positive integer rank, ## returns ## a free monoid on rank generators. -## If the optional argument name is given then the generators are +## If the optional argument name (a string) is given, +## then the generators are ## printed as name1, name2 etc., ## that is, each name is the concatenation of the string name and an -## integer from 1 to range. +## integer from 1 to rank. ## The default for name is the string "m". ##

## Called in the second form, diff --git a/lib/semigrp.gd b/lib/semigrp.gd index 9cf4c9df753..a27e03714ec 100644 --- a/lib/semigrp.gd +++ b/lib/semigrp.gd @@ -278,7 +278,7 @@ DeclareAttribute("CayleyGraphDualSemigroup",IsSemigroup); ############################################################################# ## #F FreeSemigroup( [, ][, ] ) -#F FreeSemigroup( [, ][, , ...] ) +#F FreeSemigroup( [, ], , ... ) #F FreeSemigroup( [, ] ) #F FreeSemigroup( [, ]infinity[, [, ]] ) ## diff --git a/lib/smgrpfre.gi b/lib/smgrpfre.gi index 67369260d7a..8a4fd99f4e8 100644 --- a/lib/smgrpfre.gi +++ b/lib/smgrpfre.gi @@ -378,130 +378,28 @@ InstallMethod( GeneratorsSmallest, ############################################################################# ## #F FreeSemigroup( [, ][, ] ) -#F FreeSemigroup( [, ][, , ...] ) +#F FreeSemigroup( [, ], , ... ) #F FreeSemigroup( [, ] ) #F FreeSemigroup( [, ]infinity[, [, ]] ) ## InstallGlobalFunction( FreeSemigroup, function( arg ) - local names, # list of generators names + local names, # list of generator names F, # family of free semigroup element objects - zarg, - lesy, # filter for letter or syllable words family S, # free semigroup, result - err, # string; helpful error message - form, # string: assumed argument form of call to FreeSemigroup - rank, - name, - init; - - lesy:=IsLetterWordsFamily; # default: - if not IsEmpty(arg) and IsFilter(arg[1]) then - lesy:=arg[1]; - zarg:=arg{[2..Length(arg)]}; - else - zarg:=arg; - fi; - - # Process and validate the argument list, constructing names if necessary - err := ""; - - if Length( zarg ) = 0 or zarg[1] = 0 - or (Length(zarg) = 1 and IsList( zarg[1] ) and IsEmpty( zarg[1] )) then - Error("free semigroups of rank zero are not supported"); - - # FreeSemigroup( [, ] ) - elif IsPosInt( zarg[1] ) and Length( zarg ) <= 2 then - - # Get default and optional arguments - rank := zarg[1]; - if Length( zarg ) = 1 then - name := "s"; - else - name := zarg[2]; - fi; - - # Error checking - if not IsString( name ) then - form := ", "; - err := " must be a string"; - - # Construct names - else - names:= List( [ 1 .. rank ], i -> Concatenation( name, String(i) ) ); - MakeImmutable( names ); - fi; - - # FreeSemigroup( [, , ...] ), or a list of such arguments - elif ForAll( zarg, IsString ) or Length( zarg ) = 1 and IsList( zarg[1] ) then - if Length( zarg ) = 1 and not IsString( zarg[1] ) then - form := "[ , , ... ]"; - names:= zarg[1]; - else - form := ", , ..."; - names:= zarg; - fi; - if not ForAll( names, s -> IsString(s) and not IsEmpty(s) ) then - err := "the names must be nonempty strings"; - fi; + processed; - # FreeSemigroup( infinity[, [, ]] ) - elif zarg[1] = infinity and Length( zarg ) <= 3 then - - # Get default and optional arguments - name := "s"; - init := []; - if Length( zarg ) = 3 then - form := "infinity, , "; - name := zarg[2]; - init := zarg[3]; - elif Length( zarg ) = 2 then - form := "infinity, "; - name := zarg[2]; - fi; + processed:= FreeAlgebraCreatorArgumentProcessor ("FreeSemigroup", "s", arg ); + names:= processed.names; - # Error checking - if not IsString( name ) then - err := " must be a string"; - fi; - if not ( IsList( init ) and ForAll( init, s -> IsString(s) and not IsEmpty(s) ) ) then - if not IsEmpty(err) then - Append(err, " and "); - fi; - Append(err, " must be a list of nonempty strings"); - fi; - - # Construct names - if IsEmpty(err) then - names:= InfiniteListOfNames( name, init ); - fi; - - else - ErrorNoReturn("""usage: FreeSemigroup( [, ][, ] ) - FreeSemigroup( [, ][, , ...] ) - FreeSemigroup( [, ] ) - FreeSemigroup( [, ]infinity[, [, ]] )"""); - fi; - - if not IsEmpty(err) then - ErrorNoReturn(StringFormatted("FreeSemigroup( {} ): {}", form, err)); - fi; - - # deal with letter words family types - if lesy=IsLetterWordsFamily then - if Length(names)>127 then - lesy:=IsWLetterWordsFamily; - else - lesy:=IsBLetterWordsFamily; - fi; - elif lesy=IsBLetterWordsFamily and Length(names)>127 then - lesy:=IsWLetterWordsFamily; + if IsEmpty( names ) then + ErrorNoReturn( "free semigroups of rank zero are not supported" ); fi; # Construct the family of element objects of our semigroup. - F:= NewFamily( "FreeSemigroupElementsFamily", IsAssocWord, - CanEasilySortElements, # the free group can. - CanEasilySortElements # the free group can. - and lesy); + F:= NewFamily( "FreeSemigroupElementsFamily", + IsAssocWord, + CanEasilySortElements, + CanEasilySortElements and processed.lesy ); # Install the data (names, no. of bits available for exponents, types). StoreInfoFreeMagma( F, names, IsAssocWord ); @@ -516,11 +414,16 @@ InstallGlobalFunction( FreeSemigroup, function( arg ) # store the whole semigroup in the family FamilyObj(S)!.wholeSemigroup:= S; F!.freeSemigroup:=S; - - SetIsFreeSemigroup(S,true); + SetIsFreeSemigroup( S, true ); SetIsWholeFamily( S, true ); + SetIsTrivial( S, false ); - SetIsCommutative( S, Length(names) = 1 ); + # Following is written defensively in case 0-generator free semigroups ever + # become supported in the future. + SetIsFinite( S, IsEmpty( names ) ); + SetIsEmpty( S, IsEmpty( names ) ); + SetIsCommutative( S, Length( names ) <= 1 ); + return S; end ); diff --git a/tst/testinstall/grpfree.tst b/tst/testinstall/grpfree.tst index 549dbdc98f2..995ddc83c16 100644 --- a/tst/testinstall/grpfree.tst +++ b/tst/testinstall/grpfree.tst @@ -69,5 +69,123 @@ gap> H / rho; Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 2nd choice method found for `FactorSemigroup' on 2 arguments +# FreeGroup +gap> FreeGroup(fail); +Error, usage: FreeGroup( [, ][, ] ) + FreeGroup( [, ], , ... ) + FreeGroup( [, ] ) + FreeGroup( [, ]infinity[, [, ]] ) + +# FreeGroup: rank 0 +gap> FreeGroup(); + +gap> FreeGroup([]); + +gap> FreeGroup(""); + +gap> FreeGroup(0); + +gap> FreeGroup(0, "name"); + + +# FreeGroup(infinity[, name[, init]]) +gap> FreeGroup(infinity); + +gap> FreeGroup(infinity, fail); +Error, FreeGroup( infinity, ): must be a string +gap> FreeGroup(infinity, []); + +gap> FreeGroup(infinity, ""); + +gap> FreeGroup(infinity, "nicename"); + +gap> FreeGroup(infinity, fail, fail); +Error, FreeGroup( infinity, , ): must be a string and must be a list of nonempty strings +gap> FreeGroup(infinity, "nicename", fail); +Error, FreeGroup( infinity, , ): must be a list of nonempt\ +y strings +gap> FreeGroup(infinity, "gen", []); + +gap> FreeGroup(infinity, "gen", [""]); +Error, FreeGroup( infinity, , ): must be a list of nonempt\ +y strings +gap> FreeGroup(infinity, "gen", ["starter"]); + +gap> FreeGroup(infinity, "gen", ["starter", ""]); +Error, FreeGroup( infinity, , ): must be a list of nonempt\ +y strings +gap> F := FreeGroup(infinity, "gen", ["starter", "second", "third"]); + +gap> GeneratorsOfGroup(F){[1 .. 4]}; +[ starter, second, third, gen4 ] +gap> FreeGroup(infinity, "gen", ["starter"], fail); +Error, usage: FreeGroup( [, ][, ] ) + FreeGroup( [, ], , ... ) + FreeGroup( [, ] ) + FreeGroup( [, ]infinity[, [, ]] ) + +# FreeGroup(rank[, name]) +gap> F := FreeGroup(1); + +gap> HasIsCommutative(F) and IsCommutative(F); +true +gap> F := FreeGroup(2); + +gap> HasIsCommutative(F) and not IsCommutative(F); +true +gap> F := FreeGroup(10); + +gap> F := FreeGroup(3, fail); +Error, FreeGroup( , ): must be a string +gap> F := FreeGroup(4, ""); + +gap> F := FreeGroup(5, []); + +gap> F := FreeGroup(4, "cheese"); + +gap> FreeGroup(3, "car", fail); +Error, usage: FreeGroup( [, ][, ] ) + FreeGroup( [, ], , ... ) + FreeGroup( [, ] ) + FreeGroup( [, ]infinity[, [, ]] ) + +# FreeGroup( , , ... ) +gap> FreeGroup("", "second"); +Error, FreeGroup( , , ... ): the names must be nonempty strings +gap> FreeGroup("first", ""); +Error, FreeGroup( , , ... ): the names must be nonempty strings +gap> FreeGroup("first", []); +Error, FreeGroup( , , ... ): the names must be nonempty strings +gap> FreeGroup([], []); +Error, FreeGroup( , , ... ): the names must be nonempty strings +gap> FreeGroup("bacon", "eggs", "beans"); + +gap> FreeGroup("shed"); + + +# FreeGroup( [ , , ... ] ) +gap> FreeGroup(["", "second"]); +Error, FreeGroup( [ , , ... ] ): the names must be nonempty stri\ +ngs +gap> FreeGroup(["first", ""]); +Error, FreeGroup( [ , , ... ] ): the names must be nonempty stri\ +ngs +gap> FreeGroup(["first", []]); +Error, FreeGroup( [ , , ... ] ): the names must be nonempty stri\ +ngs +gap> FreeGroup([[], []]); +Error, FreeGroup( [ , , ... ] ): the names must be nonempty stri\ +ngs +gap> FreeGroup(["bacon", "eggs", "beans"]); + +gap> FreeGroup(["grid"]); + +gap> FreeGroup(["grid"], fail); +Error, usage: FreeGroup( [, ][, ] ) + FreeGroup( [, ], , ... ) + FreeGroup( [, ] ) + FreeGroup( [, ]infinity[, [, ]] ) + # gap> STOP_TEST( "grpfree.tst", 1); diff --git a/tst/testinstall/mgmfree.tst b/tst/testinstall/mgmfree.tst new file mode 100644 index 00000000000..43f969302a3 --- /dev/null +++ b/tst/testinstall/mgmfree.tst @@ -0,0 +1,246 @@ +#@local M +gap> START_TEST("mgmfree.tst"); + +# FreeMagma +gap> FreeMagma(fail); +Error, usage: FreeMagma( [, ][, ] ) + FreeMagma( [, ], , ... ) + FreeMagma( [, ] ) + FreeMagma( [, ]infinity[, [, ]] ) + +# FreeMagma: rank 0 +gap> FreeMagma(); +Error, free magmas of rank zero are not supported +gap> FreeMagma([]); +Error, free magmas of rank zero are not supported +gap> FreeMagma(""); +Error, free magmas of rank zero are not supported +gap> FreeMagma(0); +Error, free magmas of rank zero are not supported +gap> FreeMagma(0, "name"); +Error, free magmas of rank zero are not supported + +# FreeMagma(infinity[, name[, init]]) +gap> FreeMagma(infinity); + +gap> FreeMagma(infinity, fail); +Error, FreeMagma( infinity, ): must be a string +gap> FreeMagma(infinity, []); + +gap> FreeMagma(infinity, ""); + +gap> FreeMagma(infinity, "nicename"); + +gap> FreeMagma(infinity, fail, fail); +Error, FreeMagma( infinity, , ): must be a string and must be a list of nonempty strings +gap> FreeMagma(infinity, "nicename", fail); +Error, FreeMagma( infinity, , ): must be a list of nonempt\ +y strings +gap> FreeMagma(infinity, "gen", []); + +gap> FreeMagma(infinity, "gen", [""]); +Error, FreeMagma( infinity, , ): must be a list of nonempt\ +y strings +gap> FreeMagma(infinity, "gen", ["starter"]); + +gap> FreeMagma(infinity, "gen", ["starter", ""]); +Error, FreeMagma( infinity, , ): must be a list of nonempt\ +y strings +gap> M := FreeMagma(infinity, "gen", ["starter", "second", "third"]); + +gap> GeneratorsOfMagma(M){[1 .. 4]}; +[ starter, second, third, gen4 ] +gap> FreeMagma(infinity, "gen", ["starter"], fail); +Error, usage: FreeMagma( [, ][, ] ) + FreeMagma( [, ], , ... ) + FreeMagma( [, ] ) + FreeMagma( [, ]infinity[, [, ]] ) + +# FreeMagma(rank[, name]) +gap> M := FreeMagma(1); + +gap> HasIsTrivial(M) and not IsTrivial(M); +true +gap> M := FreeMagma(2); + +gap> HasIsTrivial(M) and not IsTrivial(M); +true +gap> M := FreeMagma(10); + +gap> M := FreeMagma(3, fail); +Error, FreeMagma( , ): must be a string +gap> M := FreeMagma(4, ""); + +gap> M := FreeMagma(5, []); + +gap> M := FreeMagma(4, "cheese"); + +gap> FreeMagma(3, "car", fail); +Error, usage: FreeMagma( [, ][, ] ) + FreeMagma( [, ], , ... ) + FreeMagma( [, ] ) + FreeMagma( [, ]infinity[, [, ]] ) + +# FreeMagma( [, , ...] ) +gap> FreeMagma("", "second"); +Error, FreeMagma( , , ... ): the names must be nonempty strings +gap> FreeMagma("first", ""); +Error, FreeMagma( , , ... ): the names must be nonempty strings +gap> FreeMagma("first", []); +Error, FreeMagma( , , ... ): the names must be nonempty strings +gap> FreeMagma([], []); +Error, FreeMagma( , , ... ): the names must be nonempty strings +gap> FreeMagma("bacon", "eggs", "beans"); + +gap> FreeMagma("shed"); + + +# FreeMagma( [ [, , ...] ] ) +gap> FreeMagma(["", "second"]); +Error, FreeMagma( [ , , ... ] ): the names must be nonempty stri\ +ngs +gap> FreeMagma(["first", ""]); +Error, FreeMagma( [ , , ... ] ): the names must be nonempty stri\ +ngs +gap> FreeMagma(["first", []]); +Error, FreeMagma( [ , , ... ] ): the names must be nonempty stri\ +ngs +gap> FreeMagma([[], []]); +Error, FreeMagma( [ , , ... ] ): the names must be nonempty stri\ +ngs +gap> FreeMagma(["bacon", "eggs", "beans"]); + +gap> FreeMagma(["grid"]); + +gap> FreeMagma(["grid"], fail); +Error, usage: FreeMagma( [, ][, ] ) + FreeMagma( [, ], , ... ) + FreeMagma( [, ] ) + FreeMagma( [, ]infinity[, [, ]] ) + +# FreeMagmaWithOne +gap> FreeMagmaWithOne(fail); +Error, usage: FreeMagmaWithOne( [, ][, ] ) + FreeMagmaWithOne( [, ], , ... ) + FreeMagmaWithOne( [, ] ) + FreeMagmaWithOne( [, ]infinity[, [, ]] ) + +# FreeMagmaWithOne: rank 0 +gap> FreeMagmaWithOne(); + +gap> FreeMagmaWithOne([]); + +gap> FreeMagmaWithOne(""); + +gap> FreeMagmaWithOne(0); + +gap> FreeMagmaWithOne(0, "name"); + + +# FreeMagmaWithOne(infinity[, name[, init]]) +gap> FreeMagmaWithOne(infinity); + +gap> FreeMagmaWithOne(infinity, fail); +Error, FreeMagmaWithOne( infinity, ): must be a string +gap> FreeMagmaWithOne(infinity, []); + +gap> FreeMagmaWithOne(infinity, ""); + +gap> FreeMagmaWithOne(infinity, "nicename"); + +gap> FreeMagmaWithOne(infinity, fail, fail); +Error, FreeMagmaWithOne( infinity, , ): must be a string a\ +nd must be a list of nonempty strings +gap> FreeMagmaWithOne(infinity, "nicename", fail); +Error, FreeMagmaWithOne( infinity, , ): must be a list of \ +nonempty strings +gap> FreeMagmaWithOne(infinity, "gen", []); + +gap> FreeMagmaWithOne(infinity, "gen", [""]); +Error, FreeMagmaWithOne( infinity, , ): must be a list of \ +nonempty strings +gap> FreeMagmaWithOne(infinity, "gen", ["starter"]); + +gap> FreeMagmaWithOne(infinity, "gen", ["starter", ""]); +Error, FreeMagmaWithOne( infinity, , ): must be a list of \ +nonempty strings +gap> M := FreeMagmaWithOne(infinity, "gen", ["starter", "second", "third"]); + +gap> GeneratorsOfMagmaWithOne(M){[1 .. 4]}; +[ starter, second, third, gen4 ] +gap> FreeMagmaWithOne(infinity, "gen", ["starter"], fail); +Error, usage: FreeMagmaWithOne( [, ][, ] ) + FreeMagmaWithOne( [, ], , ... ) + FreeMagmaWithOne( [, ] ) + FreeMagmaWithOne( [, ]infinity[, [, ]] ) + +# FreeMagmaWithOne(rank[, name]) +gap> M := FreeMagmaWithOne(1); + +gap> HasIsTrivial(M) and not IsTrivial(M); +true +gap> M := FreeMagmaWithOne(2); + +gap> HasIsTrivial(M) and not IsTrivial(M); +true +gap> M := FreeMagmaWithOne(10); + +gap> M := FreeMagmaWithOne(3, fail); +Error, FreeMagmaWithOne( , ): must be a string +gap> M := FreeMagmaWithOne(4, ""); + +gap> M := FreeMagmaWithOne(5, []); + +gap> M := FreeMagmaWithOne(4, "cheese"); + +gap> FreeMagmaWithOne(3, "car", fail); +Error, usage: FreeMagmaWithOne( [, ][, ] ) + FreeMagmaWithOne( [, ], , ... ) + FreeMagmaWithOne( [, ] ) + FreeMagmaWithOne( [, ]infinity[, [, ]] ) + +# FreeMagmaWithOne( [, , ...] ) +gap> FreeMagmaWithOne("", "second"); +Error, FreeMagmaWithOne( , , ... ): the names must be nonempty s\ +trings +gap> FreeMagmaWithOne("first", ""); +Error, FreeMagmaWithOne( , , ... ): the names must be nonempty s\ +trings +gap> FreeMagmaWithOne("first", []); +Error, FreeMagmaWithOne( , , ... ): the names must be nonempty s\ +trings +gap> FreeMagmaWithOne([], []); +Error, FreeMagmaWithOne( , , ... ): the names must be nonempty s\ +trings +gap> FreeMagmaWithOne("bacon", "eggs", "beans"); + +gap> FreeMagmaWithOne("shed"); + + +# FreeMagmaWithOne( [ [, , ...] ] ) +gap> FreeMagmaWithOne(["", "second"]); +Error, FreeMagmaWithOne( [ , , ... ] ): the names must be nonemp\ +ty strings +gap> FreeMagmaWithOne(["first", ""]); +Error, FreeMagmaWithOne( [ , , ... ] ): the names must be nonemp\ +ty strings +gap> FreeMagmaWithOne(["first", []]); +Error, FreeMagmaWithOne( [ , , ... ] ): the names must be nonemp\ +ty strings +gap> FreeMagmaWithOne([[], []]); +Error, FreeMagmaWithOne( [ , , ... ] ): the names must be nonemp\ +ty strings +gap> FreeMagmaWithOne(["bacon", "eggs", "beans"]); + +gap> FreeMagmaWithOne(["grid"]); + +gap> FreeMagmaWithOne(["grid"], fail); +Error, usage: FreeMagmaWithOne( [, ][, ] ) + FreeMagmaWithOne( [, ], , ... ) + FreeMagmaWithOne( [, ] ) + FreeMagmaWithOne( [, ]infinity[, [, ]] ) + +# +gap> STOP_TEST( "mgmfree.tst", 1); diff --git a/tst/testinstall/monofree.tst b/tst/testinstall/monofree.tst index aed6642167e..65578331f23 100644 --- a/tst/testinstall/monofree.tst +++ b/tst/testinstall/monofree.tst @@ -41,5 +41,123 @@ true gap> ForAll([0,1,2,3,infinity], n -> (n < 2) = IsCommutative(FreeMonoid(n))); true +# FreeMonoid +gap> FreeMonoid(fail); +Error, usage: FreeMonoid( [, ][, ] ) + FreeMonoid( [, ], , ... ) + FreeMonoid( [, ] ) + FreeMonoid( [, ]infinity[, [, ]] ) + +# FreeMonoid: rank 0 +gap> FreeMonoid(); + +gap> FreeMonoid([]); + +gap> FreeMonoid(""); + +gap> FreeMonoid(0); + +gap> FreeMonoid(0, "name"); + + +# FreeMonoid(infinity[, name[, init]]) +gap> FreeMonoid(infinity); + +gap> FreeMonoid(infinity, fail); +Error, FreeMonoid( infinity, ): must be a string +gap> FreeMonoid(infinity, []); + +gap> FreeMonoid(infinity, ""); + +gap> FreeMonoid(infinity, "nicename"); + +gap> FreeMonoid(infinity, fail, fail); +Error, FreeMonoid( infinity, , ): must be a string and must be a list of nonempty strings +gap> FreeMonoid(infinity, "nicename", fail); +Error, FreeMonoid( infinity, , ): must be a list of nonemp\ +ty strings +gap> FreeMonoid(infinity, "gen", []); + +gap> FreeMonoid(infinity, "gen", [""]); +Error, FreeMonoid( infinity, , ): must be a list of nonemp\ +ty strings +gap> FreeMonoid(infinity, "gen", ["starter"]); + +gap> FreeMonoid(infinity, "gen", ["starter", ""]); +Error, FreeMonoid( infinity, , ): must be a list of nonemp\ +ty strings +gap> F := FreeMonoid(infinity, "gen", ["starter", "second", "third"]); + +gap> GeneratorsOfMonoid(F){[1 .. 4]}; +[ starter, second, third, gen4 ] +gap> FreeMonoid(infinity, "gen", ["starter"], fail); +Error, usage: FreeMonoid( [, ][, ] ) + FreeMonoid( [, ], , ... ) + FreeMonoid( [, ] ) + FreeMonoid( [, ]infinity[, [, ]] ) + +# FreeMonoid(rank[, name]) +gap> F := FreeMonoid(1); + +gap> HasIsCommutative(F) and IsCommutative(F); +true +gap> F := FreeMonoid(2); + +gap> HasIsCommutative(F) and not IsCommutative(F); +true +gap> F := FreeMonoid(10); + +gap> F := FreeMonoid(3, fail); +Error, FreeMonoid( , ): must be a string +gap> F := FreeMonoid(4, ""); + +gap> F := FreeMonoid(5, []); + +gap> F := FreeMonoid(4, "cheese"); + +gap> FreeMonoid(3, "car", fail); +Error, usage: FreeMonoid( [, ][, ] ) + FreeMonoid( [, ], , ... ) + FreeMonoid( [, ] ) + FreeMonoid( [, ]infinity[, [, ]] ) + +# FreeMonoid( , , ... ) +gap> FreeMonoid("", "second"); +Error, FreeMonoid( , , ... ): the names must be nonempty strings +gap> FreeMonoid("first", ""); +Error, FreeMonoid( , , ... ): the names must be nonempty strings +gap> FreeMonoid("first", []); +Error, FreeMonoid( , , ... ): the names must be nonempty strings +gap> FreeMonoid([], []); +Error, FreeMonoid( , , ... ): the names must be nonempty strings +gap> FreeMonoid("bacon", "eggs", "beans"); + +gap> FreeMonoid("shed"); + + +# FreeMonoid( [ , , ... ] ) +gap> FreeMonoid(["", "second"]); +Error, FreeMonoid( [ , , ... ] ): the names must be nonempty str\ +ings +gap> FreeMonoid(["first", ""]); +Error, FreeMonoid( [ , , ... ] ): the names must be nonempty str\ +ings +gap> FreeMonoid(["first", []]); +Error, FreeMonoid( [ , , ... ] ): the names must be nonempty str\ +ings +gap> FreeMonoid([[], []]); +Error, FreeMonoid( [ , , ... ] ): the names must be nonempty str\ +ings +gap> FreeMonoid(["bacon", "eggs", "beans"]); + +gap> FreeMonoid(["grid"]); + +gap> FreeMonoid(["grid"], fail); +Error, usage: FreeMonoid( [, ][, ] ) + FreeMonoid( [, ], , ... ) + FreeMonoid( [, ] ) + FreeMonoid( [, ]infinity[, [, ]] ) + # gap> STOP_TEST( "grpfree.tst", 1); diff --git a/tst/testinstall/smgrpfre.tst b/tst/testinstall/smgrpfre.tst index 668e2eaf97e..2c0c83d4f41 100644 --- a/tst/testinstall/smgrpfre.tst +++ b/tst/testinstall/smgrpfre.tst @@ -4,7 +4,7 @@ gap> START_TEST("smgrpfre.tst"); # FreeSemigroup gap> FreeSemigroup(fail); Error, usage: FreeSemigroup( [, ][, ] ) - FreeSemigroup( [, ][, , ...] ) + FreeSemigroup( [, ], , ... ) FreeSemigroup( [, ] ) FreeSemigroup( [, ]infinity[, [, ]] ) @@ -53,7 +53,7 @@ gap> GeneratorsOfSemigroup(F){[1 .. 4]}; [ starter, second, third, gen4 ] gap> FreeSemigroup(infinity, "gen", ["starter"], fail); Error, usage: FreeSemigroup( [, ][, ] ) - FreeSemigroup( [, ][, , ...] ) + FreeSemigroup( [, ], , ... ) FreeSemigroup( [, ] ) FreeSemigroup( [, ]infinity[, [, ]] ) @@ -78,11 +78,11 @@ gap> F := FreeSemigroup(4, "cheese"); gap> FreeSemigroup(3, "car", fail); Error, usage: FreeSemigroup( [, ][, ] ) - FreeSemigroup( [, ][, , ...] ) + FreeSemigroup( [, ], , ... ) FreeSemigroup( [, ] ) FreeSemigroup( [, ]infinity[, [, ]] ) -# FreeSemigroup( [, , ...] ) +# FreeSemigroup( , , ... ) gap> FreeSemigroup("", "second"); Error, FreeSemigroup( , , ... ): the names must be nonempty stri\ ngs @@ -100,7 +100,7 @@ gap> FreeSemigroup("bacon", "eggs", "beans"); gap> FreeSemigroup("shed"); -# FreeSemigroup( [ [, , ...] ] ) +# FreeSemigroup( [ , , ... ] ) gap> FreeSemigroup(["", "second"]); Error, FreeSemigroup( [ , , ... ] ): the names must be nonempty \ strings @@ -119,7 +119,7 @@ gap> FreeSemigroup(["grid"]); gap> FreeSemigroup(["grid"], fail); Error, usage: FreeSemigroup( [, ][, ] ) - FreeSemigroup( [, ][, , ...] ) + FreeSemigroup( [, ], , ... ) FreeSemigroup( [, ] ) FreeSemigroup( [, ]infinity[, [, ]] )