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

Method order does not change when filter ranks change, leading to subtle conflict between nq and lpres #2513

Closed
fingolfin opened this issue Jun 5, 2018 · 5 comments · Fixed by #2773
Labels
gapdays2018-spring Issues and PRs that arose at http://www.gapdays.de/gap-jupyter-days2018 kind: discussion discussions, questions, requests for comments, and so on

Comments

@fingolfin
Copy link
Member

We recently observed a test failure with the nq tests after LoadAllPackages() had run. Here is the cause:

First off, the lpres package installs another method for NilpotentQuotient but at a slightly lower priority (adjusting the rank by -1):

InstallOtherMethod( NilpotentQuotient,
  "for an FpGroup using the LPRES-package", true,
  [ IsFpGroup, IsPosInt ], -1, # give priority to NQ package
  function( G, c )
  return( NilpotentQuotient( Range( IsomorphismLpGroup( G ) ), c ) );
  end);

If you just load nq and lpres, there is no problem.

But if you first load nq; then load e.g. semigroups, then load lpres, suddenly the lpres method for NilpotentQuotient will be preferred over nq's -- because semigroups installs implications for IsFpGroup, which increases the rank of IsFpGroup, which increases the rank of the above NilpotentQuotient at the moment it is installed...

So a quick workaround would be to change the -1 above to a lower value. In plain GAP, the rank of IsFpGroup right now seems to be 38. After LoadAllPackages it has rank 111; so we'd need at least something like -80 or so to make it "safe", but of course if enough implications for IsFpGroup is installed, any fixed rank adjustment could become too small.

IMHO in this particular case, the proper fix is to just delete that method from lpres - I see no point in it anyway, as no normal user would ever be able to call it that way (at least once the issue reported here has been resolved). Somebody who wants to compare the lpres nq implementation with that in the nq package could / should just use NilpotentQuotient( Range( IsomorphismLpGroup( G ) ), c ). @laurentbartholdi any objections to that?

But this still leaves the underlying issue here, which is is that the rank of filters can change, but we never adjust the rank of methods based on that, once they have been installed, nor their order.

One fix would be to reorder all methods of all operations whenever a new implication is installed, or some variation thereof. Of course this may expose more issues in method installation which used a hard coded rank adjustment. We'd have to adjust them one by one.

@fingolfin fingolfin added request for comments kind: discussion discussions, questions, requests for comments, and so on labels Jun 5, 2018
@stevelinton
Copy link
Contributor

Running over all the methods installed (after starting master with standard packages) there are something like 240 places where the relative rank of methods changes when you call WITH_HIDDEN_IMPS_FLAGS on all the requirements. In most cases it looks like the methods which switch apply to disjoint sets of objects, for instance permutation group methods now rank slightly higher than matrix group methods.

@fingolfin
Copy link
Member Author

Here is another complication: we cannot just iterate over all method and adjust their ranks, because we need to know the original rank adjustment passed to InstallMethod; of course we can record that, but that's not quite enough either, because that value may have been computed, e.g. it may have been -RankFilter(IsFinite).

So, in order to be able to adjust the ranks later on, we'd need a completely new way to specify rank adjustments in such a way that we can recompute the adjustment later on.

@stevelinton
Copy link
Contributor

Ouch. We can record the adjustments, but I think unless we want rewrite every method installation in every package, we will just have to accept that the RankFilter in InstallMethod( <op>, <reqs>, RankFilter(<filt>)) is evaluated at the time the InstallMethod is called. This might, possibly, create some dependencies on package loading order, but it should be a lot rarer than at present.

@stevelinton
Copy link
Contributor

An idea which came up in discussion is to allow a function of no arguments in place of the rank adjustment. This is evaluated to produce the actual rank adjustment, but can be recomputed when method order is being recalculated.

@stevelinton
Copy link
Contributor

stevelinton commented Jun 7, 2018

I've been playing with this in #2521 and I'm no longer sure we even want to fix this issue. If we ensure that method ranking always reflects current implications (and so current filter ranks) then we reach a position where latent bugs (in some sense) in the library can be revealed by a user installing implications (perfectly correctly) which change ranks enough to reorder library methods.

If we do nothing then this issue persists and the relative ranking of a method installed in a package compared to methods in the library or in other packages, may depend on the order in which packages are loaded.

Neither of these is desirable, but I am wondering if the second one isn't the lesser of the two evils. At least the problem arises in relation to a method you have "just" installed, rather than code deep inside the library.

