diff --git a/lib/coll.gd b/lib/coll.gd index e947887852..6c68678f35 100644 --- a/lib/coll.gd +++ b/lib/coll.gd @@ -1371,6 +1371,10 @@ InstallFactorMaintenance( IsTrivial, ## DeclareProperty( "IsNonTrivial", IsCollection ); +# true methods to avoid immediate methods +InstallTrueMethod(HasIsTrivial,IsNonTrivial); +InstallTrueMethod(HasIsNonTrivial,IsTrivial); + ############################################################################# ## diff --git a/lib/coll.gi b/lib/coll.gi index 46fb6c8656..f46882f9a0 100644 --- a/lib/coll.gi +++ b/lib/coll.gi @@ -94,7 +94,7 @@ InstallMethod( PrintObj, ## InstallImmediateMethod( IsEmpty, IsCollection and HasSize, 0, - C -> Size( C ) = 0 ); + C->Size( C ) = 0); InstallMethod( IsEmpty, "for a collection", @@ -120,8 +120,8 @@ InstallMethod( IsTrivial, [ IsCollection ], C -> Size( C ) = 1 ); -InstallImmediateMethod( IsTrivial, - IsCollection and HasIsNonTrivial, 0, +InstallMethod( IsTrivial, + [IsCollection and HasIsNonTrivial], 0, C -> not IsNonTrivial( C ) ); @@ -129,8 +129,8 @@ InstallImmediateMethod( IsTrivial, ## #M IsNonTrivial( ) . . . . . . . . . test if a collection is nontrivial ## -InstallImmediateMethod( IsNonTrivial, - IsCollection and HasIsTrivial, 0, +InstallMethod( IsNonTrivial, + [IsCollection and HasIsTrivial], 0, C -> not IsTrivial( C ) ); InstallMethod( IsNonTrivial, @@ -169,8 +169,12 @@ InstallMethod( IsWholeFamily, ## #M Size( ) . . . . . . . . . . . . . . . . . . . . size of a collection ## -InstallImmediateMethod( Size, - IsCollection and HasIsFinite and IsAttributeStoringRep, 0, +# This used to be an immediate method. It was replaced by an ordinary +# method, as the immediate method would get called for every group that +# knows it is finite but does not know its size -- e.g. permutation, pc. +# The benefit of this is minimal beyond showing off a feature. +InstallMethod( Size,true, [IsCollection and HasIsFinite], + 100, # rank above object-specific methods function ( C ) if IsFinite( C ) then TryNextMethod(); @@ -3049,6 +3053,36 @@ end); InstallMethod( CanComputeIsSubset,"default: no, unless identical", [IsObject,IsObject],IsIdenticalObj); +# This setter method is installed to implement filter settings in response +# to an objects size as part of setting the size. This used to be handled +# instead by immediate methods, but in a situation as here it would trigger +# multiple immediate methods, several of which could apply and each changing +# the type of the object. Doing so can be costly and thus should be +# avoided. +InstallOtherMethod(SetSize,true,[IsObject and IsAttributeStoringRep,IsObject], + 100, # override system setter +function(obj,sz) +local filt; + if HasSize(obj) and Size(obj)<>sz then + if AssertionLevel()>2 then + # Make this an ordinary error (not ErrorNoReturn as suggested) to + # preserve all debugging options -- even use `return` to investigate + # what would have happened before this methods was introduced. + Error("size of ",obj," already set to ",Size(obj), + ", cannot be changed to ",sz); + fi; + return; + fi; + if sz=0 then filt:=IsEmpty and IsNonTrivial; # IsNonTrivial hold + elif sz=1 then filt:=IsTrivial; + elif sz=infinity then filt:=IsNonTrivial and HasIsFinite; + else filt:=IsNonTrivial and IsFinite; + fi; + filt:=filt and HasSize; + obj!.Size:=sz; + SetFilterObj(obj,filt); +end); + ############################################################################# ## #E diff --git a/lib/csetgrp.gi b/lib/csetgrp.gi index b00f607fcc..44c5c84478 100644 --- a/lib/csetgrp.gi +++ b/lib/csetgrp.gi @@ -411,18 +411,17 @@ end); InstallOtherMethod(DoubleCoset,"with size",true, [IsGroup,IsObject,IsGroup,IsPosInt],0, function(U,g,V,sz) -local d,fam; +local d,fam,typ; fam:=FamilyObj(U); - if not IsBound(fam!.doubleCosetsDefaultSizeType) then - fam!.doubleCosetsDefaultSizeType:=NewType(fam,IsDoubleCosetDefaultRep - and HasSize and HasIsFinite and IsFinite + typ:=NewType(fam,IsDoubleCosetDefaultRep + and HasIsFinite and IsFinite and HasLeftActingGroup and HasRightActingGroup and HasRepresentative); - fi; d:=rec(); - ObjectifyWithAttributes(d,fam!.doubleCosetsDefaultSizeType, - LeftActingGroup,U,RightActingGroup,V,Representative,g, - Size,sz); + ObjectifyWithAttributes(d,typ, + LeftActingGroup,U,RightActingGroup,V,Representative,g); + SetSize(d,sz); # Size has private setter which will cause problems with + # HasSize triggering an immediate method. return d; end); @@ -574,21 +573,25 @@ end); InstallMethod(RightCoset,"use subgroup size",IsCollsElms, [IsGroup and HasSize,IsObject],0, function(U,g) -local d,fam; +local d,fam,typ; # noch tests... fam:=FamilyObj(U); - if not IsBound(fam!.rightCosetsDefaultSizeType) then - fam!.rightCosetsDefaultSizeType:=NewType(fam,IsRightCosetDefaultRep and - HasActingDomain and HasFunctionAction and HasRepresentative and - HasSize and HasCanonicalRepresentativeDeterminatorOfExternalSet); - fi; + typ:=NewType(fam,IsRightCosetDefaultRep and + HasActingDomain and HasFunctionAction and HasRepresentative + and HasCanonicalRepresentativeDeterminatorOfExternalSet); d:=rec(); - ObjectifyWithAttributes(d,fam!.rightCosetsDefaultSizeType, + ObjectifyWithAttributes(d,typ, ActingDomain,U,FunctionAction,OnLeftInverse,Representative,g, - Size,Size(U),CanonicalRepresentativeDeterminatorOfExternalSet, + CanonicalRepresentativeDeterminatorOfExternalSet, RightCosetCanonicalRepresentativeDeterminator); + # We cannot set the size in the previous ObjectifyWithAttributes as there is + # a custom setter method (the one added in this commit). In such a case + # ObjectifyWith Attributes just does `Objectify` and calls all setters + # separately which is what we want to avoid here. + SetSize(d,Size(U)); + return d; end); diff --git a/lib/ctbl.gd b/lib/ctbl.gd index dc26480cf4..0b114f57f1 100644 --- a/lib/ctbl.gd +++ b/lib/ctbl.gd @@ -3584,6 +3584,8 @@ DeclareGlobalVariable( "CharacterTableDisplayDefaults" ); ## tbl:=rec(); ## tbl.Irr:= ## [ [ 1, 1 ], [ 1, -1 ] ]; +## tbl.IsFinite:= +## true; ## tbl.NrConjugacyClasses:= ## 2; ## tbl.Size:= diff --git a/lib/grp.gd b/lib/grp.gd index d54a47c0fb..97cd67a045 100644 --- a/lib/grp.gd +++ b/lib/grp.gd @@ -592,6 +592,7 @@ DeclareProperty( "IsPerfectGroup", IsGroup ); InstallFactorMaintenance( IsPerfectGroup, IsGroup and IsPerfectGroup, IsObject, IsGroup ); +InstallTrueMethod( IsPerfectGroup, IsGroup and IsTrivial ); ############################################################################# ## @@ -783,6 +784,8 @@ InstallFactorMaintenance( IsSolvableGroup, InstallTrueMethod( IsSolvableGroup, IsMonomialGroup ); InstallTrueMethod( IsSolvableGroup, IsSupersolvableGroup ); +InstallTrueMethod( HasIsPerfectGroup, IsGroup and IsSolvableGroup and IsNonTrivial ); + ############################################################################# ## @@ -3566,6 +3569,11 @@ DeclareOperation( "GroupWithGenerators", [ IsCollection ] ); DeclareOperation( "GroupWithGenerators", [ IsCollection, IsMultiplicativeElementWithInverse ] ); +#F MakeGroupyType( , , , ) +# type creator function to incorporate basic deductions so immediate methods +# are not needed +DeclareGlobalFunction("MakeGroupyType"); + ############################################################################# ## diff --git a/lib/grp.gi b/lib/grp.gi index 9c7781c23b..fe62b0b495 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -30,7 +30,9 @@ InstallImmediateMethod( IsFinitelyGeneratedGroup, ## #M IsCyclic( ) . . . . . . . . . . . . . . . . test if a group is cyclic ## -InstallImmediateMethod( IsCyclic, IsGroup and HasGeneratorsOfGroup, 0, +# This used to be an immediate method. It was replaced by an ordinary +# method since the flag is typically set when creating the group. +InstallMethod( IsCyclic, true, [IsGroup and HasGeneratorsOfGroup], 0, function( G ) if Length( GeneratorsOfGroup( G ) ) = 1 then return true; @@ -43,10 +45,14 @@ InstallMethod( IsCyclic, "generic method for groups", [ IsGroup ], function ( G ) + local a; # if has a generator list of length 1 then is cyclic if HasGeneratorsOfGroup( G ) and Length( GeneratorsOfGroup(G) ) = 1 then - SetMinimalGeneratingSet(G,GeneratorsOfGroup(G)); + a:=GeneratorsOfGroup(G)[1]; + if CanEasilyCompareElements(a) and not IsOne(a) then + SetMinimalGeneratingSet(G,GeneratorsOfGroup(G)); + fi; return true; # if is not commutative it is certainly not cyclic @@ -433,11 +439,6 @@ InstallMethod( IsNilpotentGroup, ## #M IsPerfectGroup( ) . . . . . . . . . . . . test if a group is perfect ## -InstallImmediateMethod( IsPerfectGroup, - IsSolvableGroup and HasIsTrivial, - 0, - IsTrivial ); - InstallImmediateMethod( IsPerfectGroup, IsGroup and HasIsAbelian and IsSimpleGroup, 0, @@ -4283,6 +4284,39 @@ local s,b; return s; end ); +#F MakeGroupyType( , , , , ) +# type creator function to incorporate basic deductions so immediate methods +# are not needed. Parameters are family, filter to start with, generator +# list, is it indeed a group (or only magma)? +InstallGlobalFunction(MakeGroupyType, +function(fam,filt,gens,id,isgroup) + + if IsFinite(gens) then + if isgroup then + filt:=filt and IsFinitelyGeneratedGroup; + fi; + + if Length(gens)>0 and CanEasilyCompareElements(gens) then + if id=false then + id:=One(gens[1]); + fi; + if id<>fail then # cannot do identity in magma + if ForAny(gens,x->x<>id) then + filt:=filt and HasIsTrivial and IsNonTrivial; + if isgroup and Length(gens)<=1 then # cyclic not for magmas + filt:=filt and IsCyclic; + fi; + else + filt:=filt and IsTrivial and HasIsNonTrivial; + fi; + fi; + elif isgroup and Length(gens)<=1 then # cyclic not for magmas + filt:=filt and IsCyclic; + fi; + fi; + return NewType(fam,filt); +end); + ############################################################################# ## #M GroupWithGenerators( ) . . . . . . . . group with given generators @@ -4291,86 +4325,57 @@ end ); InstallMethod( GroupWithGenerators, "generic method for collection", [ IsCollection ], - function( gens ) - local G,fam,typ; - - fam:=FamilyObj(gens); - if IsFinite(gens) then - if not IsBound(fam!.defaultFinitelyGeneratedGroupType) then - fam!.defaultFinitelyGeneratedGroupType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and IsFinitelyGeneratedGroup); - fi; - typ:=fam!.defaultFinitelyGeneratedGroupType; - else - if not IsBound(fam!.defaultGroupType) then - fam!.defaultGroupType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses); - fi; - typ:=fam!.defaultGroupType; - fi; +function( gens ) +local G,typ; - G:=rec(); - ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens)); + typ:=MakeGroupyType(FamilyObj(gens), + IsGroup and IsAttributeStoringRep + and HasIsEmpty and HasGeneratorsOfMagmaWithInverses, + gens,false,true); - return G; - end ); + G:=rec(); + ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens)); + + return G; +end ); InstallMethod( GroupWithGenerators, "generic method for collection and identity element", IsCollsElms, [ IsCollection, IsMultiplicativeElementWithInverse ], - function( gens, id ) - local G,fam,typ; - - fam:=FamilyObj(gens); - if IsFinite(gens) then - if not IsBound(fam!.defaultFinitelyGeneratedGroupWithOneType) then - fam!.defaultFinitelyGeneratedGroupWithOneType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and IsFinitelyGeneratedGroup and HasOne); - fi; - typ:=fam!.defaultFinitelyGeneratedGroupWithOneType; - else - if not IsBound(fam!.defaultGroupWithOneType) then - fam!.defaultGroupWithOneType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses and HasOne); - fi; - typ:=fam!.defaultGroupWithOneType; - fi; +function( gens, id ) +local G,typ; - G:=rec(); - ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), - One,id); + typ:=MakeGroupyType(FamilyObj(gens), + IsGroup and IsAttributeStoringRep + and HasIsEmpty and HasGeneratorsOfMagmaWithInverses and HasOne, + gens,id,true); - return G; + G:=rec(); + ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), + One,id); + + return G; end ); -InstallMethod( GroupWithGenerators, - "method for empty list and element", - [ IsList and IsEmpty, IsMultiplicativeElementWithInverse ], - function( empty, id ) - local G,fam,typ; +InstallMethod( GroupWithGenerators,"method for empty list and element", + [ IsList and IsEmpty, IsMultiplicativeElementWithInverse ], + function( empty, id ) +local G,fam,typ; - fam:= CollectionsFamily( FamilyObj( id ) ); - if not IsBound( fam!.defaultFinitelyGeneratedGroupWithOneType ) then - fam!.defaultFinitelyGeneratedGroupWithOneType:= - NewType( fam, IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and IsFinitelyGeneratedGroup and HasOne ); - fi; - typ:= fam!.defaultFinitelyGeneratedGroupWithOneType; + fam:= CollectionsFamily( FamilyObj( id ) ); - G:= rec(); - ObjectifyWithAttributes( G, typ, - GeneratorsOfMagmaWithInverses, empty, - One, id ); + typ:=IsGroup and IsAttributeStoringRep + and HasGeneratorsOfMagmaWithInverses and HasOne and IsTrivial and + HasIsEmpty and HasIsNonTrivial; + typ:=NewType(fam,typ); - return G; - end ); + G:= rec(); + ObjectifyWithAttributes( G, typ, + GeneratorsOfMagmaWithInverses, empty, + One, id ); + + return G; +end ); ############################################################################# diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 0cd53e6ec8..9ee39263d2 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -955,6 +955,11 @@ local iso,hom,u; if HasIsAbelian(G) and IsAbelian(G) then return TrivialSubgroup(G); elif Size(Image(hom))=infinity then + # test a special case -- one generator + if Length(GeneratorsOfGroup(G))=1 then + SetIsAbelian(G,true); + return TrivialSubgroup(G); + fi; Error("Derived subgroup has infinite index, cannot represent"); elif Size(Range(hom))=1 then return G; # this is needed because the trivial quotient is represented @@ -1539,7 +1544,7 @@ end ); #M FactorFreeGroupByRelators(,) . factor of free group by relators ## BindGlobal( "FactorFreeGroupByRelators", function( F, rels ) - local G, fam, gens; + local G, fam, gens,typ; # Create a new family. fam := NewFamily( "FamilyElementsFpGroup", IsElementOfFpGroup ); @@ -1549,12 +1554,14 @@ BindGlobal( "FactorFreeGroupByRelators", function( F, rels ) fam!.freeGroup := F; fam!.relators := Immutable( rels ); + typ:=IsSubgroupFpGroup and IsWholeFamily and IsAttributeStoringRep; + if IsFinitelyGeneratedGroup(F) then + typ:=typ and IsFinitelyGeneratedGroup; + fi; # Create the group. G := Objectify( - NewType( CollectionsFamily( fam ), - IsSubgroupFpGroup and IsWholeFamily and IsAttributeStoringRep ), - rec() ); + NewType( CollectionsFamily( fam ), typ ), rec() ); # Mark to be the 'whole group' of its later subgroups. FamilyObj( G )!.wholeGroup := G; diff --git a/lib/grpmat.gi b/lib/grpmat.gi index cea6b7f092..9caaeecb7d 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -814,61 +814,75 @@ InstallMethod( GroupWithGenerators, "list of matrices", [ IsFFECollCollColl ], #T ??? - function( gens ) - local G,fam,typ,f; - - fam:=FamilyObj(gens); - if IsFinite(gens) then - if not IsBound(fam!.defaultFinitelyGeneratedGroupType) then - fam!.defaultFinitelyGeneratedGroupType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and IsFinitelyGeneratedGroup); - fi; - typ:=fam!.defaultFinitelyGeneratedGroupType; - else - TryNextMethod(); - fi; - f:=DefaultScalarDomainOfMatrixList(gens); - gens:=List(Immutable(gens),i->ImmutableMatrix(f,i)); +function( gens ) +local G,typ,f; - G:=rec(); - ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens)); + if not IsFinite(gens) then TryNextMethod(); fi; + typ:=MakeGroupyType(FamilyObj(gens), + IsGroup and IsAttributeStoringRep + and HasGeneratorsOfMagmaWithInverses + and IsFinitelyGeneratedGroup and HasIsEmpty and IsFinite, + gens,false,true); - if IsField(f) then SetDefaultFieldOfMatrixGroup(G,f);fi; + f:=DefaultScalarDomainOfMatrixList(gens); + gens:=List(Immutable(gens),i->ImmutableMatrix(f,i)); - return G; - end ); + G:=rec(); + ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens)); + + if IsField(f) then SetDefaultFieldOfMatrixGroup(G,f);fi; + + return G; +end ); InstallMethod( GroupWithGenerators, "list of matrices with identity", IsCollsElms, [ IsFFECollCollColl,IsMultiplicativeElementWithInverse and IsFFECollColl], function( gens, id ) +local G,typ,f; + + if not IsFinite(gens) then TryNextMethod(); fi; + typ:=MakeGroupyType(FamilyObj(gens), IsGroup and IsAttributeStoringRep + and HasGeneratorsOfMagmaWithInverses and IsFinitelyGeneratedGroup + and HasIsEmpty and IsFinite and HasOne, + gens,id,true); + + f:=DefaultScalarDomainOfMatrixList(gens); + gens:=List(Immutable(gens),i->ImmutableMatrix(f,i)); + id:=ImmutableMatrix(f,id); + + G:=rec(); + ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), + One,id); + + if IsField(f) then SetDefaultFieldOfMatrixGroup(G,f);fi; + + return G; +end ); + +InstallMethod( GroupWithGenerators, + "empty list of matrices with identity", true, + [ IsList and IsEmpty,IsMultiplicativeElementWithInverse and IsFFECollColl], +function( gens, id ) local G,fam,typ,f; - fam:=FamilyObj(gens); - if IsFinite(gens) then - if not IsBound(fam!.defaultFinitelyGeneratedGroupWithOneType) then - fam!.defaultFinitelyGeneratedGroupWithOneType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and IsFinitelyGeneratedGroup and HasOne); - fi; - typ:=fam!.defaultFinitelyGeneratedGroupWithOneType; - else - TryNextMethod(); - fi; - f:=DefaultScalarDomainOfMatrixList(gens); - gens:=List(Immutable(gens),i->ImmutableMatrix(f,i)); - id:=ImmutableMatrix(f,id); + if not IsFinite(gens) then TryNextMethod(); fi; + typ:=MakeGroupyType(FamilyObj([id]), IsGroup and IsAttributeStoringRep + and HasGeneratorsOfMagmaWithInverses and IsFinitelyGeneratedGroup + and HasIsEmpty and IsFinite and HasOne + and IsTrivial and HasIsNonTrivial, + gens,id,true); + + f:=DefaultScalarDomainOfMatrixList([id]); + id:=ImmutableMatrix(f,id); - G:=rec(); - ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), - One,id); + G:=rec(); + ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), + One,id); - if IsField(f) then SetDefaultFieldOfMatrixGroup(G,f);fi; + if IsField(f) then SetDefaultFieldOfMatrixGroup(G,f);fi; - return G; + return G; end ); diff --git a/lib/grppc.gi b/lib/grppc.gi index e7e9e1726a..28901b4038 100644 --- a/lib/grppc.gi +++ b/lib/grppc.gi @@ -272,7 +272,10 @@ InstallMethod( Pcgs, ## #M GeneralizedPcgs( ) ## -InstallImmediateMethod( GeneralizedPcgs, IsGroup and HasPcgs, 0, Pcgs ); +# This used to be an immediate method. It was replaced by an ordinary +# method as the attribute is set when creating pc groups. +InstallMethod( GeneralizedPcgs,true,[ IsGroup and HasPcgs], 0, Pcgs ); + ############################################################################# ## @@ -339,77 +342,61 @@ end); InstallMethod( GroupWithGenerators, "method for pc elements collection", true, [ IsCollection and - IsMultiplicativeElementWithInverseByPolycyclicCollectorCollection] , + IsMultiplicativeElementWithInverseByPolycyclicCollectorCollection and + IsFinite] , # override methods for `IsList' or `IsEmpty'. 10, - function( gens ) - local G,fam,typ,pcgs; - - fam:=FamilyObj(gens); - if IsFinite(gens) then - if not IsBound(fam!.defaultFinitelyGeneratedGroupType) then - fam!.defaultFinitelyGeneratedGroupType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and IsFinitelyGeneratedGroup - and HasFamilyPcgs and HasHomePcgs); - fi; - typ:=fam!.defaultFinitelyGeneratedGroupType; - else - if not IsBound(fam!.defaultGroupType) then - fam!.defaultGroupType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and HasFamilyPcgs and HasHomePcgs); - fi; - typ:=fam!.defaultGroupType; - fi; +function( gens ) +local G,fam,typ,id,pcgs; - pcgs:=DefiningPcgs(ElementsFamily(fam)); - - G:=rec(); - ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), - FamilyPcgs,pcgs,HomePcgs,pcgs); - SetGroupOfPcgs (pcgs, G); - return G; - end ); + fam:=FamilyObj(gens); + pcgs:=DefiningPcgs(ElementsFamily(fam)); + + # pc groups are always finite and gens is finite. + typ:=MakeGroupyType(fam, + IsGroup and IsAttributeStoringRep and IsSolvableGroup + and HasIsEmpty and HasGeneratorsOfMagmaWithInverses + and IsFinite and IsFinitelyGeneratedGroup + and HasFamilyPcgs and HasHomePcgs and HasGeneralizedPcgs, + gens,One(gens[1]),true); + + G:=rec(); + ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), + FamilyPcgs,pcgs,HomePcgs,pcgs,GeneralizedPcgs,pcgs); + #SetGroupOfPcgs (pcgs, G); That cannot be true, as pcgs is the family pcgs + + return G; +end ); InstallOtherMethod( GroupWithGenerators, "method for pc collection and identity element", IsCollsElms, [ IsCollection and - IsMultiplicativeElementWithInverseByPolycyclicCollectorCollection , + IsMultiplicativeElementWithInverseByPolycyclicCollectorCollection + and IsFinite, IsMultiplicativeElementWithInverseByPolycyclicCollector] , 0, - function( gens, id ) - local G,fam,typ,pcgs; - - fam:=FamilyObj(gens); - if IsFinite(gens) then - if not IsBound(fam!.defaultFinitelyGeneratedGroupWithOneType) then - fam!.defaultFinitelyGeneratedGroupWithOneType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and IsFinitelyGeneratedGroup and HasOne - and HasFamilyPcgs and HasHomePcgs); - fi; - typ:=fam!.defaultFinitelyGeneratedGroupWithOneType; - else - if not IsBound(fam!.defaultGroupWithOneType) then - fam!.defaultGroupWithOneType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses and HasOne - and HasFamilyPcgs and HasHomePcgs); - fi; - typ:=fam!.defaultGroupWithOneType; - fi; +function( gens, id ) +local G,fam,typ,pcgs; - pcgs:=DefiningPcgs(ElementsFamily(fam)); + fam:=FamilyObj(gens); + pcgs:=DefiningPcgs(ElementsFamily(fam)); - G:=rec(); - ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), - One,id,FamilyPcgs,pcgs,HomePcgs,pcgs); - SetGroupOfPcgs (pcgs, G); - return G; + # pc groups are always finite and gens is finite. + typ:=MakeGroupyType(fam, + IsGroup and IsAttributeStoringRep and IsSolvableGroup + and HasIsEmpty and HasGeneratorsOfMagmaWithInverses and HasOne + and IsFinite and IsFinitelyGeneratedGroup + and HasFamilyPcgs and HasHomePcgs and HasGeneralizedPcgs, + gens,id,true); + + G:=rec(); + ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), + One,id, + FamilyPcgs,pcgs,HomePcgs,pcgs,GeneralizedPcgs,pcgs); + + #SetGroupOfPcgs (pcgs, G); + + return G; end ); InstallOtherMethod( GroupWithGenerators, @@ -418,29 +405,31 @@ InstallOtherMethod( GroupWithGenerators, IsMultiplicativeElementWithInverseByPolycyclicCollector] , # override methods for `IsList' or `IsEmpty'. 10, - function( gens, id ) - local G,fam,typ,pcgs; - - fam:= CollectionsFamily( FamilyObj( id ) ); - if not IsBound(fam!.defaultFinitelyGeneratedGroupWithOneType) then - fam!.defaultFinitelyGeneratedGroupWithOneType:= - NewType(fam,IsGroup and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses - and IsFinitelyGeneratedGroup and HasOne - and HasFamilyPcgs and HasHomePcgs); - fi; - typ:=fam!.defaultFinitelyGeneratedGroupWithOneType; +function( empty, id ) +local G,fam,typ,pcgs; - pcgs:=DefiningPcgs(ElementsFamily(fam)); + fam:= CollectionsFamily( FamilyObj( id ) ); - G:=rec(); - ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,[], - One,id,FamilyPcgs,pcgs,HomePcgs,pcgs); + # pc groups are always finite and gens is finite. + typ:=IsGroup and IsAttributeStoringRep + and HasGeneratorsOfMagmaWithInverses and HasOne + and IsFinite and IsFinitelyGeneratedGroup + and IsTrivial and HasIsNonTrivial + and HasIsEmpty and IsSolvableGroup + and HasFamilyPcgs and HasHomePcgs and HasGeneralizedPcgs; + typ:=NewType(fam,typ); - SetGroupOfPcgs (pcgs, G); - return G; -end ); + pcgs:=DefiningPcgs(ElementsFamily(fam)); + G:= rec(); + ObjectifyWithAttributes( G, typ, + GeneratorsOfMagmaWithInverses, empty, + One, id, + FamilyPcgs,pcgs,HomePcgs,pcgs,GeneralizedPcgs,pcgs); + + #SetGroupOfPcgs (pcgs, G); + return G; +end ); ############################################################################# ## diff --git a/lib/grppcaut.gi b/lib/grppcaut.gi index 4ded2f9eaf..dd683e75cd 100644 --- a/lib/grppcaut.gi +++ b/lib/grppcaut.gi @@ -1804,6 +1804,7 @@ InstallGlobalFunction(AutomorphismGroupSolvableGroup,function( G ) Add( autos, new ); od; B := GroupByGenerators( autos ); + SetIsGroupOfAutomorphismsFiniteGroup(B,true); SetSize( B, Size(A) ); PopOptions(); # undo the added `fail' return B; @@ -1906,6 +1907,7 @@ InstallGlobalFunction(AutomorphismGroupFrattFreeGroup,function( G ) # create automorphism group B := GroupByGenerators( full, IdentityMapping( G ) ); + SetIsGroupOfAutomorphismsFiniteGroup(B,true); SetSize( B, size ); return B; @@ -1960,7 +1962,6 @@ InstallGlobalFunction(AutomorphismGroupNilpotentGroup,function(G) autG := Group( gensAutG, IdentityMapping(G) ); SetIsAutomorphismGroup(autG, true); SetIsGroupOfAutomorphismsFiniteGroup(autG, true); - SetIsFinite(autG,true); return autG; end ); diff --git a/lib/grppcext.gi b/lib/grppcext.gi index 1f12b2fe8b..7ef4ba8b77 100644 --- a/lib/grppcext.gi +++ b/lib/grppcext.gi @@ -526,6 +526,7 @@ local ag, p1iso, agp, p2iso, DP, p1, p2, gens, genimgs, triso,s,i,u,opt, # If this is the first time we use it, # copy group to avoid carrying too much cruft later. ag:=Group(GeneratorsOfGroup(ag),One(ag)); + SetIsGroupOfAutomorphismsFiniteGroup(ag,true); SetSize(ag,s); fi; IsGroupOfAutomorphismsFiniteGroup(ag); @@ -953,6 +954,7 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, fi; fi; tmp:=SubgroupNC(Range(triso),genimgs); + SetIsGroupOfAutomorphismsFiniteGroup(tmp,true); SetSize(tmp,l); # cache the faithful permutation representation in case we need it # later diff --git a/lib/magma.gi b/lib/magma.gi index 47c3598d5a..6c1eac9b3a 100644 --- a/lib/magma.gi +++ b/lib/magma.gi @@ -119,8 +119,8 @@ InstallImmediateMethod( IsTrivial, fi; end ); -InstallImmediateMethod( IsTrivial, - IsMagmaWithInverses and HasGeneratorsOfMagmaWithInverses, 0, +InstallMethod( IsTrivial, + [IsMagmaWithInverses and HasGeneratorsOfMagmaWithInverses], 0, function( M ) if IsEmpty( GeneratorsOfMagmaWithInverses( M ) ) then return true; @@ -184,9 +184,11 @@ InstallImmediateMethod( IsCommutative, fi; end ); -InstallImmediateMethod( IsCommutative, - IsMagmaWithInverses and IsAssociative - and HasGeneratorsOfMagmaWithInverses, 0, +# This used to be an immediate method. It was replaced by an ordinary +# method, as the filter is now set when creating groups. +InstallMethod( IsCommutative,true, + [IsMagmaWithInverses and IsAssociative + and HasGeneratorsOfMagmaWithInverses], 0, function( M ) if Length( GeneratorsOfMagmaWithInverses( M ) ) = 1 then return true; @@ -652,17 +654,19 @@ InstallOtherMethod( MagmaWithOneByGenerators, #M MagmaWithInversesByGenerators( ) . . . . . . . . for a collection ## MakeMagmaWithInversesByFiniteGenerators:=function(family,gens) -local M; - if not IsBound(family!.defaultMagmaWithInversesByGeneratorsType) then - family!.defaultMagmaWithInversesByGeneratorsType := - NewType( FamilyObj( gens ), - IsMagmaWithInverses and IsAttributeStoringRep - and HasGeneratorsOfMagmaWithInverses); - fi; +local M,typ,id,fam; + + typ:=MakeGroupyType(FamilyObj(gens), + IsMagmaWithInverses and IsAttributeStoringRep + and HasGeneratorsOfMagmaWithInverses + and HasIsEmpty, + gens,fail,false); M:=rec(); - ObjectifyWithAttributes( M,family!.defaultMagmaWithInversesByGeneratorsType, - GeneratorsOfMagmaWithInverses, AsList( gens ) ); + + ObjectifyWithAttributes( M,typ, + GeneratorsOfMagmaWithInverses, AsList( gens )); + if HasIsAssociative( M ) and IsAssociative( M ) then SetIsFinitelyGeneratedGroup( M, true ); fi; diff --git a/lib/modulrow.gi b/lib/modulrow.gi index 645823dce4..efc9d07a15 100644 --- a/lib/modulrow.gi +++ b/lib/modulrow.gi @@ -21,26 +21,36 @@ #F FullRowModule( , ) ## InstallGlobalFunction( FullRowModule, function( R, n ) - local M; # the free module record, result +local M,typ; # the free module record, result if not ( IsRing( R ) and IsInt( n ) and 0 <= n ) then Error( "usage: FullRowModule( , ) for ring " ); fi; + typ:=IsFreeLeftModule and IsFullRowModule and IsAttributeStoringRep + and HasIsEmpty; + if IsDivisionRing( R ) then - M:= Objectify( NewType( CollectionsFamily( FamilyObj( R ) ), - IsFreeLeftModule - and IsGaussianSpace - and IsFullRowModule - and IsAttributeStoringRep ), - rec() ); + typ:=typ and IsGaussianSpace; + fi; + + if n=0 then + typ:=typ and IsTrivial and HasIsNonTrivial and IsFinite; else - M:= Objectify( NewType( CollectionsFamily( FamilyObj( R ) ), - IsFreeLeftModule - and IsFullRowModule - and IsAttributeStoringRep ), - rec() ); + typ:=typ and HasIsTrivial and IsNonTrivial; + fi; + + if n<>infinity and HasIsFinite(R) and IsFinite(R) then + typ:=typ and IsFinite; + elif n<>0 and HasIsFinite(R) and not IsFinite(R) then + typ:=typ and HasIsFinite; fi; + + + M:= Objectify( NewType( CollectionsFamily( FamilyObj( R ) ), + typ ), + rec() ); + SetLeftActingDomain( M, R ); SetDimensionOfVectors( M, n ); diff --git a/lib/object.gd b/lib/object.gd index 6269994a98..e2f2a394e4 100644 --- a/lib/object.gd +++ b/lib/object.gd @@ -665,8 +665,7 @@ DeclareOperation( "ObjByExtRep", [ IsFamily, IsObject ] ); ## gap> KnownAttributesOfObject(g); ## [ "Size", "OneImmutable", "NrMovedPoints", "MovedPoints", ## "GeneratorsOfMagmaWithInverses", "MultiplicativeNeutralElement", -## "HomePcgs", "Pcgs", "GeneralizedPcgs", "StabChainMutable", -## "StabChainOptions" ] +## "HomePcgs", "Pcgs", "StabChainMutable", "StabChainOptions" ] ## ]]> ## ## @@ -707,28 +706,29 @@ DeclareOperation( "KnownPropertiesOfObject", [ IsObject ] ); ## g:=Group((1,2),(1,2,3));; ## gap> KnownPropertiesOfObject(g); -## [ "IsFinite", "CanEasilyCompareElements", "CanEasilySortElements", -## "IsDuplicateFree", "IsGeneratorsOfMagmaWithInverses", -## "IsAssociative", "IsGeneratorsOfSemigroup", "IsSimpleSemigroup", -## "IsRegularSemigroup", "IsInverseSemigroup", -## "IsCompletelyRegularSemigroup", "IsCompletelySimpleSemigroup", -## "IsGroupAsSemigroup", "IsMonoidAsSemigroup", "IsOrthodoxSemigroup", -## "IsFinitelyGeneratedGroup", "IsSubsetLocallyFiniteGroup", -## "KnowsHowToDecompose", "IsInfiniteAbelianizationGroup", -## "IsNilpotentByFinite" ] +## [ "IsEmpty", "IsTrivial", "IsNonTrivial", "IsFinite", +## "CanEasilyCompareElements", "CanEasilySortElements", +## "IsDuplicateFree", "IsGeneratorsOfMagmaWithInverses", +## "IsAssociative", "IsGeneratorsOfSemigroup", "IsSimpleSemigroup", +## "IsRegularSemigroup", "IsInverseSemigroup", +## "IsCompletelyRegularSemigroup", "IsCompletelySimpleSemigroup", +## "IsGroupAsSemigroup", "IsMonoidAsSemigroup", "IsOrthodoxSemigroup", +## "IsFinitelyGeneratedGroup", "IsSubsetLocallyFiniteGroup", +## "KnowsHowToDecompose", "IsInfiniteAbelianizationGroup", +## "IsNilpotentByFinite", "IsTorsionFree", "IsFreeAbelian" ] ## gap> Size(g); ## 6 ## gap> KnownPropertiesOfObject(g); -## [ "IsEmpty", "IsTrivial", "IsNonTrivial", "IsFinite", -## "CanEasilyCompareElements", "CanEasilySortElements", -## "IsDuplicateFree", "IsGeneratorsOfMagmaWithInverses", -## "IsAssociative", "IsGeneratorsOfSemigroup", "IsSimpleSemigroup", -## "IsRegularSemigroup", "IsInverseSemigroup", -## "IsCompletelyRegularSemigroup", "IsCompletelySimpleSemigroup", -## "IsGroupAsSemigroup", "IsMonoidAsSemigroup", "IsOrthodoxSemigroup", -## "IsFinitelyGeneratedGroup", "IsSubsetLocallyFiniteGroup", -## "KnowsHowToDecompose", "IsPerfectGroup", "IsSolvableGroup", -## "IsPolycyclicGroup", "IsInfiniteAbelianizationGroup", +## [ "IsEmpty", "IsTrivial", "IsNonTrivial", "IsFinite", +## "CanEasilyCompareElements", "CanEasilySortElements", +## "IsDuplicateFree", "IsGeneratorsOfMagmaWithInverses", +## "IsAssociative", "IsGeneratorsOfSemigroup", "IsSimpleSemigroup", +## "IsRegularSemigroup", "IsInverseSemigroup", +## "IsCompletelyRegularSemigroup", "IsCompletelySimpleSemigroup", +## "IsGroupAsSemigroup", "IsMonoidAsSemigroup", "IsOrthodoxSemigroup", +## "IsFinitelyGeneratedGroup", "IsSubsetLocallyFiniteGroup", +## "KnowsHowToDecompose", "IsPerfectGroup", "IsSolvableGroup", +## "IsPolycyclicGroup", "IsInfiniteAbelianizationGroup", ## "IsNilpotentByFinite", "IsTorsionFree", "IsFreeAbelian" ] ## gap> KnownTruePropertiesOfObject(g); ## [ "IsNonTrivial", "IsFinite", "CanEasilyCompareElements", diff --git a/lib/read1.g b/lib/read1.g index 831ca8981b..50c115a998 100644 --- a/lib/read1.g +++ b/lib/read1.g @@ -38,6 +38,7 @@ ReadLib( "record.gd" ); ReadLib( "random.gd" ); ReadLib( "cache.gi" ); +ReadLib( "assert.gd" ); ReadLib( "coll.gi" ); ReadLib( "flag.g" ); @@ -54,7 +55,6 @@ ReadLib( "filter.gi" ); ReadLib( "object.gi" ); ReadLib( "listcoef.gd" ); ReadLib( "info.gd" ); -ReadLib( "assert.gd" ); ReadLib( "files.gd" ); ReadLib( "streams.gd" ); diff --git a/lib/vspcrow.gi b/lib/vspcrow.gi index a5f67a94f4..80f5f9b78a 100644 --- a/lib/vspcrow.gi +++ b/lib/vspcrow.gi @@ -54,22 +54,31 @@ InstallMethod( LeftModuleByGenerators, IsElmsColls, [ IsDivisionRing, IsMatrix ], function( F, mat ) - local V; + local V,typ; + typ:=IsAttributeStoringRep and HasIsEmpty and IsFiniteDimensional; if ForAll( mat, row -> IsSubset( F, row ) ) then - V:= Objectify( NewType( FamilyObj( mat ), - IsGaussianRowSpace - and IsAttributeStoringRep ), - rec() ); + typ:=typ and IsGaussianRowSpace; else - V:= Objectify( NewType( FamilyObj( mat ), - IsVectorSpace - and IsNonGaussianRowSpace - and IsRowModule - and IsAttributeStoringRep ), - rec() ); + typ:=typ and IsVectorSpace and IsRowModule and IsNonGaussianRowSpace; + fi; + + if Length(mat)>0 and ForAny(mat,x->not IsZero(x)) then + typ:=typ and HasIsTrivial and IsNonTrivial; + else + typ:=typ and IsTrivial and HasIsNonTrivial; + fi; + + if HasIsFinite(F) then + if IsFinite(F) then + typ:=typ and IsFinite; + else + typ:=typ and HasIsFinite; # i.e. not finite + fi; fi; + V:= Objectify( NewType( FamilyObj( mat ), typ), rec() ); + SetLeftActingDomain( V, F ); SetGeneratorsOfLeftModule( V, AsList( mat ) ); SetDimensionOfVectors( V, Length( mat[1] ) ); @@ -81,7 +90,7 @@ InstallMethod( LeftModuleByGenerators, "for division ring, empty list, and row vector", [ IsDivisionRing, IsList and IsEmpty, IsRowVector ], function( F, empty, zero ) - local V; + local V,typ; # Check whether this method is the right one. if not IsIdenticalObj( FamilyObj( F ), FamilyObj( zero ) ) then @@ -89,9 +98,11 @@ InstallMethod( LeftModuleByGenerators, fi; #T explicit 2nd argument above! - V:= Objectify( NewType( CollectionsFamily( FamilyObj( F ) ), - IsGaussianRowSpace - and IsAttributeStoringRep ), + typ:=IsAttributeStoringRep and HasIsEmpty and IsFiniteDimensional + and IsGaussianRowSpace and IsTrivial and HasIsNonTrivial and + IsFinite; + + V:= Objectify( NewType( CollectionsFamily( FamilyObj( F ) ),typ), rec() ); SetLeftActingDomain( V, F ); SetGeneratorsOfLeftModule( V, empty ); @@ -105,7 +116,7 @@ InstallMethod( LeftModuleByGenerators, "for division ring, matrix over it, and row vector", [ IsDivisionRing, IsMatrix, IsRowVector ], function( F, mat, zero ) - local V; + local V,typ; # Check whether this method is the right one. if not IsElmsColls( FamilyObj( F ), FamilyObj( mat ) ) then @@ -113,20 +124,29 @@ InstallMethod( LeftModuleByGenerators, fi; #T explicit 2nd argument above! + typ:=IsAttributeStoringRep and HasIsEmpty and IsFiniteDimensional; if ForAll( mat, row -> IsSubset( F, row ) ) then - V:= Objectify( NewType( FamilyObj( mat ), - IsGaussianRowSpace - and IsAttributeStoringRep ), - rec() ); + typ:=typ and IsGaussianRowSpace; + else + typ:=typ and IsVectorSpace and IsRowModule and IsNonGaussianRowSpace; + fi; + + if Length(mat)>0 and ForAny(mat,x->not IsZero(x)) then + typ:=typ and HasIsTrivial and IsNonTrivial; else - V:= Objectify( NewType( FamilyObj( mat ), - IsVectorSpace - and IsNonGaussianRowSpace - and IsRowModule - and IsAttributeStoringRep ), - rec() ); + typ:=typ and IsTrivial and HasIsNonTrivial; fi; + if HasIsFinite(F) then + if IsFinite(F) then + typ:=typ and IsFinite; + else + typ:=typ and HasIsFinite; # i.e. not finite + fi; + fi; + + V:= Objectify( NewType( FamilyObj( mat ), typ), rec() ); + SetLeftActingDomain( V, F ); SetGeneratorsOfLeftModule( V, AsList( mat ) ); SetZero( V, zero ); diff --git a/tst/testbugfix/00005.tst b/tst/testbugfix/00005.tst index eac0dfe58c..c86e494204 100644 --- a/tst/testbugfix/00005.tst +++ b/tst/testbugfix/00005.tst @@ -15,4 +15,4 @@ gap> G:=GroupByGenerators( [ [ [ 0, -1, 0, 0 ], [ 1, 0, 0, 0 ], Group([ [ [ 0, -1, 0, 0 ], [ 1, 0, 0, 0 ], [ 0, 0, 0, -1 ], [ 0, 0, 1, 0 ] ] ]) gap> Centralizer(N,G); - + diff --git a/tst/testinstall/algmat.tst b/tst/testinstall/algmat.tst index ce3f21e58b..8691d3c40a 100644 --- a/tst/testinstall/algmat.tst +++ b/tst/testinstall/algmat.tst @@ -256,8 +256,7 @@ gap> n:= NullAlgebra( GF(3) ); gap> Dimension( n ); 0 -gap> b:= Basis( n ); -SemiEchelonBasis( , [ ] ) +gap> b:= Basis( n );; gap> BasisVectors( b ); [ ] gap> zero:= Zero( n ); diff --git a/tst/testinstall/coll.tst b/tst/testinstall/coll.tst index f03249a52b..89168d1bc8 100644 --- a/tst/testinstall/coll.tst +++ b/tst/testinstall/coll.tst @@ -48,12 +48,13 @@ gap> List(props, p -> p(M0)); gap> N1:=Magma([[[1,0],[0,0]]]);; gap> ForAll(props, prop -> not Tester(prop)(N1)); true -gap> Size(N1); -1 -gap> ForAll(props, prop -> Tester(prop)(N1)); -true -gap> List(props, p -> p(N1)); -[ false, true, false, true ] + +#gap> Size(N1); +#1 +#gap> ForAll(props, prop -> Tester(prop)(N1)); +#true +#gap> List(props, p -> p(N1)); +#[ false, true, false, true ] # ... immediate methods for a collection which knows its size, # applied to collection with size greater than 1 @@ -97,13 +98,11 @@ Error, cannot test whether contains the family of its elements # Size # -# immediate method for collections knowing they are infinite +## method for collections knowing they are infinite gap> c2:=ConjugacyClass(F, F.1);; gap> HasSize(c2); false gap> SetIsFinite(c2, false); -gap> HasSize(c2); -true gap> Size(c2); infinity diff --git a/tst/testinstall/semigrp.tst b/tst/testinstall/semigrp.tst index 7b3d53e5c7..37ea869e07 100644 --- a/tst/testinstall/semigrp.tst +++ b/tst/testinstall/semigrp.tst @@ -376,7 +376,7 @@ gap> GeneratorsOfInverseSemigroup(S); gap> GeneratorsOfInverseMonoid(S); [ ] gap> S := Group(IdentityTransformation); - + gap> GeneratorsOfSemigroup(S); [ IdentityTransformation ] gap> GeneratorsOfMonoid(S); @@ -474,12 +474,11 @@ true gap> Semigroup(Idempotents(S)) = S; true -# test the methods for Random +# test the methods for Random, but do not test for the values of random +# elements gap> S := FreeSemigroup(3);; -gap> Random(S); -s1*s2 -gap> Random(GlobalRandomSource, S); -s3*s2^2 +gap> Random(S);; +gap> Random(GlobalRandomSource, S);; #T# Test DisplaySemigroup gap> DisplaySemigroup(FullTransformationSemigroup(1)); diff --git a/tst/testinstall/semitran.tst b/tst/testinstall/semitran.tst index a76324e36a..a3dae32917 100644 --- a/tst/testinstall/semitran.tst +++ b/tst/testinstall/semitran.tst @@ -141,7 +141,7 @@ gap> S := Group(Transformation([2,1,3])); gap> DegreeOfTransformationSemigroup(S); 2 gap> S := Group(IdentityTransformation); - + gap> GeneratorsOfGroup(S); [ IdentityTransformation ] gap> S := Semigroup(IdentityTransformation);