Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance some nilpotent and p-group attributes #442

Merged
merged 5 commits into from
Jan 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/gprd.gi
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ end );
#M IsNilpotentGroup( <D> )
##
InstallMethod( IsNilpotentGroup, "for direct products",
[IsGroup and HasDirectProductInfo],
[IsGroup and HasDirectProductInfo], 30,
function( D )
return ForAll( DirectProductInfo( D ).groups, IsNilpotentGroup );
end );
Expand Down
152 changes: 92 additions & 60 deletions lib/grp.gi
Original file line number Diff line number Diff line change
Expand Up @@ -156,53 +156,72 @@ InstallMethod( IsElementaryAbelian,
##
#M IsPGroup( <G> ) . . . . . . . . . . . . . . . . . is a group a p-group ?
##
InstallMethod( IsPGroup,
"generic method (check order of the group or of generators)",
[ IsGroup ],
BindGlobal( "IS_PGROUP_FOR_NILPOTENT",

function( G )
local s, gen, ord;

# We inspect orders of group generators if the group order is not yet
# known *and* the group knows to be nilpotent or is abelian;
# thus an `IsAbelian' test may be forced (which can be done via comparing
# products of generators) but *not* an `IsNilpotent' test.
if ( not HasSize( G ) )
and ( ( HasIsNilpotentGroup( G ) and IsNilpotentGroup( G ) )
or IsAbelian( G ) ) then

s:= [];
for gen in GeneratorsOfGroup( G ) do
ord:= Order( gen );
if ord = infinity then
s:= [];
for gen in GeneratorsOfGroup( G ) do
ord:= Order( gen );
if ord = infinity then
return false;
elif 1 < ord then
if not IsPrimePowerInt( ord ) then
return false;
elif 1 < ord then
UniteSet( s, Factors( ord ) );
else
AddSet( s, Factors( ord )[1] );
if 1 < Length( s ) then
return false;
fi;
fi;
od;
if IsEmpty( s ) then
return true;
fi;
od;
if IsEmpty( s ) then
return true;
fi;

else
SetPrimePGroup( G, s[1] );
return true;
end);

s:= Size( G );
if s = 1 then
return true;
elif s = infinity then
return false;
fi;
s:= Set( Factors( s ) );
if 1 < Length( s ) then
return false;
fi;
BindGlobal( "IS_PGROUP_FROM_SIZE",

function( G )
local s;

s:= Size( G );
if s = 1 then
return true;
elif s = infinity then
return false;
elif not IsPrimePowerInt( s ) then
return false;
else
s:= Factors( s );
fi;

SetPrimePGroup( G, s[1] );
return true;
end);

InstallMethod( IsPGroup,
"generic method (check order of the group or of generators if nilpotent)",
[ IsGroup ],
function( G )
local s, gen, ord;

# We inspect orders of group generators if the group order is not yet
# known *and* the group knows to be nilpotent or is abelian;
# thus an `IsAbelian' test may be forced (which can be done via comparing
# products of generators) but *not* an `IsNilpotent' test.
if ( not HasSize( G ) )
and ( ( HasIsNilpotentGroup( G ) and IsNilpotentGroup( G ) )
or IsAbelian( G ) ) then
return IS_PGROUP_FOR_NILPOTENT( G );
else
return IS_PGROUP_FROM_SIZE( G );
fi;
end );

InstallMethod( IsPGroup,
Expand All @@ -212,43 +231,34 @@ InstallMethod( IsPGroup,
local s, gen, ord;

if HasSize( G ) then
s:= Size( G );
if s = 1 then
return true;
elif s = infinity then
return false;
fi;
s:= Set( Factors( s ) );
if 1 < Length( s ) then
return false;
fi;
return IS_PGROUP_FROM_SIZE( G );
else
s:= [];
for gen in GeneratorsOfGroup( G ) do
ord:= Order( gen );
if ord = infinity then
return false;
elif 1 < ord then
UniteSet( s, Factors( ord ) );
if 1 < Length( s ) then
return false;
fi;
fi;
od;
if IsEmpty( s ) then
return true;
fi;
return IS_PGROUP_FOR_NILPOTENT( G );
fi;

SetPrimePGroup( G, s[1] );
return true;
end );


#############################################################################
##
#M PrimePGroup . . . . . . . . . . . . . . . . . . . . . prime of a p-group
##
InstallMethod( PrimePGroup,
"generic method, check the order of a nontrivial generator",
[ IsPGroup and HasGeneratorsOfGroup ],
function( G )
local gen, s;
if IsTrivial( G ) then
return fail;
fi;
for gen in GeneratorsOfGroup( G ) do
s := Order( gen );
if s <> 1 then
break;
fi;
od;
return Factors( s )[1];
end );

InstallMethod( PrimePGroup,
"generic method, check the group order",
[ IsPGroup ],
Expand All @@ -263,9 +273,13 @@ local s;
if s = 1 then
return fail;
fi;
return Set( Factors( s ) )[1];
return Factors( s )[1];
end );

RedispatchOnCondition (PrimePGroup, true,
[IsGroup],
[IsPGroup], 0);


#############################################################################
##
Expand All @@ -284,6 +298,24 @@ end );
#T (Can we install a more restrictive method that *is* immediate,
#T for example one that checks only small integers?)

InstallMethod( IsNilpotentGroup,
"if group size can be computed and is a prime power",
[ IsGroup and CanComputeSize ], 25,
function ( G )
local s;

s := Size ( G );
if IsInt( s ) and IsPrimePowerInt( s ) then
SetIsPGroup( G, true );
SetPrimePGroup( G, Factors( s )[1] );
return true;
else
SetIsPGroup( G, false );
fi;
TryNextMethod();
end );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am somewhat wary of this method. Being able to compute the size is not the same as being able to do so "quickly" or "easily" (as in CanEasilyComputePcgs). So this could lead to unexpected slow downs.

But perhaps I am just too careful here... The true problem, in any case, is that with all these automatic deductions, the system becomes very hard to predict; seemingly innocent changes can cause major changes in behaviour, both good and bad ones sigh.

So, I am not opposed to that change, just... wary... :/ But probably we should just ignore me in that regard!



InstallMethod( IsNilpotentGroup,
"generic method for groups",
[ IsGroup ],
Expand Down
171 changes: 171 additions & 0 deletions tst/testinstall/pgroups.tst
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
gap> START_TEST("pgroups.tst");
gap> A := Group((1,2),(3,4),(5,6));
Group([ (1,2), (3,4), (5,6) ])
gap> G := DirectProduct(A, A);
Group([ (1,2), (3,4), (5,6), (7,8), (9,10), (11,12) ])
gap> IsPGroup(G);
true
gap> HasPrimePGroup(A) and HasPrimePGroup(G);
true
gap> PrimePGroup(A);
2
gap> PrimePGroup(G);
2
gap> B := Group((1,2,3),(4,5,6));
Group([ (1,2,3), (4,5,6) ])
gap> IsAbelian(B);
true
gap> G := DirectProduct(B, B);
Group([ (1,2,3), (4,5,6), (7,8,9), (10,11,12) ])
gap> IsPGroup(G);
true
gap> HasPrimePGroup(G);
true
gap> PrimePGroup(G);
3
gap> C := Group((1,2,3,4),(5,6,7,8));
Group([ (1,2,3,4), (5,6,7,8) ])
gap> IsAbelian(C);
true
gap> G := DirectProduct(C, C);
Group([ (1,2,3,4), (5,6,7,8), (9,10,11,12), (13,14,15,16) ])
gap> Size(G);
256
gap> IsPGroup(G);
true
gap> HasPrimePGroup(G);
true
gap> PrimePGroup(G);
2
gap> D := Group((1,3),(1,2,3,4));
Group([ (1,3), (1,2,3,4) ])
gap> G := DirectProduct(D, D);
Group([ (1,3), (1,2,3,4), (5,7), (5,6,7,8) ])
gap> IsPGroup(G);
true
gap> HasPrimePGroup(D) and HasPrimePGroup(G);
true
gap> PrimePGroup(D);
2
gap> PrimePGroup(G);
2
gap> Q := Group( (1,2,3,8)(4,5,6,7), (1,7,3,5)(2,6,8,4) );
Group([ (1,2,3,8)(4,5,6,7), (1,7,3,5)(2,6,8,4) ])
gap> SetIsPGroup(Q,true);
gap> PrimePGroup(Q);
2
gap> G := DihedralGroup(IsFpGroup, 8);
<fp group of size 8 on the generators [ r, s ]>
gap> IsPGroup(G);
true
gap> H := CyclicGroup(IsFpGroup, 2);
<fp group of size 2 on the generators [ a ]>
gap> hom := GroupHomomorphismByImages(G, H, [G.1, G.2], [H.1, One(H)]);
[ r, s ] -> [ a, <identity ...> ]
gap> K := Kernel(hom);
Group(<fp, no generators known>)
gap> SetIsPGroup(K, true);
gap> PrimePGroup(K);
2
gap> IsPGroup(TrivialGroup());
true
gap> PrimePGroup(TrivialGroup());
fail
gap> IsPGroup(AbelianGroup([2, 4, 8, 16]));
true
gap> IsPGroup(AbelianGroup([2, 4, 8, 18]));
false
gap> H1 := Group((1,2)(3,4),(1,2,3));
Group([ (1,2)(3,4), (1,2,3) ])
gap> IsPGroup(H1);
false
gap> H2 := Group((1,2),(3,4,5));
Group([ (1,2), (3,4,5) ])
gap> IsPGroup(H2);
false
gap> H3 := Group((1,2),(3,4,5));
Group([ (1,2), (3,4,5) ])
gap> IsAbelian(H3);
true
gap> IsPGroup(H3);
false
gap> H4 := Group((1,2),(3,4,5));
Group([ (1,2), (3,4,5) ])
gap> IsAbelian(H4);
true
gap> Size(H4);
6
gap> IsPGroup(H4);
false
gap> K := Group((1,3),(1,2,3,4),(5,6,7));
Group([ (1,3), (1,2,3,4), (5,6,7) ])
gap> IsNilpotentGroup(K);
true
gap> HasIsPGroup(K);
true
gap> IsPGroup(K);
false
gap> L := Group((2,4), (1,2,3,4));
Group([ (2,4), (1,2,3,4) ])
gap> IsNilpotentGroup(L);
true
gap> HasIsPGroup(L) and HasPrimePGroup(L);
true
gap> IsPGroup(L);
true
gap> PrimePGroup(L);
2
gap> F := FreeGroup("r","s");
<free group on the generators [ r, s ]>
gap> r := F.1; s := F.2;
r
s
gap> G := F/[ r^4, s^2, s*r*s*r ];
<fp group on the generators [ r, s ]>
gap> IsNilpotentGroup(G);
true
gap> G := F/[ r^3, s^2, r*s*r*s ];
<fp group on the generators [ r, s ]>
gap> IsNilpotentGroup(G);
false
gap> ForAll(List([1..11], i -> TransitiveGroup(8,i)), IsPGroup);
true
gap> IsPGroup(TransitiveGroup(8, 12));
false
gap> IsNilpotentGroup(TransitiveGroup(8, 12));
false
gap> IsPGroup(AlternatingGroup(3));
true
gap> IsPGroup(AlternatingGroup(4));
false
gap> IsPGroup(SymmetricGroup(3));
false
gap> G := SymmetricGroup(8);
Sym( [ 1 .. 8 ] )
gap> s := Size(G);
40320
gap> IsPGroup(G);
false
gap> IsNilpotentGroup(G);
false
gap> ForAll(PrimeDivisors(s), p -> HasIsPGroup(SylowSubgroup(G, p)));
true
gap> ForAll(PrimeDivisors(s), p -> HasPrimePGroup(SylowSubgroup(G, p)));
true
gap> ForAll(PrimeDivisors(s), p -> p=PrimePGroup(SylowSubgroup(G, p)));
true
gap> G := DihedralGroup(Factorial(8));
<pc group of size 40320 with 11 generators>
gap> IsPGroup(G);
false
gap> IsNilpotentGroup(G);
false
gap> s := Size(G);
40320
gap> ForAll(PrimeDivisors(s), p -> HasIsPGroup(SylowSubgroup(G, p)));
true
gap> ForAll(PrimeDivisors(s), p -> HasPrimePGroup(SylowSubgroup(G, p)));
true
gap> ForAll(PrimeDivisors(s), p -> p=PrimePGroup(SylowSubgroup(G, p)));
true
gap> STOP_TEST("pgroups.tst", 10000);