@olexandr-konovalov olexandr-konovalov added the gapdays2018-spring Issues and PRs that arose at http://www.gapdays.de/gap-jupyter-days2018 label Jun 8, 2018
fingolfin pushed a commit to fingolfin/gap that referenced this issue Sep 4, 2018
Many GAP methods get rank adjustments based on the rank of some filter,
e.g, `RankFilter(IsAbelian)`. However, these ranks may change when new
implications are added, e.g. when certain packages are loaded. But those
method rank adjustments then won't be updated, which can ultimately lead
to the effect that loading a package changes which methods get executed
in otherwise identical code.

This PR helps avoid that, by making it possible to set "dynamic" rank
adjustments which get updated as new implications are added. Some cleverness
is needed to make this work efficiently when loading packages.

- Record rank adjustment in METHODS_OPERATION
- Add RECALCULATE_ALL_METHOD_RANKS function which does what it says.
- Adjust MethodsOperation to include base rank
- Increase size of HIDDEN_IMPS_CACHE and WITH_IMPS_CACHE to speed up RECALCULATE_ALL_METHOD_RANKS()
- Make sure RANK_FILTERS is always set promptly, then remove the test for it being unset
  in RankFilter
- Automatically reorder methods after library or package loading, or InstallTrueMethod
- Use COPY_LIST_ENTRIES in method installation to avoid making an intermediate list
- Support passing a function of no arguments as the rank adjustment to InstallMethod
- Reset reordering status on quit from break loop.

Fixes gap-system#2513
fingolfin pushed a commit to fingolfin/gap that referenced this issue Sep 4, 2018
Many GAP methods get rank adjustments based on the rank of some filter,
e.g, `RankFilter(IsAbelian)`. However, these ranks may change when new
implications are added, e.g. when certain packages are loaded. But those
method rank adjustments then won't be updated, which can ultimately lead
to the effect that loading a package changes which methods get executed
in otherwise identical code.

This PR helps avoid that, by making it possible to set "dynamic" rank
adjustments which get updated as new implications are added. Some cleverness
is needed to make this work efficiently when loading packages.

- Record rank adjustment in METHODS_OPERATION
- Add RECALCULATE_ALL_METHOD_RANKS function which does what it says.
- Adjust MethodsOperation to include base rank
- Increase size of HIDDEN_IMPS_CACHE and WITH_IMPS_CACHE to speed up RECALCULATE_ALL_METHOD_RANKS()
- Make sure RANK_FILTERS is always set promptly, then remove the test for it being unset
  in RankFilter
- Automatically reorder methods after library or package loading, or InstallTrueMethod
- Use COPY_LIST_ENTRIES in method installation to avoid making an intermediate list
- Support passing a function of no arguments as the rank adjustment to InstallMethod
- Reset reordering status on quit from break loop.

Fixes gap-system#2513
fingolfin pushed a commit to fingolfin/gap that referenced this issue Sep 7, 2018
Many GAP methods get rank adjustments based on the rank of some filter,
e.g, `RankFilter(IsAbelian)`. However, these ranks may change when new
implications are added, e.g. when certain packages are loaded. But those
method rank adjustments then won't be updated, which can ultimately lead
to the effect that loading a package changes which methods get executed
in otherwise identical code.

This PR helps avoid that, by making it possible to set "dynamic" rank
adjustments which get updated as new implications are added. Some cleverness
is needed to make this work efficiently when loading packages.

- Record rank adjustment in METHODS_OPERATION
- Add RECALCULATE_ALL_METHOD_RANKS function which does what it says.
- Adjust MethodsOperation to include base rank
- Increase size of HIDDEN_IMPS_CACHE and WITH_IMPS_CACHE to speed up RECALCULATE_ALL_METHOD_RANKS()
- Make sure RANK_FILTERS is always set promptly, then remove the test for it being unset
  in RankFilter
- Automatically reorder methods after library or package loading, or InstallTrueMethod
- Use COPY_LIST_ENTRIES in method installation to avoid making an intermediate list
- Support passing a function of no arguments as the rank adjustment to InstallMethod
- Reset reordering status on quit from break loop.

Fixes gap-system#2513
fingolfin pushed a commit to fingolfin/gap that referenced this issue Sep 12, 2018
Many GAP methods get rank adjustments based on the rank of some filter,
e.g, `RankFilter(IsAbelian)`. However, these ranks may change when new
implications are added, e.g. when certain packages are loaded. But those
method rank adjustments then won't be updated, which can ultimately lead
to the effect that loading a package changes which methods get executed
in otherwise identical code.

This PR helps avoid that, by making it possible to set "dynamic" rank
adjustments which get updated as new implications are added. Some cleverness
is needed to make this work efficiently when loading packages.

