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

Performance improvements and Corrections (in code used by group automorphisms) #968

Merged
merged 10 commits into from
Dec 8, 2016

Conversation

hulpke
Copy link
Contributor

@hulpke hulpke commented Dec 1, 2016

This PR contains a number of performance improvements in code (SmallerDegreePermutationRepresentation, Normalizer in Sn, Compatible pairs computation, permrep for automorphism group, stabilizer of vector orbits) in code used by group automorphisms. With these changes the examples in the original version of grpauto.tst run (if the assertion level is set to 0) in 2GB and about an hour.

It also fixes a number of observed issues: SolvableRadical code will not apply be default to FpGroups,
PreImagesRepresentative for PcGroups not testing membership in image properly.

@hulpke hulpke added the do not merge PRs which are not yet ready to be merged (e.g. submitted for discussion, or test results) label Dec 1, 2016
@hulpke hulpke added this to the GAP 4.9.0 milestone Dec 1, 2016
@ChrisJefferson
Copy link
Contributor

Based on how the code works, I suspect if you can cheaply calculate the Stabilizer of a group in Sn, you can calculate the Normalizer of H in G by doing Intersection(G, Normalizer(Sn, H)). The only time this should be slower would be if G was small enough that the time taken to calculate Normalizer(Sn,H) dominated the calculation.

@hulpke
Copy link
Contributor Author

hulpke commented Dec 1, 2016

@ChrisJefferson
Yes, one could do so, but what the code does in to find an overgroup of the normalizer in Sn and then call the ordinary normalizer -- it basically just descends from Sn (where few of the backtrack refinements work) to maximal subgroups or intersections of maximal subgroups which are unsymmetric enough that the backtrack has something to bite into.

What one can do (and I have done so in the past in particular situations) is indeed to reduce normalizer to centralizer+automorphism realizations, but this is only worth if the automorphisms can be found cheaply enough.

@hulpke hulpke removed the do not merge PRs which are not yet ready to be merged (e.g. submitted for discussion, or test results) label Dec 2, 2016
@codecov-io
Copy link

codecov-io commented Dec 3, 2016

Current coverage is 49.43% (diff: 48.71%)

Merging #968 into master will decrease coverage by 0.18%

@@             master       #968   diff @@
==========================================
  Files           424        424          
  Lines        222983     223138   +155   
  Methods        3430       3430          
  Messages          0          0          
  Branches          0          0          
==========================================
- Hits         110645     110313   -332   
- Misses       112338     112825   +487   
  Partials          0          0          

Powered by Codecov. Last update 5d7cd4c...fc2b75e

@hulpke hulpke force-pushed the additions branch 2 times, most recently from 44ca2d7 to 8a723f6 Compare December 4, 2016 20:19
##
#M StructureDescription( <G> )
##
AttributeMethodByNiceMonomorphism( StructureDescription,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sorry, but I have no idea what this is supposed to do. Does it mean the GAP will check if IsHandledByNiceMonomorphism is true, and if yes, then checks StructureDescription for the nice morphism image?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hungaborhorvath : Yes, sometimes the easiest option is to just print the method -- this is AttributeMethodByNiceMonomorphism

function ( oper, par )
    if 1 <> Length( par )  then
        Error( "need only one argument for ", NameFunction( oper ) );
    fi;
    par := ShallowCopy( par );
    par[1] := par[1] and IsHandledByNiceMonomorphism;
    InstallOtherMethod( oper, "handled by nice monomorphism: Attribute",
     true, par, 0, function ( obj )
          return oper( NiceObject( obj ) );
      end );
    return;
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what does this differently than what is already in grpnames.gi:1914-1924? Is this not superfluous?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, this duplicates the StructureDescription method already in grpnames.gi. Though I'd argue that the latter should be replaced by this. Using AttributeMethodByNiceMonomorphism is arguably the right thing to do.

@hulpke
Copy link
Contributor Author

hulpke commented Dec 4, 2016

@hungaborhorvath
Yes. The calculation cleary will be faster that way.

@@ -1619,6 +1619,11 @@ InstallMethod( StructureDescription,
k, # maximal power of d in Size(G)
pi; # subset of primes

if not HasIsFinite(G) and IsFinite(G) then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intentionally put this line here because IsFinite ranks higher than IsAbelian? I guess an IsFinite check is not too much for infinite abelian groups.

BTW, I could make two different methods for StructureDescription, one for finite groups and one for abelian, but for that I would need to hack around with some of the internal functions, so that is why I rather did it this way. And I did the IsAbelian check first, because that is the first step of the finite method, as well, thus saving time on the infinite abelian groups, and not wasting any time on the others (unless abelian test is faster for groups that know they are finite).

@@ -1083,7 +1083,7 @@ gap> StructureDescription(testG(8,2));
gap> StructureDescription(testG(8,3));
"C3 x QD16"
gap> StructureDescription(testG(8,4));
"((C16 x C2) : C2) : C2"
"((C16 : C2) : C2) : C2"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not work with no packages. The proper test should check for StructureDescription(testG(8,4):nice);
That would be stable with or without packages.

@hulpke
Copy link
Contributor Author

hulpke commented Dec 4, 2016

@hungaborhorvath
The code for Struct.Desc. is installed without requiring finiteness or abelianness, but forces test for these. This gives higher ranked methods (that would apply say if IsFinite was known) no chance, even if they are better.
The change tests finiteness, if it was not yet known and if so goes back into method selection from the start. It is at the start of the function, because this way I did not have to understand the rest of the code.

If you want a recommendation for cleaning up, I would install the method (by first assigning it to a variable) twice, once for IsFinite and once for IsAbelian (or split the code up into two functions) and then use two RedispatchOnCondition to test IsAbelian, or IsFinite, if no method applied. This way a missing property does not mean no method is found, but one retains the method selection even after the property is tested.

@hungaborhorvath
Copy link
Contributor

@hulpke Thank you for the advice. I would have appreciated it more during the 7 months #763 was open and not 3 days after its merge, but it is better late than never.

I decided to open an issue on how things are preferred to be done for StructureDescription in #979 to steer the development of this function in the way the community wants it. Hope to have your thoughts there. Thanks.

@@ -1082,8 +1082,8 @@ gap> StructureDescription(testG(8,2));
"((C8 x C2) : C2) : C2"
gap> StructureDescription(testG(8,3));
"C3 x QD16"
gap> StructureDescription(testG(8,4));
"((C16 x C2) : C2) : C2"
gap> Length(StructureDescription(testG(8,4)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not going to work, because without packages it returns "(C16 x C4) : C2", which has different length. (Could check for length>0, but I like the more stable nice option.) Also testG(8,2) is problematic. The nice option, though, would give a stable result, and further, it would more likely reveal problems with existing code, as in #973 I found that Centralizer cannot necessarily be computed in testG(8,2) (but this may be intended, I am not sure).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about

gap> StructureDescription(testG(8,4)) in [ "((C16 x C2) : C2) : C2", "(C16 x C4) : C2" ];
true

Not that I like this too much, but it does not contradict to a documented behaviour.

@hulpke hulpke force-pushed the additions branch 3 times, most recently from 11e3982 to 938de2f Compare December 5, 2016 16:43
@hulpke hulpke changed the title Performance improvements Performance improvements and Corrections Dec 5, 2016
@fingolfin
Copy link
Member

This PR decreases test coverage, and indeed, looking at https://codecov.io/gh/gap-system/gap/pull/968/compare quite a lot of the new code does not seem to be exercised by the test suite? (Or maybe those coverage reports only refer to testinstall ??)

It would be really nice if some simple test case could be added which trigger the new code...

@fingolfin
Copy link
Member

BTW, I also fully agree with @hulpke's advice regarding RedispatchOnCondition etc.

@hungaborhorvath
Copy link
Contributor

I will do the code split with redispatches, but I guess it makes sense to do it only after this PR is merged.

@hulpke
Copy link
Contributor Author

hulpke commented Dec 5, 2016

@fingolfin
The original version of grpaut.tst (which I'd be delighted to restore) will test the a significant part of the new code -- that's why it was put in. However it runs about 2 hours with assertions turned off.
This is in part because these are changes in handling large examples.

I can try to add further examples, but that might come at the cost of overall runtime. What does `codecov.io' actually run? testinstall? Or teststandard?

@olexandr-konovalov
Copy link
Member

@hulpke

The original version of grpaut.tst (which I'd be delighted to restore) will test the a significant part of the new code -- that's why it was put in. However it runs about 2 hours with assertions turned off. This is in part because these are changes in handling large examples.

Note that the original version of grpaut.tst is intended to be in benchmarks in PR #966. Maybe we can merge that PR (it also has other changes for other benchmarks) and then move tests between tst and benchmarks, to avoid having a third version of tests?

I can try to add further examples, but that might come at the cost of overall runtime. What does `codecov.io' actually run? testinstall? Or teststandard?

From https://github.com/gap-system/gap/blob/master/.travis.yml one could see that it's a aggregated coverage by tst/test{install,bugfix,travis}.g tests. This gives all from testinstall plus bugfix.tst plus those from teststandard which have not more than 18080000 GAP4stones.

@hungaborhorvath
Copy link
Contributor

@hulpke Thank you for your help and suggestions. I had some time on my hands, so I split the StructureDescription method in #985, and also did correct the tests and nice monomorphism as you suggested.

Could you remove your commit about the StructureDescription part, so the two PRs would not conflict with each other? Thank you.

@hulpke
Copy link
Contributor Author

hulpke commented Dec 5, 2016

@hungaborhorvath
I've removed the commit.

@hungaborhorvath
Copy link
Contributor

@hulpke Thank you.

@fingolfin
Copy link
Member

@hulpke Thanks for the clarification, I wasn't aware about the (re)moved tests.
As long as they are there, and we do run them automatically sometimes (e.g. on our Jenkins), I am fine -- though it still would be nice to have "quick" tests for these functions at some point, too. That could perhaps be achieved by invoking them directly with suitable test values, instead of trying to reach them via high-level calls. (Incidentally, that leads us to the notion of "unit test"... :-)

FIX: More lenient in using maxes for factor group perm rep.
Use structure of automorphisms of socle to write down permutations for it.

but careful with primitive library
…pairs.

FIX: First abelian, then primitive to avoid recursion.

FIX: Improved heuristics for particular approaches
Only call these methods if `CanComputeFittingFree` is set. This will be set
for perm and pc groups, as well as if HasFittingFreeLiftSetup is set.
Add some fallback methods.
Finiteness test fallback for lattice

This fixes gap-system#980
Improved method for fusing orbits.
Also nicer info printing.

Removed temporary test
@olexandr-konovalov
Copy link
Member

Would be good to merge this as #980 and #990 seem to depend on this. But there are 9 more commits within last 8 days which seem not to be reviewed yet.

@@ -11,6 +11,15 @@

gap> START_TEST("grpauto.tst");

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've run make teststandard for this PR. The no-packages version took 1257s and displayed one diff:

########> Diff in /home/alexk/GITREPS/gap/tst/teststandard/grpauto.tst:12
# Input is:
START_TEST("grpauto.tst");
# Expected output:

# But found:
########

Because it expects the empty line as an output of START_TEST("grpauto.tst");. Please delete this empty line, or even better - leave this empty line intact, but add a comment after it, describing this test case (note that if there would be a comment already, the test would just pass - see my remark below).


Remark: It's documented behaviour of Test which has to distinguish empty lines as parts of output from empty lines as separators: "To allow for comments in fname the following lines are ignored by default: lines at the beginning of fname that start with "#", and one empty line together with one or more lines starting with "#". All other lines are considered as GAP output from the preceding GAP input."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, the version with all packages took 1330s and did not run out of memory (-o 1g -K 2g).

@hulpke hulpke merged commit f1e9830 into gap-system:master Dec 8, 2016
@olexandr-konovalov olexandr-konovalov changed the title Performance improvements and Corrections Performance improvements and Corrections (in code used by group automorphisms) Jan 29, 2018
@olexandr-konovalov olexandr-konovalov added the release notes: added PRs introducing changes that have since been mentioned in the release notes label Jan 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release notes: added PRs introducing changes that have since been mentioned in the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants