Skip to content

Commit

Permalink
Add LowIndexNormalSubs operation (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
FriedrichRober authored Dec 20, 2023
1 parent 8617b89 commit cba84e8
Show file tree
Hide file tree
Showing 12 changed files with 246 additions and 97 deletions.
1 change: 1 addition & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
GAPBRANCH: ${{ matrix.gap-branch }}
GAP_PKGS_TO_BUILD: "io profiling grape cohomolo"
- uses: gap-actions/build-pkg@v1
- uses: gap-actions/build-pkg-docs@v1
- uses: gap-actions/run-pkg-tests@v2
- uses: gap-actions/process-coverage@v2
- uses: codecov/codecov-action@v3
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@

/gh-pages/

_dev
_dev

/tst/files/doc/
9 changes: 9 additions & 0 deletions dev/tests_doc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Introduction
The files in this directory are used to post-process test files
that are extracted from the documentation examples.

# Main Files
- `processTests.sh` : processes all doc tests and moves them into `tst/files/doc`.

# Instructions
In order to post-process the tests and move them into `tst/files/doc` automatically, one needs to execute `processTests.sh` from any place.
17 changes: 17 additions & 0 deletions dev/tests_doc/processTests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

# go to root of repo
script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd $script_dir/../..
echo "Working in folder $(pwd)"

# Post-processing for the extracted examples from the documentation.
# - Move files into test_dir
test_dir="tst/files/doc"
mkdir -p $test_dir
files=($(ls -1 tst/lins*.tst))
echo "Found ${#files[@]} test file(s)"
for file in ${files[@]}; do
echo "Processing $file"
mv $file $test_dir/${file#"tst/"}
done
108 changes: 14 additions & 94 deletions doc/intro.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,45 +22,18 @@ The current implementation in ⪆ uses a table of groups that was computed by
<Heading>Examples</Heading>

In this section we present example sessions which demonstrate
how to use the search methods provided by &LINS;. <P/>
how to use the main high-level functions provided by &LINS;. <P/>

<Subsection>
<Heading>Example : all normal subgroups up to index <M>n</M></Heading>

We compute all normal subgroups in <M>D_{50}</M>,
the dihedral group of size <M>50</M>.
<Example><![CDATA[
gap> n := 50;
gap> G := DihedralGroup(n);
gap> G := DihedralGroup(50);
<pc group of size 50 with 3 generators>
]]></Example>

The search algorithm automatically translates the group into a finitely presented group
via a call to <C>IsomorphismFpGroup</C>. <Br/>
The isomorphism is stored inside the lins graph.
<Example><![CDATA[
gap> gr := LowIndexNormalSubgroupsSearchForAll(G, n);
<lins graph found 4 normal subgroups up to index 50>
gap> r := LinsRoot(gr);
<lins node of index 1>
gap> H := Grp(r);
<fp group of size 50 on the generators [ F1, F2, F3 ]>
gap> Iso := IsomorphismFpGroup(gr);
[ f1, f2, f3 ] -> [ F1, F2, F3 ]
gap> Source(Iso) = G;
true
gap> Range(Iso) = H;
true
]]></Example>

In order to get all nodes from the search graph, we need to use <C>List</C>.
As expected, the algorithm finds <M>D_{50}, C_{25}, C_5</M>
and the trivial group.
<Example><![CDATA[
gap> L := List(gr);
[ <lins node of index 1>, <lins node of index 2>, <lins node of index 10>,
<lins node of index 50> ]
gap> IsoTypes := List(L, node -> StructureDescription(Grp(node)));
gap> L := LowIndexNormalSubs(G, 50);;
gap> IsoTypes := List(L, StructureDescription);
[ "D50", "C25", "C5", "1" ]
]]></Example>

Expand All @@ -72,77 +45,24 @@ gap> IsoTypes := List(L, node -> StructureDescription(Grp(node)));
We compute all normal subgroups of index <M>5^2 = 25</M> in <M>C_5^4</M>,
the direct product of <M>4</M> copies of the cyclic group of order <M>5</M>:
<Example><![CDATA[
gap> p := 5;;
gap> d := 4;;
gap> C := CyclicGroup(5);;
gap> G := DirectProduct(ListWithIdenticalEntries(d, C));
gap> G := ElementaryAbelianGroup(5^4);
<pc group of size 625 with 4 generators>
]]></Example>

Again, the search algorithm automatically translates the group into a finitely presented group
via a call to <C>IsomorphismFpGroup</C>.
<Example><![CDATA[
gap> gr := LowIndexNormalSubgroupsSearchForIndex(G, 5 ^ 2, infinity);
<lins graph found 963 normal subgroups up to index 25>
]]></Example>

Now we are not interested in all normal subgroups that the search graph considered,
but only in those of index <M>25</M>. Thus we need to use <C>ComputedNormalSubgroups</C>.
For a prime <M>p</M>, and integers <M>d, s \in \mathbb{N}</M>,
the number of subgroups of order <M>p^s</M> of an elementary abelian <M>p</M>-group of order <M>p^d</M>
is exactly
<Alt Not="Text,HTML"><Display>
\frac
{\left(p^d - 1\right)\left(p^d - p\right) \cdots \left(p^d - p^{s-1}\right)}
{\left(p^s - 1\right)\left(p^s - p\right) \cdots \left(p^s - p^{s-1}\right)}\;.
</Display></Alt>
<Alt Only="Text,HTML"><Display Mode="M">
( (p^d - 1)(p^d - p) \cdots (p^d - p^{(s-1)}) ) / ( (p^s - 1)(p^s - p) \cdots (p^s - p^{(s-1)}) ) .
</Display></Alt>
Thus we expect to find
<Alt Not="Text,HTML"><M>\frac{(5^4-1) \cdot (5^4-5)}{(5^2 - 1) \cdot (5^2 - 5)} = 806</M></Alt>
<Alt Only="Text,HTML"><M>( (5^4-1) \cdot (5^4-5) ) / ( (5^2 - 1) \cdot (5^2 - 5) ) = 806</M></Alt>
normal subgroups of index <M>25</M>. <Br/>
Furthermore, all subgroups need to be of the isomorphism type <M>C_5^2</M>.
<Example><![CDATA[
gap> L := ComputedNormalSubgroups(gr);;
gap> Length(L);
806
gap> IsoTypes := DuplicateFreeList(List(L, node -> StructureDescription(Grp(node))));
[ "C5 x C5" ]
gap> L := LowIndexNormalSubs(G, 5 ^ 2 : allSubgroups := false);;
gap> IsoTypes := Collected(List(L, StructureDescription));
[ [ "C5 x C5", 806 ] ]
]]></Example>

</Subsection>

<Subsection>
<Heading>Example : a normal subgroup of index <M>n</M></Heading>
</Section>

We compute a normal subgroup of index <M>3 \cdot 5 = 15</M> in
<M>C_3 \times C_3 \times C_4 \times C_5</M>,
a direct product of cyclic groups:
<Example><![CDATA[
gap> pList := [3, 3, 4, 5];;
gap> G := DirectProduct(List(pList, p -> CyclicGroup(p)));
<pc group of size 60 with 4 generators>
]]></Example>
<Section Label="Main Functions">
<Heading>Main Functions</Heading>

Again, the search algorithm automatically translates the group into a finitely presented group
via a call to <C>IsomorphismFpGroup</C>.
<Example><![CDATA[
gap> gr := LowIndexNormalSubgroupsSearchForIndex(G, 15, 1);
<lins graph found 7 normal subgroups up to index 15>
]]></Example>
In this section, we include all the main high-level functions provided to the user.
For advanced search methods in the lattice of normal subgroups, take a look at Chapter <Ref Chap="LINS Interface"/>. <P/>

We use <C>ComputedNormalSubgroups</C> in order to get the normal subgroup of index <M>15</M>.
As expected, the algorithm finds a group of the isomorphism type <M>C_{12} = C_3 \times C_4</M>.
<Example><![CDATA[
gap> L := ComputedNormalSubgroups(gr);
[ <lins node of index 15> ]
gap> IsoTypes := List(L, node -> StructureDescription(Grp(node)));
[ "C12" ]
]]></Example>

</Subsection>
<#Include Label="LowIndexNormalSubs">

</Section>

Expand Down
120 changes: 119 additions & 1 deletion doc/lins_interface.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<Chapter Label="LINS Interface">
<Heading>LINS Interface</Heading>

This chapter explains the provided search methods
This chapter is intended for advanced users.
It explains the provided search methods
and the interface to the search graph structure <C>LinsGraph</C>.

<Section Label="LINS Graph">
Expand Down Expand Up @@ -80,4 +81,121 @@ Returns the index <M>[G : H]</M>.

</Section>

<Section Label="Advanced Examples">
<Heading>Examples</Heading>

In this section we present example sessions which demonstrate
how to use the advanced search methods provided by &LINS;.
For this we revise the examples from the introduction as well as include new ones. <P/>

<Subsection>
<Heading>Revised Example : all normal subgroups up to index <M>n</M></Heading>

We compute all normal subgroups in <M>D_{50}</M>,
the dihedral group of size <M>50</M>.
<Example><![CDATA[
gap> G := DihedralGroup(50);
<pc group of size 50 with 3 generators>
]]></Example>

The search algorithm automatically translates the group into a finitely presented group
via a call to <C>IsomorphismFpGroup</C>. <Br/>
The isomorphism is stored inside the lins graph.
<Example><![CDATA[
gap> gr := LowIndexNormalSubgroupsSearchForAll(G, 50);
<lins graph contains 4 normal subgroups up to index 50>
gap> r := LinsRoot(gr);
<lins node of index 1>
gap> H := Grp(r);
<fp group of size 50 on the generators [ F1, F2, F3 ]>
gap> Iso := IsomorphismFpGroup(gr);
[ f1, f2, f3 ] -> [ F1, F2, F3 ]
gap> Source(Iso) = G;
true
gap> Range(Iso) = H;
true
]]></Example>

In order to get all nodes from the search graph, we need to use <C>List</C>.
As expected, the algorithm finds <M>D_{50}, C_{25}, C_5</M>
and the trivial group.
<Example><![CDATA[
gap> L := List(gr);
[ <lins node of index 1>, <lins node of index 2>, <lins node of index 10>,
<lins node of index 50> ]
gap> IsoTypes := List(L, node -> StructureDescription(Grp(node)));
[ "D50", "C25", "C5", "1" ]
]]></Example>

</Subsection>

<Subsection>
<Heading>Revised Example : all normal subgroups of index <M>n</M></Heading>

We compute all normal subgroups of index <M>5^2 = 25</M> in <M>C_5^4</M>,
the direct product of <M>4</M> copies of the cyclic group of order <M>5</M>:
<Example><![CDATA[
gap> G := ElementaryAbelianGroup(5^4);
<pc group of size 625 with 4 generators>
]]></Example>

Again, the search algorithm automatically translates the group into a finitely presented group
via a call to <C>IsomorphismFpGroup</C>.
<Example><![CDATA[
gap> gr := LowIndexNormalSubgroupsSearchForIndex(G, 5 ^ 2, infinity);
<lins graph contains 963 normal subgroups up to index 25>
]]></Example>

Now we are not interested in all normal subgroups that the search graph considered,
but only in those of index <M>25</M>. Thus we need to use <C>ComputedNormalSubgroups</C>.
For a prime <M>p</M>, and integers <M>d, s \in \mathbb{N}</M>,
the number of subgroups of order <M>p^s</M> of an elementary abelian <M>p</M>-group of order <M>p^d</M>
is exactly
<Alt Not="Text,HTML"><Display>
\frac
{\left(p^d - 1\right)\left(p^d - p\right) \cdots \left(p^d - p^{s-1}\right)}
{\left(p^s - 1\right)\left(p^s - p\right) \cdots \left(p^s - p^{s-1}\right)}\;.
</Display></Alt>
<Alt Only="Text,HTML"><Display Mode="M">
( (p^d - 1)(p^d - p) \cdots (p^d - p^{(s-1)}) ) / ( (p^s - 1)(p^s - p) \cdots (p^s - p^{(s-1)}) ) .
</Display></Alt>
Thus we expect to find
<Alt Not="Text,HTML"><M>\frac{(5^4-1) \cdot (5^4-5)}{(5^2 - 1) \cdot (5^2 - 5)} = 806</M></Alt>
<Alt Only="Text,HTML"><M>( (5^4-1) \cdot (5^4-5) ) / ( (5^2 - 1) \cdot (5^2 - 5) ) = 806</M></Alt>
normal subgroups of index <M>25</M>. <Br/>
Furthermore, all subgroups need to be of the isomorphism type <M>C_5^2</M>.
<Example><![CDATA[
gap> L := ComputedNormalSubgroups(gr);;
gap> IsoTypes := Collected(List(L, node -> StructureDescription(Grp(node))));
[ [ "C5 x C5", 806 ] ]
]]></Example>

</Subsection>

<Subsection>
<Heading>Example : a normal subgroup of index <M>n</M></Heading>

We compute a normal subgroup of index <M>3 \cdot 5 = 15</M> in
<M>C_3 \times C_3 \times C_4 \times C_5</M>,
a direct product of cyclic groups:
<Example><![CDATA[
gap> G := AbelianGroup([3, 3, 4, 5]);
<pc group of size 180 with 4 generators>
gap> gr := LowIndexNormalSubgroupsSearchForIndex(G, 15, 1);
<lins graph contains 7 normal subgroups up to index 15>
]]></Example>

We use <C>ComputedNormalSubgroups</C> in order to get the normal subgroup of index <M>15</M>.
As expected, the algorithm finds a group of the isomorphism type <M>C_{12} = C_3 \times C_4</M>.
<Example><![CDATA[
gap> L := ComputedNormalSubgroups(gr);
[ <lins node of index 15> ]
gap> IsoTypes := List(L, node -> StructureDescription(Grp(node)));
[ "C12" ]
]]></Example>

</Subsection>

</Section>

</Chapter>
18 changes: 18 additions & 0 deletions gap/LINS.gd
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,24 @@ DeclareAttribute( "LinsOptions", IsLinsGraph, "mutable" );
## Main functions
#############################################################################

## <#GAPDoc Label="LowIndexNormalSubs">
## <ManSection>
## <Oper Name="LowIndexNormalSubs" Arg="G, n : allSubgroups := true"/>
## <Description>
## Returns a list of all normal subgroups of <A>G</A> with index at most <A>n</A>.
## If the option <A>allSubgroups</A> is set to <K>false</K>,
## then onlye the normal subgroups of <A>G</A> with index equal to <A>n</A> are returned. <P/>
##
## The generic method uses <Ref BookName="Reference" Attr="IsomorphismFpGroup"/> to transform <A>G</A> into an fp-group
## and then calls some variant of the low-level function <Ref Func="LowIndexNormalSubgroupsSearch"/>. <P/>
##
## Note that a similar operation <Ref BookName="polycyclic" Attr="LowIndexNormalSubgroups"/> exists in the package <Package>polycyclic</Package>.
## Due to technical incompabilities, those operations could not be unified. <P/>
## </Description>
## </ManSection>
## <#/GAPDoc>
DeclareOperation( "LowIndexNormalSubs", [IsGroup, IsPosInt] );

## <#GAPDoc Label="LowIndexNormalSubgroupsSearch">
## <ManSection>
## <Func Name="LowIndexNormalSubgroupsSearch" Arg="G, n[, opts]"/>
Expand Down
19 changes: 18 additions & 1 deletion gap/LINS.gi
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ end);

InstallMethod( ViewObj, "for Lins Graph Node", [IsLinsGraph],
function(gr)
Print("<lins graph found ", Length(List(gr)), " normal subgroups up to index ", IndexBound(gr), ">");
Print("<lins graph contains ", Length(List(gr)), " normal subgroups up to index ", IndexBound(gr), ">");
end);


Expand Down Expand Up @@ -464,3 +464,20 @@ end);
InstallGlobalFunction( LowIndexNormalSubgroupsSearchForAll, function(G, n)
return LowIndexNormalSubgroupsSearch(G, n);
end);

InstallMethod( LowIndexNormalSubs, "for groups",
[IsGroup, IsPosInt],
function(G, n)
local allSubgroups, gr, iso;
allSubgroups := ValueOption("allSubgroups");
if allSubgroups = fail then
allSubgroups := true;
fi;
if allSubgroups then
gr := LowIndexNormalSubgroupsSearchForAll(G, n);
else
gr := LowIndexNormalSubgroupsSearchForIndex(G, n, infinity);
fi;
iso := IsomorphismFpGroup(gr);
return List(ComputedNormalSubgroups(gr), rH -> PreImage(iso, Grp(rH)));
end);
3 changes: 3 additions & 0 deletions makedoc.g
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@ AutoDoc( rec( scaffold := rec(
"license.xml",
],
),
extract_examples := true,
autodoc := true ) );

Exec("dev/tests_doc/processTests.sh");
14 changes: 14 additions & 0 deletions tst/files/quick/Operation/DihedralGroup_20_10_Fp.tst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#############################################################################
# G = D_20
# index = 10
# fp-group
#############################################################################

gap> G := DihedralGroup(IsFpGroup, 20);
<fp group of size 20 on the generators [ r, s ]>
gap> L := LowIndexNormalSubs(G, 10);
[ <fp group of size 20 on the generators [ r, s ]>, Group([ r ]),
Group([ r^-2, s ]), Group([ r^-2, s*r^-1 ]), Group([ r^-2 ]),
Group([ r^5 ]) ]
gap> List(L, H -> Index(G, H));
[ 1, 2, 2, 2, 4, 10 ]
Loading

0 comments on commit cba84e8

Please sign in to comment.