- Record rank adjustment in METHODS_OPERATION
- Add RECALCULATE_ALL_METHOD_RANKS function which does what it says.
- Adjust MethodsOperation to include base rank
- Increase size of HIDDEN_IMPS_CACHE and WITH_IMPS_CACHE to speed up RECALCULATE_ALL_METHOD_RANKS()
- Make sure RANK_FILTERS is always set promptly, then remove the test for it being unset
  in RankFilter
- Automatically reorder methods after library or package loading, or InstallTrueMethod
- Use COPY_LIST_ENTRIES in method installation to avoid making an intermediate list
- Support passing a function of no arguments as the rank adjustment to InstallMethod
- Reset reordering status on quit from break loop.

Fixes gap-system#2513
fingolfin pushed a commit to fingolfin/gap that referenced this issue Sep 12, 2018
Many GAP methods get rank adjustments based on the rank of some filter,
e.g, `RankFilter(IsAbelian)`. However, these ranks may change when new
implications are added, e.g. when certain packages are loaded. But those
method rank adjustments then won't be updated, which can ultimately lead
to the effect that loading a package changes which methods get executed
in otherwise identical code.

This PR helps avoid that, by making it possible to set "dynamic" rank
adjustments which get updated as new implications are added. Some cleverness
is needed to make this work efficiently when loading packages.

- Record rank adjustment in METHODS_OPERATION
- Add RECALCULATE_ALL_METHOD_RANKS function which does what it says.
- Adjust MethodsOperation to include base rank
- Increase size of HIDDEN_IMPS_CACHE and WITH_IMPS_CACHE to speed up RECALCULATE_ALL_METHOD_RANKS()
- Make sure RANK_FILTERS is always set promptly, then remove the test for it being unset
  in RankFilter
- Automatically reorder methods after library or package loading, or InstallTrueMethod
- Use COPY_LIST_ENTRIES in method installation to avoid making an intermediate list
- Support passing a function of no arguments as the rank adjustment to InstallMethod
- Reset reordering status on quit from break loop.

Fixes gap-system#2513
fingolfin pushed a commit to fingolfin/gap that referenced this issue Sep 12, 2018
Many GAP methods get rank adjustments based on the rank of some filter,
e.g, `RankFilter(IsAbelian)`. However, these ranks may change when new
implications are added, e.g. when certain packages are loaded. But those
method rank adjustments then won't be updated, which can ultimately lead
to the effect that loading a package changes which methods get executed
in otherwise identical code.

This PR helps avoid that, by making it possible to set "dynamic" rank
adjustments which get updated as new implications are added. Some cleverness
is needed to make this work efficiently when loading packages.

- Record rank adjustment in METHODS_OPERATION
- Add RECALCULATE_ALL_METHOD_RANKS function which does what it says.
- Adjust MethodsOperation to include base rank
- Increase size of HIDDEN_IMPS_CACHE and WITH_IMPS_CACHE to speed up RECALCULATE_ALL_METHOD_RANKS()
- Make sure RANK_FILTERS is always set promptly, then remove the test for it being unset
  in RankFilter
- Automatically reorder methods after library or package loading, or InstallTrueMethod
- Use COPY_LIST_ENTRIES in method installation to avoid making an intermediate list
- Support passing a function of no arguments as the rank adjustment to InstallMethod
- Reset reordering status on quit from break loop.

Fixes gap-system#2513
fingolfin pushed a commit that referenced this issue Sep 14, 2018
Many GAP methods get rank adjustments based on the rank of some filter,
e.g, `RankFilter(IsAbelian)`. However, these ranks may change when new
implications are added, e.g. when certain packages are loaded. But those
method rank adjustments then won't be updated, which can ultimately lead
to the effect that loading a package changes which methods get executed
in otherwise identical code.

This PR helps avoid that, by making it possible to set "dynamic" rank
adjustments which get updated as new implications are added. Some cleverness
is needed to make this work efficiently when loading packages.

- Record rank adjustment in METHODS_OPERATION
- Add RECALCULATE_ALL_METHOD_RANKS function which does what it says.
- Adjust MethodsOperation to include base rank
- Increase size of HIDDEN_IMPS_CACHE and WITH_IMPS_CACHE to speed up RECALCULATE_ALL_METHOD_RANKS()
- Make sure RANK_FILTERS is always set promptly, then remove the test for it being unset
  in RankFilter
- Automatically reorder methods after library or package loading, or InstallTrueMethod
- Use COPY_LIST_ENTRIES in method installation to avoid making an intermediate list
- Support passing a function of no arguments as the rank adjustment to InstallMethod
- Reset reordering status on quit from break loop.

Fixes #2513
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gapdays2018-spring Issues and PRs that arose at http://www.gapdays.de/gap-jupyter-days2018 kind: discussion discussions, questions, requests for comments, and so on
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants