Skip to content

PR or not PR?: @frankluebeck extensions - #15

Open
frankluebeck wants to merge 8 commits into
gap-packages:masterfrom
frankluebeck:fl_extensions
Open

PR or not PR?: @frankluebeck extensions#15
frankluebeck wants to merge 8 commits into
gap-packages:masterfrom
frankluebeck:fl_extensions

Conversation

@frankluebeck

Copy link
Copy Markdown
Member

This pull request provides various additions and changes. See the not so short commit messages for more details.

Several functions are probably of more general interest and should be documented (not yet done).

In fact, much of the original code in InduceRestrict.gi is disabled and no longer needed.
And it would be sensible and not much additional effort to substitute all of the original code completely by some simpler bookkeeping with hooks for interactive use.

So, the question is how to proceed? Would it be better to create a new package with this code (instead of substituting the whole content of the InduceReduce package)?

There is a good speedup for all of the examples (and more) discussed here, but one major bottleneck in GAP remains the slow conjugacy testing. E.g., for G=PSL(3,17) computing all power maps now takes about 11 seconds on my machine and then computing all irreducible characters takes another 11 seconds.

I have some more ideas for changes, but let us first discuss how to proceed.

These files contains the function PositionConjugacyClass(G, x) for
identifying the number of the G-conjugacy class of the element x in
G.

This uses a tree structure to compute class invariants until
the class is determined, see ConjugacyClassInvariants(G).

In this version only very basic invariants are used, e.g.
cycle types for permutations, characteristic and minimal polynomial for
matrices, and as fallback always conjugation tests against candidates.

This could be enhanced with more functions that find other invariants.
The function PowerMapsOfAllClasses(G) computes efficiently
all powermaps of all conjugacy classes of G using some orbit stabilizer
algorithm, and reusing the information from classes already considered.

There are also utility functions as applications:
   MaximalCyclics(G)
   RationalClassSets(G)
   InduceAllFromCyclicSubgroup(G, i)
   InducedFromAllMaximalCyclicSubgroups(G)
   PowerMapCharacters(G, n)
   SmallPowerMapCharacters(G)
NaturalCharacters(G) using given representation of G

pPrimeCharacter(chi, p)
pPrimeRestriction(chi, p) which use for primes p the decomposition of
finite order group elements x = y z = z y into unique elements y of
order p and z of order not divible by p
So far, the new code is just loaded when the package is loaded,
but nothing is changed for InduceReduce.
Now we use the new functionality provided by the previous commits
in InduceReduce:
  - substitute FindClass, PowMap and InduceCyc
  - since it is pretty fast now, we make DoCyclicFirst the default
  - afterwards we use natural characters and power map characters
  - a general utility 'ImportGeneralizedCharacters' for importing
    characters from other functions
  - scalar products of generalized characters are speeded up
    a bit by using chi(g^-1) instead of ComplexConjugate(chi(g))
    (using the precomputed power map of -1)
  - we now skip elementary subgroups where the p-subgroup is cyclic
    (since then the whole elementary subgroup is cyclic)
    MaximalNonCyclicElementarySubgroups(G) up to conjugacy
         <x> x P is denoted [i,p] if x is in class i and P a Sylow-p
         of the centralizer of x

    InducedFromElementary(G, i, p[, "linear"/"nonlinear"])
         induce irreducibles from elementary subgroup [i,p] (see above),
         optionally only linear/nonlinear irreducibles
With this huge parts of the code in InduceRestrict.gi are no longer
used.

This avoids redundant elementary subgroups and the computation of the
induced characters from an elementary subgroup is sometimes much faster.

Large parts of the Unger record are no longer used.
@ThomasBreuer

Copy link
Copy Markdown
Collaborator

Thanks.
Very impressive.

Comparing the timings from #5 (the comment from August 8), we get speedup for the simple groups among the examples considered there. Below are the analogous timings but with the code from the current branch.

[[                           G, IrrUnger, IrrDixonSchneider, IrrBaumClausen, IrrConlon],
 [ AbelianGroup( [ 2, 3, 7 ] ),       22,                51,              4,        16],
 [ExtraspecialGroup( 27, '+' ),        8,                14,              3,        20],
 [      SmallGroup( 768, 590 ),     4198,              1293,             63,       642],
 [          MathieuGroup( 12 ),      106,               467,              0,         0],
 [          MathieuGroup( 24 ),      277,              3661,              0,         0],
 [      SimpleGroup( "U4(3)" ),      729,              3570,              0,         0],
 [                  GL( 2, 3 ),        8,                31,              0,         0],
 [                  SP( 4, 3 ),      661,              1045,              0,         0]]

For small PC groups of order up to 100, we get no speedup.

gap> # abelian
gap> Sum( timings( groups2[1], funs ), x -> x{[2..5]} );
[ 46555, 30040, 882, 8391 ]
gap> # nonabelian supersolvable
gap> Sum( timings( groups2[2], funs ), x -> x{[2..5]} );
[ 37013, 28183, 3996, 71365 ]
gap> # non-supersolvable
gap> Sum( timings( groups2[3], funs ), x -> x{[2..5]} );
[ 1423, 1702, 0, 0 ]

Larger simple groups are interesting from the viewpoint that Unger's algorithm is better than Dixon's algorithm.
Here are some examples, computed with the master branch and the current branch, respectively. The timings are for the call IrrUnger(G).

G                    | master | curr.
---------------------------------------------
PSL(2,23)            |    210 |   146
PSL(2,41)            |    468 |   443
PSL(2,59)            |   1142 |   892
PSL(3,4)             |    233 |   289
PSL(3,5)             |    286 |   183
PSL(3,7)             |    397 |   249
PSL(3,9)             |   3618 |  2544
PSL(3,11)            |  10777 |  6518
SimpleGroup( "J2" )  |    759 |   366
SimpleGroup( "J3" )  |   6543 |  3174
SimpleGroup( "HS" )  |    892 |   498
SimpleGroup( "McL" ) |   1386 |   768

@ThomasBreuer ThomasBreuer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes, parts of the code are of general interest.

I think the class identification would fit best into the GAP library. The Dixon-Schneider implementation uses already something similar, but the data are hidden inside the Dixon record, and cannot be used for other purposes.

The improvements for inducing from cyclic subgroups could replace existing GAP library code.

And the improved power map handling could also be unified with the corresponding parts of the Dixon-Schneider code.

local r, funcs, tree, find;
if IsBound(G!.ConjugacyClassInvariants) then
return G!.ConjugacyClassInvariants;
fi;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

So the idea is to create the value once, perhaps depending on individual args, to store the value (as for an attribute), and later return this stored value, independent of the args given then. This may lead to unexpected behaviour.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I had not used an attribute here such that one can just remove this component and compute invariants with different arguments.

Comment thread lib/InduceReduce.gi
GR.B:=GR.B-mat*I;
Append(GR.Ir,Set(I)); # add the new irreducible characters to I
GR.foundDim := Length(GR.Ir)+Length(GR.Gram);
GR.foundDet := DeterminantMat(GR.Gram);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In IrrUnger( SmallGroup( 1, 1 ) ), we get that GR.Gram is the empty list, and we get an error.
(In fact, we run into a similar error already a few lines earlier, in GR.B:=temp.transformation*GR.B, where temp.transformation is empty. This did not happen in the old code.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed.

# for permutation groups: cycle structures on orbits of points
CCInvFuncs.CycStruct := function(r, tree)
local o, fu;
o := Orbits(r.G, MovedPoints(r.G));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
o := Orbits(r.G, MovedPoints(r.G));
o := Orbits(r.G);

(Then we compute this only once.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good idea.

Comment thread lib/SomeCharacters.gi
t := CharacterTable(G);
cls := ConjugacyClasses(G){IdentificationOfConjugacyClasses(t)};
reps := List(cls, Representative);
orb := Orbits(G, MovedPoints(G));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
orb := Orbits(G, MovedPoints(G));
orb := Orbits(G);

Comment thread lib/PowerMaps.gi
od;

# so far we have in res[i][k] the class of reps[i]^k,
# now we shift it to reps[i]^(k-1), so that the trivial class comes first

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just for curiosity: Why is this shifted data format better than the one without the shift?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

0-based allows accessing k-th power as l[k mod n + 1] while 1-based one needs extra code to handle k mod n = 0.

@frankluebeck

Copy link
Copy Markdown
Member Author

Probably we don't want to merge this pull request here.

I have now also written code to substitute InduceReduce.g* and then collected all code in a new package https://github.com/frankluebeck/UTable.

That code avoids calling CharacterTable (such that one could add a method for it with nicer ordering of classes and characters). Also generalized characters are stored more efficiently with one value per rational class. There is a speedup for computing scalar products and linear combinations of class functions. This is the more useful the more complicated the irrationalities are.

To compare with the new package try:

LoadPackage("UTable");
G:=....
Irr(UTable(G));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants