diff --git a/doc/ref/grplib.xml b/doc/ref/grplib.xml index 3f463fcfa1..29dee10899 100644 --- a/doc/ref/grplib.xml +++ b/doc/ref/grplib.xml @@ -89,7 +89,9 @@ calculations. <#Include Label="ElementaryAbelianGroup"> <#Include Label="FreeAbelianGroup"> <#Include Label="DihedralGroup"> -<#Include Label="QuaternionGroup"> +<#Include Label="IsDihedralGroup"> +<#Include Label="DicyclicGroup"> +<#Include Label="IsQuaternionGroup"> <#Include Label="ExtraspecialGroup"> <#Include Label="AlternatingGroup"> <#Include Label="SymmetricGroup"> diff --git a/grp/basic.gd b/grp/basic.gd index 9f2a28def6..d9c40d17cf 100644 --- a/grp/basic.gd +++ b/grp/basic.gd @@ -343,31 +343,34 @@ end ); ############################################################################# ## -#O QuaternionGroupCons( , ) +#O DicyclicGroupCons( , ) ## ## -## +## ## ## ## ## ## -DeclareConstructor( "QuaternionGroupCons", [ IsGroup, IsInt ] ); +DeclareConstructor( "DicyclicGroupCons", [ IsGroup, IsInt ] ); +DeclareSynonym("QuaternionGroupCons", DicyclicGroupCons); ############################################################################# ## -#F QuaternionGroup( [, ] ) . . . . . . . quaternion group of order +#F DicyclicGroup( [, [, ] ] ) Dicyclic group of order ## -## <#GAPDoc Label="QuaternionGroup"> +## <#GAPDoc Label="DicyclicGroup"> ## -## -## +## +## ## ## -## constructs the generalized quaternion group (or dicyclic group) of size -## n in the category given by the filter filt. Here, n -## is a multiple of 4. +## constructs the dicyclic group of size n +## in the category given by the filter filt. Here, n must be a +## multiple of 4. The synonym for +## is provided for backward compatibility, but will +## print a warning if n is not a power of 2. ## If filt is not given it defaults to . ## For more information on possible values of filt see section ## (). @@ -375,8 +378,8 @@ DeclareConstructor( "QuaternionGroupCons", [ IsGroup, IsInt ] ); ## degree and minimal dimension in coprime characteristic). ##

## QuaternionGroup(32); -## +## gap> DicyclicGroup(24); +## ## gap> g:=QuaternionGroup(IsMatrixGroup,CF(16),32); ## Group([ [ [ 0, 1 ], [ -1, 0 ] ], [ [ E(16), 0 ], [ 0, -E(16)^7 ] ] ]) ## ]]> @@ -384,23 +387,77 @@ DeclareConstructor( "QuaternionGroupCons", [ IsGroup, IsInt ] ); ## ## <#/GAPDoc> ## -BindGlobal( "QuaternionGroup", function ( arg ) +BindGlobal( "GRPLIB_DicyclicParameterCheck", +function(args, quaternion) + local size; + + if Length(args) = 1 then + args := [ IsPcGroup, args[1] ]; + elif Length(args) = 2 then + # 2 inputs are valid, but we just reuse args + # args := args; + elif Length(args) = 3 then + if not IsField(args[2]) then + ErrorNoReturn("usage: must be a field"); + fi; + else + ErrorNoReturn("usage: DicyclicGroup( [, [, ] ] )"); + fi; - if Length(arg) = 1 then - return QuaternionGroupCons( IsPcGroup, arg[1] ); - elif IsOperation(arg[1]) then - if Length(arg) = 2 then - return QuaternionGroupCons( arg[1], arg[2] ); - elif Length(arg) = 3 then - # some filters require extra arguments, e.g. IsMatrixGroup + field - return QuaternionGroupCons( arg[1], arg[2], arg[3] ); + size := args[Length(args)]; + if not IsFilter(args[1]) then + ErrorNoReturn("usage: must be a filter"); fi; - fi; - Error( "usage: QuaternionGroup( [, ] )" ); -end ); + if not (IsPosInt(size) and (size mod 4 = 0)) then + ErrorNoReturn("usage: must be a positive integer divisible by 4"); + fi; + + if not IsPrimePowerInt(size) or size < 8 then + if quaternion = "error" then + ErrorNoReturn("usage: must be a power of 2 and at least 8"); + elif quaternion = "warn" then + if not IsPrimePowerInt(size) then + Info(InfoWarning, 1, "Warning: QuaternionGroup called with ", size, + " which is not a power of 2"); + else + Info(InfoWarning, 1, "Warning: QuaternionGroup called with ", size, + " which is less than 8"); + fi; + fi; + fi; + + return args; +end); + +BindGlobal( "DicyclicGroup", +function(args...) + local res; + + res := GRPLIB_DicyclicParameterCheck(args, ""); + + return CallFuncList(DicyclicGroupCons, res); +end); + +BindGlobal( "QuaternionGroup", +function(args...) + local res; -DeclareSynonym( "DicyclicGroup", QuaternionGroup ); + res := GRPLIB_DicyclicParameterCheck(args, "warn"); + + return CallFuncList(DicyclicGroupCons, res); +end); + +BindGlobal( "GeneralisedQuaternionGroup", +function(args...) + local res, grp; + + res := GRPLIB_DicyclicParameterCheck(args, "error"); + grp := CallFuncList(DicyclicGroupCons, res); + SetIsGeneralisedQuaternionGroup(grp, true); + + return grp; +end); ############################################################################# diff --git a/grp/basicfp.gi b/grp/basicfp.gi index 8c18059a17..76fa791db5 100644 --- a/grp/basicfp.gi +++ b/grp/basicfp.gi @@ -174,9 +174,9 @@ end ); ############################################################################# ## -#M QuaternionGroupCons( , ) +#M DicyclicGroupCons( , ) ## -InstallMethod( QuaternionGroupCons, +InstallMethod( DicyclicGroupCons, "fp group", true, [ IsFpGroup and IsFinite, diff --git a/grp/basicmat.gi b/grp/basicmat.gi index 94af904604..dabc6db18a 100644 --- a/grp/basicmat.gi +++ b/grp/basicmat.gi @@ -68,23 +68,23 @@ end ); ############################################################################# ## -#M QuaternionGroupCons( , ) +#M DicyclicGroupCons( , ) ## -InstallMethod( QuaternionGroupCons, +InstallMethod( DicyclicGroupCons, "matrix group for default field", true, [ IsMatrixGroup and IsFinite, IsInt and IsPosRat ], 0, function( filter, n ) - return QuaternionGroup( filter, Rationals, n ); + return DicyclicGroup( filter, Rationals, n ); end ); ############################################################################# ## -#M QuaternionGroupCons( , , ) +#M DicyclicGroupCons( , , ) ## -InstallOtherMethod( QuaternionGroupCons, +InstallOtherMethod( DicyclicGroupCons, "matrix group for given field", true, [ IsMatrixGroup and IsFinite, @@ -103,7 +103,7 @@ function( filter, fld, n ) one := 1; elif Characteristic( fld ) = 0 or (0 = n mod Characteristic( fld )) then # XXX: regular rep is not minimal - grp := QuaternionGroup( IsPermGroup, n ); + grp := DicyclicGroup( IsPermGroup, n ); grp := Group( List( GeneratorsOfGroup( grp ), prm -> PermutationMat( prm, NrMovedPoints( grp ), fld ) ) ); SetSize( grp, n ); return grp; diff --git a/grp/basicpcg.gi b/grp/basicpcg.gi index 64154edc09..702d69d463 100644 --- a/grp/basicpcg.gi +++ b/grp/basicpcg.gi @@ -217,9 +217,9 @@ end ); ############################################################################# ## -#M QuaternionGroupCons( , ) +#M DicyclicGroupCons( , ) ## -InstallMethod( QuaternionGroupCons, +InstallMethod( DicyclicGroupCons, "pc group", true, [ IsPcGroup and IsFinite, diff --git a/grp/basicprm.gi b/grp/basicprm.gi index 7ef7adbfde..d6118b6524 100644 --- a/grp/basicprm.gi +++ b/grp/basicprm.gi @@ -236,9 +236,9 @@ InstallMethod( DihedralGroupCons, ############################################################################# ## -#M QuaternionGroupCons( , <4n> ) +#M DicyclicGroupCons( , <4n> ) ## -InstallMethod( QuaternionGroupCons, +InstallMethod( DicyclicGroupCons, "perm. group", true, [ IsPermGroup, IsPosInt ], 0, diff --git a/lib/grp.gd b/lib/grp.gd index c40b5ab3b9..609b7581da 100644 --- a/lib/grp.gd +++ b/lib/grp.gd @@ -3220,7 +3220,7 @@ DeclareOperation("CentralizerModulo", [IsGroup,IsGroup,IsObject]); ## U_1:= G, ## U_i:= [G, U_{{i-1}}] U_{{i-1}}^{p}. ## g:=QuaternionGroup(12);; +## gap> g:=DicyclicGroup(12);; ## gap> PCentralSeries(g,2); ## [ , Group([ y3, y*y3 ]), Group([ y*y3 ]) ] ## gap> g:=SymmetricGroup(4);; @@ -3250,7 +3250,7 @@ KeyDependentOperation( "PCentralSeries", IsGroup, IsPosInt, "prime" ); ## . ##

