-
Notifications
You must be signed in to change notification settings - Fork 160
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
Reduce impact of immediate methods to calculations with groups #2387
Conversation
lib/coll.gi
Outdated
# TryNextMethod(); | ||
# fi; | ||
# return infinity; | ||
# 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.
I agree this should not be an immediate method, but perhaps it should be retained as a regular method? Then with the IsAttributeStoringRep
removed.
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.
If we do so, we need to rank this high, so that it overrides any other.
(Also removing this immediate method broke specific tests for this method will need to be adjusted.)
lib/grp.gi
Outdated
# else | ||
# TryNextMethod(); | ||
# 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.
Fine by me.
Ooops, the next method after this one is incorrect: it does
if HasGeneratorsOfGroup( G ) and Length( GeneratorsOfGroup(G) ) = 1 then
SetMinimalGeneratingSet(G,GeneratorsOfGroup(G));
which is incorrect if GeneratorsOfGroup(G)
consists only of an identity element. This is of course currently hidden by the immediate method. Mental note to self: try to find a tests case triggering this (after the immediate is gone), and fix it. (But anybody else feel free to fix this first, I won't work on it today for sure ;-)
lib/grp.gi
Outdated
typ:=typ and HasIsTrivial and HasIsNonTrivial; | ||
triv:=true; | ||
# basic consequence | ||
typ:=typ and HasIsPerfectGroup and IsPerfectGroup; |
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'd rather have a InstallTrueMethod( IsPerfectGroup, IsGroup and IsTrivial );
, this will cover the above (with zero overhead).
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.
Yes. That would be much nicer. Will change.
lib/grp.gi
Outdated
else | ||
ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens), | ||
IsEmpty,false,IsTrivial,triv, | ||
IsNonTrivial,not triv); |
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.
Hmm, why set IsTrivial
resp. IsNonTrivial
this way, instead of just anding them into typ
like you do with e.g. IsCyclic
? Does this have some functional difference?
If not, I'd just set this all in typ
, then you can get rid of triv
and simplify the code here and elsewhere accordingly.
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'd love to do. But how do I set a flag to `false' as part of a type?
IsTrivial and IsNonTrivial are twins that are set the opposite way and currently immediate methods are used to set either to false if the other is set.
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.
If you just specify HasIsCyclic
without IsCyclic
, then this is equivalent to setting it to false.
In somewhat related news, I plan to add an InstallFalseMethod
helper soon (see #235), at least for "elementary" properties (i.e. not involving and-ing together multiple properties).
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.
Thanks! Will do so.
lib/grp.gi
Outdated
G:=rec(); | ||
ObjectifyWithAttributes(G,typ,GeneratorsOfMagmaWithInverses,AsList(gens)); | ||
fi; | ||
typ:=NewType(fam,typ); |
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.
Just to make it explicit: the changes in this PR get rid of the cached values fam!.defaultFinitelyGeneratedGroupType
and fam!.defaultGroupType
. I assume that you verified that there is a net gain (probably because this initial type (almost?) always ended up being replaced by immediate methods anyway.
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.
When I left the caching in I ran into problems -- a non-nilpotent group claimed to be nilpotent. The best I could come up (#2394 ) is that the cached type in fact gets changed later and thus cannot be cached. If I'm doing something wrong here I'd love to know (and then would add type caching again).
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 am not sure how useful those caches would be, unless done very carefully: in the old code, there were already two caches, one for finitely generated groups, and one for those where we don't know whether they are f.g. or not. In order to preset IsTrivial
and other flags, you'd have to either create more caches (i.e. have one cached type for trivial groups; one for non-trivial cyclic; one for non-cyclic f.g.; one for the generic case). Of course that number grows as you add special cases. Luckily, in this case at least the number of types does not seem to grow exponentially, as most of the checks differentiate based on the generating set along.
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.
At the start of writing the previous comment, I wasn't sure, because I thought you'd need to add 2^n caches, for n 3 or 4, but now it seems only four may be needed, which is at least not totally crazy.
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.
Another cause for the problems you have seen may be that you add e.g. HasIsTrivial
to the flag lists of the type. I think that means that any object created with that type is non-trivial, no matter what; once HasIsTrivial
is set, one cannot change the value of IsTrivial
anymore (at least not without low-level bit fiddling); this is a feature, not a bug.
lib/grp.gi
Outdated
typ:=typ and IsFinitelyGeneratedGroup; | ||
if Length(gens)<=1 then | ||
typ:=typ and HasIsCyclic and IsCyclic | ||
and HasIsCommutative and IsCommutative; |
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.
Note that this is equivalent to typ := typ and IsCyclic
, as IsCyclic
implies IsCommutative
, and each implies its tester, and handling these implications comes at zero cost here.
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.
Ah -- I wasn't sure. Will fix.
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.
Every property implies it tester; for the rest, you can check this e.g. as follows :
gap> ShowImpliedFilters(IsCyclic);
May imply with:
+IsMagmaWithInverses
+IsAssociative
IsCommutative
IsNilpotentGroup
IsSupersolvableGroup
IsSolvableGroup
IsNilpotentByFinite
+IsOrdinaryTable
IsCommutative
IsNilpotentCharacterTable
IsSolvableCharacterTable
IsSupersolvableCharacterTable
Or, more technically:
gap> IsEquivFilters:={f1,f2}->IS_EQUAL_FLAGS(WITH_IMPS_FLAGS(FLAGS_FILTER(f1)), WITH_IMPS_FLAGS(FLAGS_FILTER(f2)));
function( f1, f2 ) ... end
gap> IsEquivFilters(IsGroup and IsCyclic, HasIsCyclic and IsCyclic and HasIsCommutative and IsCommutative and IsGroup);
true
lib/grp.gi
Outdated
and HasGeneratorsOfMagmaWithInverses and HasOne | ||
and IsFinitelyGeneratedGroup and HasIsTrivial and HasIsNonTrivial | ||
and HasIsFinite and HasIsCyclic | ||
and HasIsPerfectGroup and HasIsEmpty; |
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.
Can't you just replace the above with typ:= IsGroup and IsAttributeStoringRep and HasGeneratorsOfMagmaWithInverses and HasOne and IsTrivial
? The IsTrivial
implies (via zero cost implications) all the remaining flags.
lib/grppc.gi
Outdated
@@ -272,7 +272,8 @@ InstallMethod( Pcgs, | |||
## | |||
#M GeneralizedPcgs( <G> ) | |||
## | |||
InstallImmediateMethod( GeneralizedPcgs, IsGroup and HasPcgs, 0, Pcgs ); | |||
# is now set when creating | |||
#InstallImmediateMethod( GeneralizedPcgs, IsGroup and HasPcgs, 0, Pcgs ); |
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.
Well, it is set when creating via GroupWithGenerators
, but that's not the only way to create a group object! However, I agree this does not need to be an immediate method; esp. as nothing tests HasGroupWithGenerators
. So let's just turn it into a regular method.
lib/magma.gi
Outdated
TryNextMethod(); | ||
fi; | ||
end ); | ||
# this is now set when creating groups |
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 should say "when creating magmas". But even then it's not quite true: If a magma is created in a non-standard way, it may not be set. So, like with most of the other immediate methods you remove/commented out, I'd prefer to instead turn it into a regular method.
lib/magma.gi
Outdated
# typ:=typ and IsFinitelyGeneratedGroup; don't know whether group | ||
if Length(gens)<=1 then | ||
typ:=typ and HasIsCyclic and IsCyclic | ||
and HasIsCommutative and IsCommutative; |
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 deduction is not correct for non-associative magmas.
Codecov Report
@@ Coverage Diff @@
## master #2387 +/- ##
==========================================
- Coverage 73.98% 73.98% -0.01%
==========================================
Files 484 484
Lines 245405 245434 +29
==========================================
+ Hits 181571 181573 +2
- Misses 63834 63861 +27
|
lib/grp.gi
Outdated
id:=One(gens[1]); | ||
if ForAny(gens,x->x<>id) then | ||
typ:=typ and HasIsTrivial and HasIsNonTrivial; | ||
triv:=false; |
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.
Hmm, why does this still use triv
instead of setting typ:=typ and HasIsTrivial and IsNonTrivial
; similar below
lib/grp.gi
Outdated
else | ||
typ:=typ and HasIsTrivial and HasIsNonTrivial; | ||
triv:=true; | ||
typename:="defaultFinitelyGeneratedTrivialGroupType"; |
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.
The FG part of this name seems redundant: trivial already implies iy, no? Same for the cyclic types.
lib/grp.gi
Outdated
typ:=fam!.defaultGroupWithOneType; | ||
elif Length(gens)<=1 then | ||
typ:=typ and IsCyclic; | ||
typename:="defaultFinitelyGeneratedCyclicGroupWithOneType"; |
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 type computation is repeated several times across multiple GroupWithGenerators methods - can't it perhaps be factored out into a common helper function?
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.
The best I was able to come up with would have been preprocessor macros, but for a function there are too many small differences that would require input parameter and extra processing. (This is an observation of my incompetence, not a statement that it cannot be done.)
lib/grp.gi
Outdated
# IsSolvableGroup and HasIsTrivial, | ||
# 0, | ||
# IsTrivial ); | ||
InstallTrueMethod( IsPerfectGroup, IsGroup and IsTrivial ); |
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.
InstallTrueMethod calls belong into .gd files
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.
Done.
lib/coll.gi
Outdated
# replace immediate method by ordinary, as immediate gets called for every | ||
# group that knows it is finite but does not know its size -- e.g. | ||
# permutation, pc. The benefit of this is minimal beyond showing off a | ||
# feature. |
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 comment (as well as several other that follow) only make full sense when read in the context of this commit resp. PR; but if somebody reads this in a year, they might have a hard time understanding what is meant here. "What is being replaced here???"
Not having this commit would IMHO be better; or start it with something like "the following method used to be immediate. However..." but I wonder whether this would be a useful comment. I think this would better fit into the commit message.
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'll change the text. IF it it hidden in a commit message, however I think it is less likely to be seen and also loses the reference to the place in the source code.
lib/coll.gi
Outdated
# group that knows it is finite but does not know its size -- e.g. | ||
# permutation, pc. The benefit of this is minimal beyond showing off a | ||
# feature. | ||
InstallMethod( Size,true, [IsCollection and HasIsFinite], 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.
You can omit true and 0 here
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.
OK, but is it a problem if they're in? (Some methods actually might need a higher ranking).
lib/grp.gi
Outdated
@@ -30,7 +30,9 @@ InstallImmediateMethod( IsFinitelyGeneratedGroup, | |||
## | |||
#M IsCyclic( <G> ) . . . . . . . . . . . . . . . . test if a group is cyclic | |||
## | |||
InstallImmediateMethod( IsCyclic, IsGroup and HasGeneratorsOfGroup, 0, | |||
# this is now set when creating the groups, make ordinary instead of |
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.
See above
lib/grp.gi
Outdated
fi; | ||
else | ||
typ:=typ and IsTrivial and HasIsNonTrivial; | ||
typename:="defaultFinitelyGeneratedTrivialGroupType"; |
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.
The FG part of this name seems redundant: trivial already implies iy, no? Same for the cyclic types.
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.
yes, changed.
lib/grppcfp.gi
Outdated
@@ -69,6 +69,7 @@ InstallGlobalFunction( IsomorphismFpGroupByPcgs, function( pcgs, str ) | |||
od; | |||
od; | |||
H := F / rels; | |||
SetIsFinite(H,true); |
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 find it rather awkward to add all this SetIsFinite
calls before each SetSize
; and it is easy to forget, too. I'd rather add this into a custome setter for Size
. I can submit a PR doing that tomorrow. Such a setter could also set IsTrivial, IsEmpty, IsNontrivial in one go.
Also, I assume this is only beneficial because setting IsFinite
does not trigger any/fewer immediate methods than setting Size
, correct?
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.
Yes to both. The setter also is on my to-do list.
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.
Also, the IsFinite might be overkill -- I was trying to get rid of calls to immediate methods.
lib/grp.gi
Outdated
#InstallImmediateMethod( IsPerfectGroup, | ||
# IsSolvableGroup and HasIsTrivial, | ||
# 0, | ||
# IsTrivial ); |
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.
Let's just remove this completely -- see also my suggestion above for the other "missing" direction.
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.
ditto OK
lib/grp.gi
Outdated
typ:=typ and IsFinitelyGeneratedGroup; | ||
typename:="defaultFinitelyGeneratedGroupWithOneType"; | ||
|
||
if Length(gens)>0 and CanEasilyCompareElements(gens) then |
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.
Use >=0
to deal with empty collections? Or even better, as this also works if CanEasilyCompareElements(gens)
is false, start like this:
if Length(gens) = 0 then
...
elif CanEasilyCompareElements(gens) then
...
elif Length(gens) = 1 then
...
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.
But there is a specialized method below for the case of IsEmpty
for the collection gens
. Wouldn't it override it?
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.
That method is only for empty lists, but not for empty collections-that-aren't-lists. Though these are rather rare and special beast.
But as I said before, it would also be nice if all this logic would not have to be repeated in almost identical form several times, but rather was put into one (or at least very few) helper functions which can be called from multiple places.
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 hear what you say and there is still stuff to clean up. If the type caching goes away, it should be easier to have the logic in one function, and I consider this a goal before merging.
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.
The deductions logic is now in a separate function.
lib/grp.gi
Outdated
typ:=typ and HasIsTrivial and IsNonTrivial; | ||
if Length(gens)<=1 then | ||
typ:=typ and IsCyclic; | ||
typename:="defaultNontrivialCyclicGroupWithOneType"; |
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.
BTW, NEW_TYPE
also performs caching of types for a given family. You can inspect NEW_TYPE_CACHE_MISS
and NEW_TYPE_CACHE_HIT
before/after creating a group to see it was effective. So.... that might in fact render the cache here moot. (While the explicit cache here may be a tiny bit faster, it also adds a lot of complexity...)
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'll put this in a separate remark as a push will make it go outdated in code
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.
(after all it did not, but should not be only commit remark)
tst/testinstall/coll.tst
Outdated
gap> SetIsFinite(c2, false); | ||
gap> HasSize(c2); | ||
true | ||
gap> Size(c2); |
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 test foremost was meant to test that Size
method. Since it is still there, just not immediate, we could keep the test, and just remove the two checks for HasSize
.
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.
OK.
@fingolfin remarked
Yes, the type caching here is beyond ugly, and the only reason would be if it has a notable performance impact. On a single pair of tests I measure (re-starting GAP) 237 sec. with caching versus 211 seconds without caching. Is this good enough to say we simply leave the caching out? In any case, I have rearranged the commits so that the re-introduction of caching (with shorter names) now is all located in a single commit. It thus could be removed easily. |
959e9b6
to
718a107
Compare
lib/grp.gi
Outdated
@@ -30,7 +30,9 @@ InstallImmediateMethod( IsFinitelyGeneratedGroup, | |||
## | |||
#M IsCyclic( <G> ) . . . . . . . . . . . . . . . . test if a group is cyclic | |||
## | |||
InstallImmediateMethod( IsCyclic, IsGroup and HasGeneratorsOfGroup, 0, | |||
# This used to be an immediate method. It was replaced by an ordinary | |||
# method sine the flag is typically set when creating the group. |
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.
sine -> since
9af1a23
to
ed5c90a
Compare
29132cf
to
23258ff
Compare
lib/grppcaut.gi
Outdated
@@ -971,6 +975,7 @@ local f,act,xset,stb,hom,n,m,l,i; | |||
Add(stb,m); | |||
stb:=List(stb,x->x^act); # base change | |||
stb:=Group(stb); | |||
SetIsFinite(stb,true); |
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.
Are all these SetIsFinite
calls still necessary?
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.
No. SetSize (or SetIsGroupOfAutomorphismsFiniteGroup) should take care of it.
lib/coll.gi
Outdated
SetIsEmpty(obj,sz=0); | ||
SetIsTrivial(obj,sz=1); | ||
SetIsNonTrivial(obj,sz<>1); | ||
SetIsFinite(obj,sz<>infinity); |
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.
Doesn't this still change the type four times (less for sz=0 and sz=1 because of implications, but stilll). Plus a fifth time for the size. So, how about something like this:
function(obj, size)
local filt;
if HasSize(obj) and Size(obj) <> size then
ErrorNoReturn("size of <obj>" already set to ", Size(obj), ", cannot change it to ", size);
fi;
if size = 0 then filt := IsEmpty;
elif size = 1 then filt := IsTrivial;
elif size = infinity then filt := IsNonTrivial and HasIsFinite;
else filt := IsNonTrivial and IsFinite;
fi;
filt := filt and HasSize;
obj!.Size := size;
SetFilterObj(obj, filt);
end;
This assumes we already have or add (negative) implications between IsEmpty, IsTrivial and IsNonTrivial (the three are after all mutually exclusive).
(We may also wish to add IsNonEmpty
and IsInfinite
, but better not in this PR)
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.
Thank you -- you've just answered a question I had, but had not yet asked -- indeed the four sets
are bad, but I wanted first to get the errors out. Will change as you suggest.
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 is done. However (the manual specifies that an SetSize
if size is given has no effect) I have wrapped the error into a check that requires assertion level to be >=3.
cc93123
to
186ea11
Compare
86e8b4f
to
f2d70e1
Compare
@fingolfin |
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.
Only some quick remarks, I have not yet looked at everything, need to prepare class material etc. now instead.
However, I am rather unhappy with the commit structure. At the very least, the commit messages need work. They reference work which is not visible anymore, which is highly confusing. They also contain typos (e.g. Empty
instead of IsEmpty
), and incomplete sentences, reducing their usefulness.
However, it also happens that one commit introduces a typo and then a later one fixes it (instead of just fixing the first commit); or that a commit contains changed not indicated by its summary line (which then turns out to not actually summarize what the commit is about).
I know it's tiresome to work so long on such a big patch, but it's also very tiresome if one has to debug these changes in a year down the road, and has to painstakingly reverse engineer what the changes were about, etc., so doing this right now will save us work down the road.
In this case, it might actually be best to first squash all changes together into one commit, or perhaps two (using git reset
to uncommit all changes, followed by using git add -p
judiciously to create fresh commits): one which turns immediates into implications; and one with the rest. I haven't had a chance to read through everything to say for sure, I'll try to do that during this week.
lib/coll.gi
Outdated
if HasSize(obj) and Size(obj)<>sz then | ||
if AssertionLevel()>2 then | ||
# Make this an ordinary error to enter break loop so that one can | ||
# investigate call order for debugging |
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 don't understand this comment. What is a "non-ordinary error"? Perhaps you are referring to Assert
? But that enters a break loop for me just fine, doesn't it?
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 had suggested ErrorNoReturn
in an earlier remark on this function. For debugging (and understanding how code worked in the past despite this issue) it seemed better to not forbid return;
. (Yes, it could mislead a user, but this is really an error that should never come up for a user. (I'm happy to replace by Assert
, if that is preferred here.
lib/coll.gi
Outdated
@@ -3052,6 +3053,31 @@ end); | |||
InstallMethod( CanComputeIsSubset,"default: no, unless identical", | |||
[IsObject,IsObject],IsIdenticalObj); | |||
|
|||
# avoid immediate methods triggering multiple type changes once the Size of | |||
# an object is known. |
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 comment starts mid-thought. Perhaps: "Custom SetSize method which sets various properties implied by the given size. This avoids ..." ?
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 see this as mid-thought, but I'm happy to change it.
lib/csetgrp.gi
Outdated
RightCosetCanonicalRepresentativeDeterminator); | ||
SetSize(d,Size(U)); # as own setter |
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 does "as own setter" mean?
Also, doesn't ObjectifyWithAttributes
call custom setters anyway? It contains specific code to detect them. But perhaps you want to avoid that? In that case, I guess a comment explaining that (and why) would be indeed appropriate, but this comment isn't doing that.
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.
We cannot set the size in the previous ObjectifyWithAttributes
as there is a custom setter method (the one just added here). In such a case ObjectifyWith Attributes just does
Objectify` and calls all setters separately which is what we want to avoid here.
@@ -784,6 +784,8 @@ InstallFactorMaintenance( IsSolvableGroup, | |||
InstallTrueMethod( IsSolvableGroup, IsMonomialGroup ); | |||
InstallTrueMethod( IsSolvableGroup, IsSupersolvableGroup ); | |||
|
|||
InstallTrueMethod( HasIsPerfectGroup, IsGroup and IsSolvableGroup and IsNonTrivial ); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
lib/grp.gi
Outdated
@@ -31,7 +31,7 @@ InstallImmediateMethod( IsFinitelyGeneratedGroup, | |||
#M IsCyclic( <G> ) . . . . . . . . . . . . . . . . test if a group is cyclic | |||
## | |||
# This used to be an immediate method. It was replaced by an ordinary | |||
# method sine the flag is typically set when creating the group. | |||
# method since the flag is typically set when creating the group. |
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 fixes a typo from the first commit. It should be instead melded into the first commit...
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.
ditto
@fingolfin Yes, my plan is to merge everything into a single commit (and then revise the comments) before merging. (Some of this has been done now.) So far I have done partial merges but left some recent commits separately so it was clear what has changed. |
@hulpke I misunderstood one of your earlier remarks as saying "this PR is now ready to be merged". I see now that this wasn't what you said at all. My apologies for the misunderstanding. |
This commit changes routines that create groups, certain Submagmas aand vector spaces so that flags that set basic properties (being trivial, being empty, being cyclic) are set at the same time as the object was created. This functionality used to be provided through immediate methods, however this meant that the type of a just-created object was changed immediately multiple times (with some changes precipitating other changes), causing a notable performance hit. Notably, the following changes have been done: 1) In a number of methods used to create groups (or submagmas, when called from `Subgroup` or cosets) from generating sets, a number of cheaply deduced properties (such as being cyclic) are set while creating the object. Thus the immediate methods do not apply for these objects any longer. 2) Type caching in these methods is not worth the effort and has been removed. 3) A new setter method for `Size` deals similarly with deductions done before by immediate methods for a known size. Caveat: The manual specifies (ill-advised one might say) that setting a different size if a size already is given will be ignored. This is tested in manual examples and test files. The new setter method therefore cannot be used to check for this property as an error -- it will do so only if assertion level is set >=3. 4a) Immediate methods that have been made obsoleteby the changes in 1) and 3) have been changed to ordinary methods. 4b) A number of immediate methods (e.g. a trivial group is solvable) have been replaced by `TrueMethods` that have the same effect but are chaper to run. 4c) Also a number of immediate methods that need to run often, but apply only rarely (i.e. setting `IsFinite` to false if a size is set to `infinity`) have been removed. 5) These changes have minor impact on test files and manual tests: A few objects will have slightly different knowledge about their properties and thus print differently; respectivelty test code exists that checks explicitly for such properties having been set by immediate methods. These tests and examples have been changed. A few, very instable tests (e.g. checking explicitly for the values of random elements) have been commented out. 6) Some tests explicitly relied on immediate methods enabling derived series calculations in special cases of finitely presented groups. These tests never would have worked if immedite methods were turned off, the respective finitely presented groups method has been changed accordingly to test explicitly for the particular situation, thus enabling the same examples to work.
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 pretty good now. I have some minor comments. Several of them (e.g. the wish to change IsTrivial and HasIsNonTrival to just
IsTrivial`) can be addressed in a separate PR (and also by somebody else, e.g. me), I just mentioned them because I tried to document everything that occurred to me.
Anyway, I'd like to run a few more tests with this tonight, and (barring more remarks from @hulpke) plan to merge it then or tomorrow.
RightCosetCanonicalRepresentativeDeterminator); | ||
# We cannot set the size in the previous ObjectifyWithAttributes as there is | ||
# a custom setter method (the one added in this commit). In such a case | ||
# ObjectifyWith Attributes just does `Objectify` and calls all setters |
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.
"ObjectifyWith Attributes" -> "ObjectifyWithAttributes" (one word)
IsSolvableGroup and HasIsTrivial, | ||
0, | ||
IsTrivial ); | ||
|
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.
Why remove this, instead of turning this into a plain method? Wouldn't that still be useful?
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 don't think it's necessary to add a "this used to be an immediate method ..." comment)
filt:=filt and IsTrivial and HasIsNonTrivial; | ||
fi; | ||
fi; | ||
elif isgroup and Length(gens)<=1 then # cyclic not for magmas |
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 could replace this elsif
by fi; if
and then get rid of the identical check a few lines above.
if Length(GeneratorsOfGroup(G))=1 then | ||
SetIsAbelian(G,true); | ||
return TrivialSubgroup(G); | ||
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.
So this seems to be a separate improvement for DerivedSubgroup
on fp subgroups of rank 1... But why is it needed? Because we removed the immediate method for "size of generating set <= 1 implies abelian" ?
This raises two questions:
- Where is the place we create a group w/o taking care of that? can we do something about it (i.e. fix the issue at its root, not the symptom)
- Do we really need to remove (or replace by normal ones) those immediate methods? After all, if e.g.
IsFinite
is set, then no immediate method forIsFinite
is run. So leaving those immediate methods in should not cause a speed penalty anymore -- or does it? I should run some tests....
One, id, | ||
FamilyPcgs,pcgs,HomePcgs,pcgs,GeneralizedPcgs,pcgs); | ||
|
||
#SetGroupOfPcgs (pcgs, 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.
Why is this commented out? It used to be there. Is it not needed anymore? (Why?) If so, I'd just remove that line.
filt:=filt and IsCyclic; | ||
fi; | ||
else | ||
filt:=filt and IsTrivial and HasIsNonTrivial; |
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.
Since we now have implications IsTrivial => HasIsNonTrivial and IsNonTrivial => HasIsTrivial I'd kind of prefer if this line (and similar ones throughout this PR) were changed to e.g. filt:=filt and IsTrivial
-- I find that much easier to grok; indeed, several times when reading through this PR did I misread a HasIsTrivial
/ IsTrivial
/ HasIsNonTrivial
/ IsNonTrivial
@@ -15,4 +15,4 @@ gap> G:=GroupByGenerators( [ [ [ 0, -1, 0, 0 ], [ 1, 0, 0, 0 ], | |||
Group([ [ [ 0, -1, 0, 0 ], [ 1, 0, 0, 0 ], [ 0, 0, 0, -1 ], [ 0, 0, 1, 0 ] ] | |||
]) | |||
gap> Centralizer(N,G); | |||
<matrix group of size infinity with 6 generators> | |||
<matrix group with 6 generators> |
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.
Interesting. Do you by chance know why we don't know that this centralize is infinite anymore?
This is an attempt to resolve #2386. It changes group generation that many immediate methods are not triggered any longer, and removes immediate methods that are taken care off by the creation process or that have small payoff.
See the commit text for detailled description.
Note that it will require #2429 which was requested to be taken out (and might not test cleanly without)