diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index d93ae12..919f109 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -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 diff --git a/.gitignore b/.gitignore index 950d0ab..8bec6f5 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,6 @@ /gh-pages/ -_dev \ No newline at end of file +_dev + +/tst/files/doc/ diff --git a/dev/tests_doc/README.md b/dev/tests_doc/README.md new file mode 100644 index 0000000..056c6ef --- /dev/null +++ b/dev/tests_doc/README.md @@ -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. diff --git a/dev/tests_doc/processTests.sh b/dev/tests_doc/processTests.sh new file mode 100755 index 0000000..d15b82a --- /dev/null +++ b/dev/tests_doc/processTests.sh @@ -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 diff --git a/doc/intro.xml b/doc/intro.xml index 6b6633d..a171197 100644 --- a/doc/intro.xml +++ b/doc/intro.xml @@ -22,7 +22,7 @@ The current implementation in ⪆ uses a table of groups that was computed by Examples In this section we present example sessions which demonstrate -how to use the search methods provided by &LINS;.

+how to use the main high-level functions provided by &LINS;.

Example : all normal subgroups up to index n @@ -30,37 +30,10 @@ how to use the search methods provided by &LINS;.

We compute all normal subgroups in D_{50}, the dihedral group of size 50. n := 50; -gap> G := DihedralGroup(n); +gap> G := DihedralGroup(50); -]]> - -The search algorithm automatically translates the group into a finitely presented group -via a call to IsomorphismFpGroup.
-The isomorphism is stored inside the lins graph. - gr := LowIndexNormalSubgroupsSearchForAll(G, n); - -gap> r := LinsRoot(gr); - -gap> H := Grp(r); - -gap> Iso := IsomorphismFpGroup(gr); -[ f1, f2, f3 ] -> [ F1, F2, F3 ] -gap> Source(Iso) = G; -true -gap> Range(Iso) = H; -true -]]> - -In order to get all nodes from the search graph, we need to use List. -As expected, the algorithm finds D_{50}, C_{25}, C_5 -and the trivial group. - L := List(gr); -[ , , , - ] -gap> IsoTypes := List(L, node -> StructureDescription(Grp(node))); +gap> L := LowIndexNormalSubs(G, 50);; +gap> IsoTypes := List(L, StructureDescription); [ "D50", "C25", "C5", "1" ] ]]> @@ -72,77 +45,24 @@ gap> IsoTypes := List(L, node -> StructureDescription(Grp(node))); We compute all normal subgroups of index 5^2 = 25 in C_5^4, the direct product of 4 copies of the cyclic group of order 5: p := 5;; -gap> d := 4;; -gap> C := CyclicGroup(5);; -gap> G := DirectProduct(ListWithIdenticalEntries(d, C)); +gap> G := ElementaryAbelianGroup(5^4); -]]> - -Again, the search algorithm automatically translates the group into a finitely presented group -via a call to IsomorphismFpGroup. - gr := LowIndexNormalSubgroupsSearchForIndex(G, 5 ^ 2, infinity); - -]]> - -Now we are not interested in all normal subgroups that the search graph considered, -but only in those of index 25. Thus we need to use ComputedNormalSubgroups. -For a prime p, and integers d, s \in \mathbb{N}, -the number of subgroups of order p^s of an elementary abelian p-group of order p^d -is exactly - -\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)}\;. - - -( (p^d - 1)(p^d - p) \cdots (p^d - p^{(s-1)}) ) / ( (p^s - 1)(p^s - p) \cdots (p^s - p^{(s-1)}) ) . - -Thus we expect to find -\frac{(5^4-1) \cdot (5^4-5)}{(5^2 - 1) \cdot (5^2 - 5)} = 806 -( (5^4-1) \cdot (5^4-5) ) / ( (5^2 - 1) \cdot (5^2 - 5) ) = 806 -normal subgroups of index 25.
-Furthermore, all subgroups need to be of the isomorphism type C_5^2. - 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 : a normal subgroup of index n + -We compute a normal subgroup of index 3 \cdot 5 = 15 in -C_3 \times C_3 \times C_4 \times C_5, -a direct product of cyclic groups: - pList := [3, 3, 4, 5];; -gap> G := DirectProduct(List(pList, p -> CyclicGroup(p))); - -]]> +

+Main Functions -Again, the search algorithm automatically translates the group into a finitely presented group -via a call to IsomorphismFpGroup. - gr := LowIndexNormalSubgroupsSearchForIndex(G, 15, 1); - -]]> +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 .

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

diff --git a/doc/lins_interface.xml b/doc/lins_interface.xml index f41a6cd..c937438 100644 --- a/doc/lins_interface.xml +++ b/doc/lins_interface.xml @@ -1,7 +1,8 @@ LINS Interface -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 LinsGraph.
@@ -80,4 +81,121 @@ Returns the index [G : H].
+
+Examples + +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.

+ + +Revised Example : all normal subgroups up to index n + +We compute all normal subgroups in D_{50}, +the dihedral group of size 50. + G := DihedralGroup(50); + +]]> + +The search algorithm automatically translates the group into a finitely presented group +via a call to IsomorphismFpGroup.
+The isomorphism is stored inside the lins graph. + gr := LowIndexNormalSubgroupsSearchForAll(G, 50); + +gap> r := LinsRoot(gr); + +gap> H := Grp(r); + +gap> Iso := IsomorphismFpGroup(gr); +[ f1, f2, f3 ] -> [ F1, F2, F3 ] +gap> Source(Iso) = G; +true +gap> Range(Iso) = H; +true +]]> + +In order to get all nodes from the search graph, we need to use List. +As expected, the algorithm finds D_{50}, C_{25}, C_5 +and the trivial group. + L := List(gr); +[ , , , + ] +gap> IsoTypes := List(L, node -> StructureDescription(Grp(node))); +[ "D50", "C25", "C5", "1" ] +]]> + +
+ + +Revised Example : all normal subgroups of index n + +We compute all normal subgroups of index 5^2 = 25 in C_5^4, +the direct product of 4 copies of the cyclic group of order 5: + G := ElementaryAbelianGroup(5^4); + +]]> + +Again, the search algorithm automatically translates the group into a finitely presented group +via a call to IsomorphismFpGroup. + gr := LowIndexNormalSubgroupsSearchForIndex(G, 5 ^ 2, infinity); + +]]> + +Now we are not interested in all normal subgroups that the search graph considered, +but only in those of index 25. Thus we need to use ComputedNormalSubgroups. +For a prime p, and integers d, s \in \mathbb{N}, +the number of subgroups of order p^s of an elementary abelian p-group of order p^d +is exactly + +\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)}\;. + + +( (p^d - 1)(p^d - p) \cdots (p^d - p^{(s-1)}) ) / ( (p^s - 1)(p^s - p) \cdots (p^s - p^{(s-1)}) ) . + +Thus we expect to find +\frac{(5^4-1) \cdot (5^4-5)}{(5^2 - 1) \cdot (5^2 - 5)} = 806 +( (5^4-1) \cdot (5^4-5) ) / ( (5^2 - 1) \cdot (5^2 - 5) ) = 806 +normal subgroups of index 25.
+Furthermore, all subgroups need to be of the isomorphism type C_5^2. + L := ComputedNormalSubgroups(gr);; +gap> IsoTypes := Collected(List(L, node -> StructureDescription(Grp(node)))); +[ [ "C5 x C5", 806 ] ] +]]> + +
+ + +Example : a normal subgroup of index n + +We compute a normal subgroup of index 3 \cdot 5 = 15 in +C_3 \times C_3 \times C_4 \times C_5, +a direct product of cyclic groups: + G := AbelianGroup([3, 3, 4, 5]); + +gap> gr := LowIndexNormalSubgroupsSearchForIndex(G, 15, 1); + +]]> + +We use ComputedNormalSubgroups in order to get the normal subgroup of index 15. +As expected, the algorithm finds a group of the isomorphism type C_{12} = C_3 \times C_4. + L := ComputedNormalSubgroups(gr); +[ ] +gap> IsoTypes := List(L, node -> StructureDescription(Grp(node))); +[ "C12" ] +]]> + + + +

+
diff --git a/gap/LINS.gd b/gap/LINS.gd index 6df2e00..6f510a1 100644 --- a/gap/LINS.gd +++ b/gap/LINS.gd @@ -175,6 +175,24 @@ DeclareAttribute( "LinsOptions", IsLinsGraph, "mutable" ); ## Main functions ############################################################################# +## <#GAPDoc Label="LowIndexNormalSubs"> +## +## +## +## Returns a list of all normal subgroups of G with index at most n. +## If the option allSubgroups is set to false, +## then onlye the normal subgroups of G with index equal to n are returned.