## g:=QuaternionGroup(12);; +## gap> g:=DicyclicGroup(12);; ## gap> PRump(g,2) = PCentralSeries(g,2)[2]; ## true ## gap> g:=SymmetricGroup(4);; @@ -3279,7 +3279,7 @@ KeyDependentOperation( "PRump", IsGroup, IsPosInt, "prime" ); ## It is the core of a Sylow p-subgroup of G, ## see . ## g:=QuaternionGroup(12);; +## gap> g:=DicyclicGroup(12);; ## gap> PCore(g,2); ## Group([ y3 ]) ## gap> PCore(g,2) = Core(g,SylowSubgroup(g,2)); diff --git a/lib/grpnames.gd b/lib/grpnames.gd index 35357adc9b..fc4a93bb2a 100644 --- a/lib/grpnames.gd +++ b/lib/grpnames.gd @@ -433,45 +433,62 @@ DeclareSynonym( "DecompositionTypes", DecompositionTypesOfGroup ); #P IsDihedralGroup( ) #A DihedralGenerators( ) ## +## <#GAPDoc Label="IsDihedralGroup"> ## ## ## ## ## -## Indicates whether the group G is a dihedral group. -## If it is, methods may set the attribute DihedralGenerators to +## indicates whether the group G is a +## dihedral group. If it is, methods may set the attribute +## to ## [t,s], where t and s are two elements such -## that G = t, s | t^2 = s^n = 1, s^t = s^-1. +## that G = \langle t, s | t^2 = s^n = 1, s^t = s^{-1} \rangle. ## ## +## <#/GAPDoc> ## DeclareProperty( "IsDihedralGroup", IsGroup ); DeclareAttribute( "DihedralGenerators", IsGroup ); InstallTrueMethod( IsGroup, IsDihedralGroup ); +InstallTrueMethod( IsDihedralGroup, HasDihedralGenerators ); + ############################################################################# ## #P IsQuaternionGroup( ) #A QuaternionGenerators( ) ## +## <#GAPDoc Label="IsQuaternionGroup"> ## +## ## +## ## ## ## -## Indicates whether the group G is a generalized quaternion group -## of size N = 2^(k+1), k >= 2. If it is, methods may set -## the attribute QuaternionGenerators to [t,s], -## where t and s are two elements such that G = -## t, s | s^(2^k) = 1, t^2 = s^(2^k-1), s^t = s^-1. +## indicates whether the group +## G is a generalized quaternion group of size N = 2^(k+1), +## k >= 2. +## If it is, methods may set the attribute +## to [t,s], where t and s are two elements such that G = +## \langle t, s | s^{(2^k)} = 1, t^2 = s^{(2^k-1)}, s^t = s^{-1} \rangle. +## and are +## provided for backwards compatibility with existing code. ## ## +## <#/GAPDoc> ## -DeclareProperty( "IsQuaternionGroup", IsGroup ); -DeclareAttribute( "QuaternionGenerators", IsGroup ); +DeclareProperty( "IsGeneralisedQuaternionGroup", IsGroup ); +DeclareAttribute( "GeneralisedQuaternionGenerators", IsGroup ); +# Backwards compatibility +DeclareSynonymAttr( "IsQuaternionGroup", IsGeneralisedQuaternionGroup ); +DeclareSynonymAttr( "QuaternionGenerators", GeneralisedQuaternionGenerators ); InstallTrueMethod( IsGroup, IsQuaternionGroup ); +InstallTrueMethod( IsGeneralisedQuaternionGroup, HasGeneralisedQuaternionGenerators ); + ############################################################################# ## diff --git a/lib/grpnames.gi b/lib/grpnames.gi index 98b630580e..0c23f94f5a 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -949,16 +949,11 @@ InstallMethod( DecompositionTypesOfGroup, ## #M IsDihedralGroup( ) . . . . . . . . . . . . . . . . . . generic method ## -InstallMethod( IsDihedralGroup, - "generic method", true, [ IsGroup ], 0, - - function ( G ) +DoComputeDihedralGenerators := function(G) local Zn, G1, T, n, t, s, i; - if not IsFinite(G) then TryNextMethod(); fi; - - if Size(G) mod 2 <> 0 then return false; fi; + if Size(G) mod 2 <> 0 then return fail; fi; n := Size(G)/2; # find a normal subgroup of G of type Zn @@ -966,12 +961,12 @@ InstallMethod( IsDihedralGroup, # G = < s, t | s^n = t^2 = 1, s^t = s^-1 > # ==> Comm(s, t) = s^-1 t s t = s^-2 ==> G' = < s^2 > = < s > Zn := DerivedSubgroup(G); - if not ( IsCyclic(Zn) and Size(Zn) = n ) then return false; fi; + if not ( IsCyclic(Zn) and Size(Zn) = n ) then return fail; fi; else # n mod 2 = 0 # G = < s, t | s^n = t^2 = 1, s^t = s^-1 > # ==> Comm(s, t) = s^-1 t s t = s^-2 ==> G' = < s^2 > G1 := DerivedSubgroup(G); - if not ( IsCyclic(G1) and Size(G1) = n/2 ) then return false; fi; + if not ( IsCyclic(G1) and Size(G1) = n/2 ) then return fail; fi; # G/G1 = {1*G1, t*G1, s*G1, t*s*G1} T := RightTransversal(G,G1); i := 1; @@ -979,29 +974,54 @@ InstallMethod( IsDihedralGroup, Zn := ClosureGroup(G1,T[i]); i := i + 1; until i > 4 or ( IsCyclic(Zn) and Size(Zn) = n ); - if not ( IsCyclic(Zn) and Size(Zn) = n ) then return false; fi; + if not ( IsCyclic(Zn) and Size(Zn) = n ) then return fail; fi; fi; # now Zn is normal in G and Zn = < s | s^n = 1 > # choose t in G\Zn and check dihedral structure repeat t := Random(G); until not t in Zn; if not (Order(t) = 2 and ForAll(GeneratorsOfGroup(Zn),s->t*s*t*s=s^0)) - then return false; fi; + then return fail; fi; # choose generator s of Zn repeat s := Random(Zn); until Order(s) = n; - SetDihedralGenerators(G,[t,s]); + return [t,s]; +end; + +InstallMethod( IsDihedralGroup, + "for a group", + true, + [ IsGroup and IsFinite ], 0, +function(G) + local gens; + + gens := DoComputeDihedralGenerators(G); + if gens = fail then + return false; + else + SetDihedralGenerators(G, gens); + fi; return true; - end ); +end); + +InstallMethod( DihedralGenerators, + "for a group", + [ IsGroup and IsFinite ], +function(G) + local gens; + + gens := DoComputeDihedralGenerators(G); + SetIsDihedralGroup(G, gens <> fail); + if gens = fail then + ErrorNoReturn("G is not a dihedral group"); + fi; + return gens; +end); ############################################################################# ## #M IsQuaternionGroup( ) . . . . . . . . . . . . . . . . . generic method ## -InstallMethod( IsQuaternionGroup, - "generic method", true, [ IsGroup ], 0, - - function ( G ) - +DoComputeGeneralisedQuaternionGenerators := function(G) local N, # size of G k, # ld(N) n, # N/2 @@ -1011,17 +1031,15 @@ InstallMethod( IsQuaternionGroup, t, s, # canonical generators of the quaternion group i; # counter - if not IsFinite(G) then TryNextMethod(); fi; - N := Size(G); k := LogInt(N,2); - if not( 2^k = N and k >= 3 ) then return false; fi; + if not( 2^k = N and k >= 3 ) then return fail; fi; n := N/2; # G = # ==> Comm(s, t) = s^-1 t s t = s^-2 ==> G' = < s^2 > G1 := DerivedSubgroup(G); - if not ( IsCyclic(G1) and Size(G1) = n/2 ) then return false; fi; + if not ( IsCyclic(G1) and Size(G1) = n/2 ) then return fail; fi; # find a normal subgroup of G of type Zn # G/G1 = {1*G1, t*G1, s*G1, t*s*G1} @@ -1031,20 +1049,49 @@ InstallMethod( IsQuaternionGroup, Zn := ClosureGroup(G1,T[i]); i := i + 1; until i > 4 or ( IsCyclic(Zn) and Size(Zn) = n ); - if not ( IsCyclic(Zn) and Size(Zn) = n ) then return false; fi; + if not ( IsCyclic(Zn) and Size(Zn) = n ) then return fail; fi; # now Zn is normal in G and Zn = < s | s^n = 1 > # choose t in G\Zn and check quaternion structure repeat t := Random(G); until not t in Zn; if not (Order(t) = 4 and ForAll(GeneratorsOfGroup(Zn), s->s^t*s = s^0)) - then return false; fi; + then return fail; fi; # choose generator s of Zn repeat s := Random(Zn); until Order(s) = n; - SetQuaternionGenerators(G,[t,s]); + return [t,s]; +end; + +InstallMethod( IsGeneralisedQuaternionGroup, + "for a group", + true, + [ IsGroup and IsFinite ], + 0, +function(G) + local gens; + + gens := DoComputeGeneralisedQuaternionGenerators(G); + if gens = fail then + return false; + else + SetGeneralisedQuaternionGenerators(G, gens); + fi; return true; - end ); +end); + +InstallMethod( GeneralisedQuaternionGenerators, + "for a group", + [ IsGroup and IsFinite ], +function(G) + local gens; + gens := DoComputeGeneralisedQuaternionGenerators(G); + SetIsGeneralisedQuaternionGroup(G, gens <> fail); + if gens = fail then + ErrorNoReturn("G is not a generalised quaternion group"); + fi; + return gens; +end); ############################################################################# ## #M IsQuasiDihedralGroup( ) . . . . . . . . . . . . . . . generic method diff --git a/tst/testinstall/grp/basic.tst b/tst/testinstall/grp/basic.tst index 0d6b7c2f17..dcaaac7724 100644 --- a/tst/testinstall/grp/basic.tst +++ b/tst/testinstall/grp/basic.tst @@ -225,57 +225,127 @@ Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 2nd choice method found for `DihedralGroupCons' on 2 arguments # -# quaternion groups +gap> Q := DihedralGroup(32);; +gap> gens := DihedralGenerators(Q);; +gap> Group(gens) = Q; +true +gap> Q := Group(GeneratorsOfGroup(DihedralGroup(IsPermGroup, 32)));; +gap> HasIsDihedralGroup(Q); +false +gap> HasDihedralGenerators(Q); +false +gap> gens := DihedralGenerators(Q);; +gap> Group(gens) = Q; +true +gap> IsDihedralGroup(Q); +true +gap> Q := Group(GeneratorsOfGroup(DihedralGroup(IsPermGroup, 32)));; +gap> HasIsDihedralGroup(Q); +false +gap> HasDihedralGenerators(Q); +false +gap> IsDihedralGroup(Q); +true +gap> HasDihedralGenerators(Q); +true +gap> Unbind(F);; Unbind(Q);; + +# +# dicyclic groups # -gap> IdGroup(QuaternionGroup(4)); +gap> IdGroup(DicyclicGroup(4)); [ 4, 1 ] -gap> IdGroup(QuaternionGroup(IsFpGroup,4)); +gap> IdGroup(DicyclicGroup(IsFpGroup,4)); [ 4, 1 ] -gap> QuaternionGroup(8); +gap> DicyclicGroup(8); -gap> QuaternionGroup(IsPcGroup,8); +gap> DicyclicGroup(IsPcGroup,8); -gap> QuaternionGroup(IsPermGroup,8); +gap> DicyclicGroup(IsPermGroup,8); Group([ (1,5,3,7)(2,8,4,6), (1,2,3,4)(5,6,7,8) ]) -gap> QuaternionGroup(IsFpGroup,8); +gap> DicyclicGroup(IsFpGroup,8); -gap> G:=QuaternionGroup(IsMatrixGroup, 8); +gap> G:=DicyclicGroup(IsMatrixGroup, 8); gap> FieldOfMatrixGroup(G); DimensionOfMatrixGroup(G); Rationals 4 -gap> G:=QuaternionGroup(IsMatrixGroup, GF(2), 8); +gap> G:=DicyclicGroup(IsMatrixGroup, GF(2), 8); gap> FieldOfMatrixGroup(G); DimensionOfMatrixGroup(G); GF(2) 8 -gap> G:=QuaternionGroup(IsMatrixGroup, GF(3), 8); +gap> G:=DicyclicGroup(IsMatrixGroup, GF(3), 8); gap> FieldOfMatrixGroup(G); DimensionOfMatrixGroup(G); GF(3) 4 gap> F:=FunctionField(GF(3),["t"]); FunctionField(...,[ t ]) -gap> G:=QuaternionGroup(IsMatrixGroup, F, 8); +gap> G:=DicyclicGroup(IsMatrixGroup, F, 8); gap> DimensionOfMatrixGroup(G); 4 # -gap> QuaternionGroup(2,3); -Error, usage: QuaternionGroup( [, ] ) -gap> QuaternionGroup(IsRing,3); -Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `QuaternionGroupCons' on 2 arguments -gap> QuaternionGroup(0); -Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `QuaternionGroupCons' on 2 arguments -gap> QuaternionGroup(1); -Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 2nd choice method found for `QuaternionGroupCons' on 2 arguments -gap> QuaternionGroup(IsFpGroup,1); -Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 2nd choice method found for `QuaternionGroupCons' on 2 arguments +gap> DicyclicGroup(2,3); +Error, usage: must be a filter +gap> DicyclicGroup(IsRing,3); +Error, usage: must be a positive integer divisible by 4 +gap> DicyclicGroup(0); +Error, usage: must be a positive integer divisible by 4 +gap> DicyclicGroup(1); +Error, usage: must be a positive integer divisible by 4 +gap> DicyclicGroup(IsFpGroup,1); +Error, usage: must be a positive integer divisible by 4 + +# +# (generalised) quaternion groups +# +gap> QuaternionGroup(4); +#I Warning: QuaternionGroup called with 4 which is less than 8 + +gap> QuaternionGroup(8); + +gap> QuaternionGroup(12); +#I Warning: QuaternionGroup called with 12 which is not a power of 2 + +gap> QuaternionGroup(11); +Error, usage: must be a positive integer divisible by 4 +gap> GeneralisedQuaternionGroup(16); + +gap> Q := GeneralisedQuaternionGroup(IsFpGroup, 32); + +gap> gens := GeneralisedQuaternionGenerators(Q);; +gap> Group(gens) = Q; +true +gap> GeneralisedQuaternionGroup(IsMatrixGroup, 32); + +gap> F:=FunctionField(GF(16),1);; +gap> Q:=GeneralisedQuaternionGroup(IsMatrixGroup, F, 256); + +gap> HasIsGeneralisedQuaternionGroup(Q); +true +gap> Q := Group(GeneratorsOfGroup(GeneralisedQuaternionGroup(IsPermGroup, 32)));; +gap> HasIsGeneralisedQuaternionGroup(Q); +false +gap> HasGeneralisedQuaternionGenerators(Q); +false +gap> gens := GeneralisedQuaternionGenerators(Q);; +gap> Group(gens) = Q; +true +gap> IsGeneralisedQuaternionGroup(Q); +true +gap> Q := Group(GeneratorsOfGroup(GeneralisedQuaternionGroup(IsPermGroup, 32)));; +gap> HasIsGeneralisedQuaternionGroup(Q); +false +gap> HasGeneralisedQuaternionGenerators(Q); +false +gap> IsGeneralisedQuaternionGroup(Q); +true +gap> HasGeneralisedQuaternionGenerators(Q); +true +gap> Unbind(F);; Unbind(Q);; # # elementary abelian groups