-
Notifications
You must be signed in to change notification settings - Fork 161
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 IsAbelian filters to IsSolvableGroup and DerivedSeries #706
Conversation
Ok, this is really embarassing. My current modifications apparently recovered a bug in somewhere in my own previous code for As far as I can see, the main change is in method selection for Is there any way I can use profiling to have a file with all the commands run in the order they are actually called? |
Ok, so after #708 is merged, tests should not fail anymore. |
Why do we again have a multitude of immediate methods put in here? Yes, they all look harmless, but I don't see them achieving much either and they contribute minuscule to the runtime of all other code. |
@hulpke I felt that you put in your checks for |
@hungaborhorvath
|
@hulpke Very well, I removed all three immediate methods and then rewrote the checks in I am also wondering about the following example:
Calling |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All in all, I think this is a worthwhile contribution (and I am sorry it's been neglected since April sigh).
@hungaborhorvath I could totally understand if you are fed up by the delays and constant nitpicking :-/. But in case you are still with us (yay!!), perhaps you are interested in replying to my comments, and/or just rebasing your work on the latest master branch (that way, the code coverage test gets run, which will tell us if your tests fully exercise the new code).
Thankt you once more for your contributions and patience!
InstallMethod( IsPerfectGroup, "for groups having abelian invariants", | ||
[ IsGroup and HasAbelianInvariants ], | ||
grp -> Length( AbelianInvariants( grp ) ) = 0 ); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a clear win to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is not currently covered by the tests.
Indeed, I just looked into it and noticed that there is an almost identical method being installed for groups in the filter IsSubgroupFpGroup
in grpf.gi, line 910.
The difference if of course that this method gets invoked even if they are not yet computed.
Which leaves me wondering how to create a group for which this method gets triggered...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fingolfin Ok, so we need a group that is not created as a subgroup of an fp-group, does not know if it is finite but does know its abelian invariants. Perhaps some PSL group constructed by generators over some infinite field? I am not sure how to do that in GAP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fingolfin I did some poking around in the library. As far as I can tell, currently AbelianInvariants
can only be computed for (subgroups of) fp-groups or for all groups, but then an IsFinite
check is immediately forced. (Or it can be computed for Pcp-groups, but that uses the polycyclic package.) So currently I do not see a way to define a group for which we can compute AbelianInvariants
and this line would run before any other for IsPerfectGroup
.
Assert(2, not IsAbelian(G)); | ||
SetIsAbelian(G, false); | ||
return false; | ||
fi; | ||
end ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems correct and fine, but I found it a bit hard to read and verify. How about something like this instead?
isSolvable := IsTrivial( S[ Length( S ) ] );
isAbelian := isSolvable and Length( S ) <= 2;
Assert(2, IsAbelian(G) = isAbelian);
SetIsAbelian(G, isAbelian);
return isSolvable;
I find that a lot easier to understand and verify, and it reduces code duplication.
Assert(2, not IsAbelian(G)); | ||
SetIsAbelian(G, false); | ||
fi; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about simplifying this chunk similar to what I proposed for IsSolvableGroup
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not entirely the same, because here we do not want to force an IsAbelian or IsSolvable check. The only simplification I see now (it is late, though....) is to use IsAttributeKnownAndEqualTo
.
(HasIsPerfectGroup(S[Length(S)]) and not IsPerfectGroup(S[Length(S)])) | ||
or (HasAbelianInvariants(S[Length(S)]) | ||
and Length(AbelianInvariants(S[Length(S)])) > 0) | ||
) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh, this makes my head hurt... :). But it seems valid, and the code it replaces is not nicer, so no fundamental objection. Simplifying that doesn't seem easy... Hmmm
Perhaps we should add some functions like these:
IsAttributeKnownAndEqualTo := function(obj, attribute, value)
return Tester(attribute)(obj) and attribute(obj) = value;
end;
IsKnownToBeTrivial := obj -> IsAttributeKnownAndEqualTo(obj, IsTrivial, true);
Then the code here could be changed to this (I made another change to avoid writing S[Length(S)]
all the time; I didn't check this code, so I might have messed that up. But I hope my intent is clear):
S :=[];
D := G;
while not IsKnownToBeTrivial(D) and
not IsAttributeKnownAndEqualTo(D, IsPerfectGroup, true) and
not IsAttributeKnownAndEqualTo(D, AbelianInvariants, [] do
Add( S, D );
Info( InfoGroup, 2, "DerivedSeriesOfGroup: step ", Length(S) );
D := DerivedSubgroup( D );
od;
Add( S, D );
I think there are other places in the GAP library which would become more readable with IsAttributeKnownAndEqualTo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is one thing I wonder about, though: What if the group D
(resp. S[Length(S)]
does not "know" it is trivial, but actually is trivial... don't we then end up with a list S
which contains two copies of the trivial group at the end? Same for the group being perfect...
(This is pertinent to all variants of the code: the current one, hungaborhorvath's version, and my proposed variant...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fingolfin
Should not IsAttributeKnownAndEqualTo
, and similarly IsKnownToBeTrivial
, go to some other file, like oper1.gi? Anyway, this seems like more than what this PR is for. I do not mind to wait with this PR until such functions are available, but such a useful function would be lost in this PR which is about something else.
BTW, your code really is not entirely the same as the original, but I get the idea. In any case, the code runs fine for e.g. Group((1,2,3),(3,4,5))
, and the key is the D <> S[ Length(S) ])
part of the code.
gap> G := F/[ a^2, b^2, c^2, d^2, (a*b)^3, (b*c)^3, (c*d)^3, (a*c)^2, (a*d)^2, (b*d)^2 ];; | ||
gap> not IsSolvable(G) and HasIsAbelian(G) and not IsAbelian(G); | ||
true | ||
gap> STOP_TEST("IsSolvableGroup.tst", 10000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests, yay!!!
One of the commits also has a typo in the commit message ("fo" instead of "for") |
@hungaborhorvath ping, could you please rebase this PR, too? |
@fingolfin Yes, I will rebase it and make the changes you suggested. However, these are actual code changes, so I would like to take some time to make sure to get them right. |
c4161c4
to
60e55b7
Compare
@fingolfin I have rebased this, and also did one of the simplifications. As to the other, I am not sure that should be included in this PR or in a separate one. |
Current coverage is 48.72% (diff: 96.00%)@@ master #706 diff @@
==========================================
Files 424 424
Lines 222120 222141 +21
Methods 3429 3429
Messages 0 0
Branches 0 0
==========================================
- Hits 108343 108235 -108
- Misses 113777 113906 +129
Partials 0 0
|
|
||
# set IsAbelian filter | ||
isAbelian := isSolvable and Length( S ) <= 2; | ||
Assert(2, IsAbelian(G) = isAbelian); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point of this assert? It adds several seconds to your tests, as tests are run at assertion level 2 right now.
I'd either remove it, or increase the level to 3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not know about the assertion level being increased for tests, thank you. Increased it to 3. There are several other places in grp.gi where I think very similar lines exist with assertion level 2.
true | ||
gap> F := FreeGroup("r", "s");; r := F.1;; s := F.2;; | ||
gap> G := F/[s^2, s*r*s*r];; | ||
gap> IsSolvable(G) and HasIsAbelian(G) and not IsAbelian(G); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line of the test, and the three similar ones following below, seem not quite right to me: they implicitly assume that IsSolvable
is computed in one specific way (namely by computing the derived series). But at least hypothetically, I could come up with a much better way to compute solvability of fp-groups, say by only inspecting the relators. If that "superior" method was added to GAP, this test might suddenly fail, in case my method does not detect abelianess.
So, wouldn't it be better to explicitly call DerivedSeriesOfGroup(G)
beforehand, as what we really are testing here is that computing the derived series automatically detects both solvability and abelianess...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right that if a new method comes, then these tests may fail. However, after I checked the examples, I am now pretty confident that I wanted to check whether the method in this PR adds the appropriate IsSolvable
and IsAbelian
flags. The DerivedSeriesOfGroup
should not (and does not) add most of these flags, mainly because it stops due to empty AbelianInvariants
, instead of knowing that the last entry is trivial.
I would rather prefer to write a comment into the test file about these examples explaining this situation. But of course if you still prefer otherwise, I can run DerivedSeriesOfGroup
first, and then check for the necessary flags, but that would not test whether the IsSolvable
method in this PR really adds the appropriate flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment would be fine. Just so that if it ever fails due to another change (and it may never do so), then whoever has to fix the test at least understands why it is the way it is.
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comments to these tests.
@hungaborhorvath regarding assertion levels, you may find this useful: #564 |
Hm, now this branch has conflicts with the current master. I guess due to some merges. How can I resolve this? |
@hungaborhorvath the conflict comes from an immediate method you added -- and then later on remove. If you squash your changes into fewer commits, or even just a single one, this will go. You can do this via interactive rebase. Run this command with your PR checked out (and no local modifications):
This will open up an editor, and you can instruct it to s(quas) or f(ixup) some or all of your commits together. In this case, I think you could just squash everything into a single commit. Once that worked, you should be able to rebase onto master again, and force-push the result. |
4e61256
to
50a1023
Compare
@fingolfin Hm, there is a problem. I did what you suggested (picked the first commit, squashed all the others, slightly rephrased the commit message). Then I rebased according to gap-system/master without any error messages, but somehow github complains about all checks failing.... Did I mess something up? |
Seems I was mistaken and there is still a conflict (in particular, you didn't rebase onto the latest master branch version...). If you rebase onto the latest master, you'll have to resolve the conflict. I can post some instructions how to do that later. |
- IsAbelian filters are added to IsSolvableGroup and DerivedSeries. - IsSolvable filters are added to DerivedSeriesOfGroup. - @hulpke's enhancement on DerivedSeriesOfGroup in commit e5eb173 about HasGeneratorsOfGroup and about HasAbelianInvariants are enhanced with HasIsTrivial and HasIsPerfectGroup.
50a1023
to
05c4635
Compare
@fingolfin Ok, I think I have managed to resolve the conflict. The master branch contained an immediate method for perfect groups, using the same lines where I added a new method for perfect groups. So I opened up the file in the editor, kept both changes, added it to the rebase, and continued the rebase, and I think now everything should work fine. |
@hungaborhorvath Thanks for resolving the conflict. Now, I noticed that the new IsPerfectGroup method is not covered by the tests. Do you know any examples which trigger it? |
about HasGeneratorsOfGroup and about HasAbelianInvariants are replaced
with HasIsTrivial and HasIsPerfectGroup (for which the corresponding
immediate methods are installed, see above).