+## +## The generic method uses to transform G into an fp-group +## and then calls some variant of the low-level function .

+## +## Note that a similar operation exists in the package polycyclic. +## Due to technical incompabilities, those operations could not be unified.

+## +## +## <#/GAPDoc> +DeclareOperation( "LowIndexNormalSubs", [IsGroup, IsPosInt] ); + ## <#GAPDoc Label="LowIndexNormalSubgroupsSearch"> ## ## diff --git a/gap/LINS.gi b/gap/LINS.gi index f5e9ad2..6aaf9e2 100644 --- a/gap/LINS.gi +++ b/gap/LINS.gi @@ -142,7 +142,7 @@ end); InstallMethod( ViewObj, "for Lins Graph Node", [IsLinsGraph], function(gr) - Print(""); + Print(""); end); @@ -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); diff --git a/makedoc.g b/makedoc.g index 4588a7c..fe4d4bb 100644 --- a/makedoc.g +++ b/makedoc.g @@ -25,4 +25,7 @@ AutoDoc( rec( scaffold := rec( "license.xml", ], ), + extract_examples := true, autodoc := true ) ); + +Exec("dev/tests_doc/processTests.sh"); diff --git a/tst/files/quick/Operation/DihedralGroup_20_10_Fp.tst b/tst/files/quick/Operation/DihedralGroup_20_10_Fp.tst new file mode 100644 index 0000000..b9887fe --- /dev/null +++ b/tst/files/quick/Operation/DihedralGroup_20_10_Fp.tst @@ -0,0 +1,14 @@ +############################################################################# +# G = D_20 +# index = 10 +# fp-group +############################################################################# + +gap> G := DihedralGroup(IsFpGroup, 20); + +gap> L := LowIndexNormalSubs(G, 10); +[ , 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 ] diff --git a/tst/files/quick/Operation/DihedralGroup_20_10_Pc.tst b/tst/files/quick/Operation/DihedralGroup_20_10_Pc.tst new file mode 100644 index 0000000..54fa9ad --- /dev/null +++ b/tst/files/quick/Operation/DihedralGroup_20_10_Pc.tst @@ -0,0 +1,14 @@ +############################################################################# +# G = D_20 +# index = 10 +# pc-group +############################################################################# + +gap> G := DihedralGroup(20); + +gap> L := LowIndexNormalSubs(G, 10); +[ Group([ f1, f2, f3 ]), Group([ f1, f3^4 ]), Group([ f2 ]), + Group([ f1*f2*f3^4, f1*f2 ]), Group([ f3^4 ]), + Group([ of ..., f2*f3^2 ]) ] +gap> List(L, H -> Index(G, H)); +[ 1, 2, 2, 2, 4, 10 ] diff --git a/tst/files/quick/Operation/DihedralGroup_20_10_Perm.tst b/tst/files/quick/Operation/DihedralGroup_20_10_Perm.tst new file mode 100644 index 0000000..95d0321 --- /dev/null +++ b/tst/files/quick/Operation/DihedralGroup_20_10_Perm.tst @@ -0,0 +1,16 @@ +############################################################################# +# G = D_20 +# index = 10 +# perm-group +############################################################################# + +gap> G := DihedralGroup(IsPermGroup, 20); +Group([ (1,2,3,4,5,6,7,8,9,10), (2,10)(3,9)(4,8)(5,7) ]) +gap> L := LowIndexNormalSubs(G, 10); +[ Group([ (2,10)(3,9)(4,8)(5,7), (1,6)(2,7)(3,8)(4,9)(5,10), (1,7,3,9,5) + (2,8,4,10,6) ]), Group([ (2,10)(3,9)(4,8)(5,7), (1,7,3,9,5)(2,8,4,10,6) + ]), Group([ (1,6)(2,7)(3,8)(4,9)(5,10), (1,7,3,9,5)(2,8,4,10,6) ]), + Group([ (1,6)(2,5)(3,4)(7,10)(8,9), (1,7,3,9,5)(2,8,4,10,6) ]), + Group([ (1,7,3,9,5)(2,8,4,10,6) ]), Group([ (1,6)(2,7)(3,8)(4,9)(5,10) ]) ] +gap> List(L, H -> Index(G, H)); +[ 1, 2, 2, 2, 4, 10 ]