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

Add LowIndexNormalSubs operation #59

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
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.
37 changes: 37 additions & 0 deletions dev/tests_doc/processTests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/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)"

# get operating system
unameOut="$(uname -s)"
case "${unameOut}" in
Linux*) machine=Linux;;
Darwin*) machine=Mac;;
CYGWIN*) machine=Cygwin;;
MINGW*) machine=MinGw;;
*) machine="UNKNOWN:${unameOut}"
esac


# Post-processing for the extracted examples from the documentation.
# - Add a "\n" to all Print executions.
# - 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"
if [ "${machine}" == "Mac" ]; then
sed -i "" 's|Print(\(.*\));|Print(\1, \"\\n\");|g' $file
FriedrichRober marked this conversation as resolved.
Show resolved Hide resolved
elif [ "${machine}" == "Linux" ]; then
sed -i 's|Print(\(.*\));|Print(\1, \"\\n\");|g' $file
else
echo "ERROR: Unsupported operating system ${machine}"
exit 1
fi;
mv $file $test_dir/${file#"tst/"}
done
102 changes: 13 additions & 89 deletions doc/intro.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,45 +22,19 @@ 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> n := 50;;
gap> G := DihedralGroup(n);
FriedrichRober marked this conversation as resolved.
Show resolved Hide resolved
<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, n);;
gap> IsoTypes := List(L, H -> StructureDescription(H));
FriedrichRober marked this conversation as resolved.
Show resolved Hide resolved
[ "D50", "C25", "C5", "1" ]
]]></Example>

Expand All @@ -77,72 +51,22 @@ gap> d := 4;;
gap> C := CyclicGroup(5);;
gap> G := DirectProduct(ListWithIdenticalEntries(d, C));
FriedrichRober marked this conversation as resolved.
Show resolved Hide resolved
<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, H -> StructureDescription(H)));
FriedrichRober marked this conversation as resolved.
Show resolved Hide resolved
[ [ "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.
FriedrichRober marked this conversation as resolved.
Show resolved Hide resolved
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
125 changes: 124 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,126 @@ 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> n := 50;;
gap> G := DihedralGroup(n);
<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 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> p := 5;;
gap> d := 4;;
gap> C := CyclicGroup(5);;
gap> G := DirectProduct(ListWithIdenticalEntries(d, C));
FriedrichRober marked this conversation as resolved.
Show resolved Hide resolved
<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> pList := [3, 3, 4, 5];;
gap> G := DirectProduct(List(pList, p -> CyclicGroup(p)));
<pc group of size 180 with 5 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");
Loading