A subgroup $H$ of $G$ is said to be pronormal in $G$ if for each $g \in G$, there exists $x\in \langle H, H^g \rangle$ such that $H^x = H^g$.
A test for pronormality of a subgroup is given by the following GAP code:
IsPronormal := function(G,H)
return(ForAll(Set(G),g->IsConjugate(Group(Union(H,H^g)),H,H^g)));
end;;
Now for a non-pronormal subgroup $H$, I want to explicitly find its pronormaliser in the group $G$, that is the set of all $g\in G$ such that $H$ and $H^g$ are conjugate in $\langle H, H^g \rangle$. How do I use GAP to list these elements?
I will start with the code review, examining
IsPronormalfunction given in the question.The initial version indeed does what's written on the box. It precisely matches the given definition. This is a good starting point following the paradigm "Make it right, then make it fast".
I would only reformat it differently - there is no need to make such redundant indentation, and also
returnis a keyword and not a function, so there is no need to use in parentheses inreturn(...):(just to make it clear, GAP is not sensitive to indentation, and individual formatting preferences may vary, but it's good to use consistent style - for example, following the style used in the GAP library).
Let's now create some group, for example $S_6$:
This is a list of representatives of conjugacy classes of its subgroups:
Now we will check for each subgroup whether it is pronormal in $S_6$. It takes almost a minute:
The first improvement is by replacing
Set(G)byG. GAP "knows" how to enumerate all elements of this group, so there is no need to create a set of its elements. Not only that it takes some time, but also GAP may run out of memory for large groups, while it can be perfectly capable of enumerating their elements one by one:This helps a little bit with performance. Also, the new result matches the old one:
The next step is to look at
Group( Union(H,H^g) ). This generates a new group taking a set-theoretic union of all elements ofHandH^gas generators. This list of generators is redundant (indeed, the answer to this question uses generators of groups, not their lists of elements).Now we are getting same results almost twice faster:
There is another redundant calculation here:
H^gis computed twice. We need to rewrite the function as follows to avoid this:Caching
H^ginKhelps to bring down the runtime just under half a minute:Further steps:
whether we need to check the condition for all elements $g \in G$. For example, one can exclude all central elements $g$ (will not help in the case of the symmetric group, but useful in general case)
obviously, we do not have to check the condition for $g \in H$
can we instead of iterating over all $g \in G$ check only representatives of conjugacy classes of elements of $G$? This seems not to be the case here, but this is useful advice to keep in mind for the future.
Now to compute pronormaliser, one could start with the following prototype (basically, replace
ForAllbyFilteredin one of the versions ofIsPronormalabove):For a given $G$ and $H$, it returns a list of all elements $g\in G$ such that $H$ and $H^g$ are conjugate in $\langle H, H^g \rangle$. It may then be improved following the same approach as above.
Remark: I've used some crude approach to testing to check that each new version of the code returns the same result as previous ones. There is a better way to automate testing - please see "Using regression tests" in the Software Carpentry lesson on GAP for further details.