-
Notifications
You must be signed in to change notification settings - Fork 59
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
Modules over Nemo.ZZ fail due to divrem/div definitions #842
Comments
It goes without saying that this issue could hit anyone at any time (and probably does already without them knowing it). It has nothing to do with modules per se. |
If all goes well time-wise, I intend to close this issue today, unless there is an absolute uproar about what I proposed. I strongly believe this is an important issue, perhaps the one thing that bugs me the most about Nemo. I am not intent on (*) if there are objections. I will not personally do (**) as the owners of the Oscar package will want to do what works for them. The point (***) would need a central location for developer documentation/decisions. [We have had many "canonical" places for such decisions to be written up, none of which I can now recall the URL's for. We should decide on a single canonical place (I suggest in the actual documentation of Nemo and/or Oscar, whichever is more appropriate for the particular issue, as this is where other developers will actually look, instead of some random collaborative pad, a wiki, meeting minutes, random text files, on the oscar-dev list, GitHub tickets, a blog, the Oscar website, group emails or worse still in a purely verbal agreement, etc. I'm not personally opposed to a PEP system, so long as it gets written up somewhere that is accessible from the documentation and doesn't make use of a technology here today and gone tomorrow.)] |
Does this mean Base.div(::fmpz, ::fmpz) and Nemo.div(::fmpz, ::fmpz) are different? So in Nemo and in the REPL the behaviors are different? This makes working with the only useful integer type that we have more cumbersome, just to cope with some questionable design desicions for BigInt, which no one should use anyway. We should make working with Nemo types more easy, not more complicated. If we need a different function, just give it a different name. But having this subtle difference between To emphasize: Apparently, the people who invented these methods of Edit: If not a different function name, how about a keyword argument or something like that. |
Oh dear. Sorry, but I am not going to go over this for the hundredth time. div behaves differently in AbstractAlgebra and Base already. div and divrem are made to agree with each other in AbstractAlgebra, and this is required for the generic code to work. This has nothing to do with Modules. This bug will hit you in many different places. If we go with your definition, we will have to change EVERY div and divrem in AbstractAlgebra, Nemo, Oscar to div(a, b, true). The definition must agree with what Flint does for division with remainder, and we cannot rewrite Flint from scratch just because Julia has an inconsistency. |
Why didn't you complain about this before I implemented it? Or on one of the many other tickets where I have painstakingly gone through all our options? |
Can you point me to the issue where we agreed on this "fix"? |
The main problem is that we try to use julia Are we really going to make Nemo experience worse at the REPL by requiring people to do Nemo.div(a, b) instead of div(a, b)? |
In AbstractAlgebra. It was already fixed there. We've been using different internal versions of a number of functions that Julia messes up for ages. All I'm doing here is rolling that change out to Nemo. I even went to the trouble of finding an explicit bug that is caused by it (one of many I am sure). Here is one ticket where we discussed many permutations of things that could fix the div/rem/mod/divrem issues (there are others): Nemocas/AbstractAlgebra.jl#101 There simply aren't any other workable solutions. I've exhausted myself trying to find one! |
You can export the Nemo version if you want, but it won't match Base. That means AbstractAlgebra and Nemo will behave differently for the user. If that's what you want, I'll make the change. Or, as I offered above a few days ago, we can not export it at all. The only thing I care about is that the definition of div and divrem inside Nemo match the definitions inside AbstractAlgebra, so that the generic code in AbstractAlgebra works with the Nemo integer type, AND so that it matches what Flint is doing everywhere, so I don't have to rewrite most of Flint. The other option is to rename div and divrem EVERYWHERE to something else, e.g. quo and quorest (you can't use quo and quorem because rem does not agree with the definition that we require). If you have a better idea, let's hear it, but it would have been much better to bring it up months ago, before we changed AbstractAlgebra. |
This has nothing to do with BigInt! The definition for BigInt does NOT match the definition we use everywhere in AbstractAlgebra, which is the definition Flint uses. The problem is, it doesn't match what Nemo uses (internally) hence the bugs. That's precisely what I'm trying to fix. I can't change how Julia handles BigInt's outside of AbstractAlgebra, but we have changed it so it is usable inside AbstractAlgebra. Are we really going to go back and change everything all over again because now after months you suddenly don't like it again!? |
Here are your three options:
All three options suck. But the one that is consistent with how we've changed AbstractAlgebra, and which requires the least rewriting of code is the one I picked, namely 3. I really don't like 2 because no one wants to use a CAS where the Euclidean quotient and remainder functions are named something bizarre. |
Just to make sure, inside Nemo So the only annoyance is that inside Nemo, for (P.S.: Exporting |
For your first question: sort of. If you are doing div of anything other than fmpz integers, yes. If you are doing div of integers, it now uses the definition that is the same as the one used inside AbstractAlgebra and internally in Flint, which it wasn't before. So it does change the behaviour of div for fmpz inside Nemo. The answer to your second question is yes. But as I said, I don't care what behaviour you pick for the REPL. It can be the same or different or nonexistent. I just chose what would give exactly the same behaviour as AbstractAlgebra currently has (which we have no choice about, as it depends on what Julia does in Base). As for your P.S. yes, correct, we cannot export the "better" definitions or the user will be greeted with unhappiness. |
Great. This means that I think what I meant to say is that we have no choice for my second question. |
No, we have a choice. You can choose to make the Base definition for fmpz match the Nemo definition. It just won't match what Base does for its own integers at the REPL (and hence won't match the behaviour of AbstractAlgebra). I am not 100% sure my choice is the better one on that issue. We can certainly change this in the future if we decide it is the wrong choice. However, we've lived with this in AbstractAlgebra for ages now and so far it seems to work, so I am cautiously optimistic. |
For completeness, here is another discussion we had on the same issue, basically going back and forth over the same things and not really reaching a workable conclusion. I don't suggest re-reading it now. Most of what is there is just wrong. The later ticket is "more correct", but still incorrect. I'm only giving it here for future reference. I think there is another somewhere, where I spelled out all our options and what is wrong with each of them. I'll try to find it, but so far am having some trouble doing so. |
This is related, including for completeness: |
I found the other "discussion" we had (basically me explaining over and over the same points in different ways). It was an email discussion. I reproduce part of it here (with some modifications so it flows better), since it is not otherwise online (I have made sure there are no personal details). I have added emphasis ******* at one point below: I decided to have a look at #699 To remind you of the problem, so you don't have to read all that:
My reasoning in #699 is that if we eventually want to have a At first this seemed like a simple task. All I have to do is remove In fact the only place in AbstractAlgebra where we define a mod The problem is the tests fail. There are two places where we really
In HNF we currently have the nice property that HNF is unique over Z. There's clearly no way to fix all this. Obviously in every ring other than Z we can just set rem and mod to do This all strongly argues for continuing to do all Euclidean divisions But I have no idea what we do for the general Euclidean interface from We can't use div, rem and divrem for the reasons I outlined above. Of course Euclidean division doesn't require a unique set of We have two choices:
(Actually, accessing them via Oscar.blah might not be a good idea Obviously the first option above is bad and impractical. The second is A third option would be to define a hacked version of rem over Z in The reason this is pointless is Julia also defines invmod and we have But just for fun: julia> using Nemo julia> invmod(-2, -3) # julia's invmod, defined in terms of mod it seems julia> invmod(ZZ(-2), ZZ(-3)) # Nemo's I've no idea if that is good or bad. The upshot of all of this is we are going to have to use I guess in Oscar we can just import the AbstractAlgebra definitions of Actually, what I said above isn't correct either. Whilst we have a Inside Nemo we use the Nemo definitions of div and divrem, which agree It's just luck that this hasn't happened to us so far in any critical Even over Z/nZ for multiprecision n we'd be using Flint's fmpz_mod for At the present moment I can't see any way to trip up Nemo by making it We will of course have the same problem in Oscar. I think the only strictly correct way of doing things would be to Then Oscar could internally import both the internal Hecke would have to do the same thing, i.e. not import div and divrem The biggest risk would be code in Nemo/Hecke/Oscar that is written for I can't think of a way to modify the Oscar documentation to make a Actually, this is not a good example: "The biggest risk would be code in Nemo/Hecke/Oscar that is written for Of course if you lifted from Z/nZ to Z the result would actually be It's actually hard to come up with a situation where you would end up I found an example. The invariant factors function snf is generic for So the following test function for modules over ZZ fails if you use julia> for R in [ZZ, QQ]
Test Failed at REPL[17]:13 I will open a ticket explaining the issue. Then we can decide if we I think I have a very simple way to explain the problem so that it is
Quite obviously, people write code based on Nemo with the assumption The only way to fix this is precisely what I proposed. Internal to There's no way you can make a system consistent if it changes the Some additional comments:
After this the discussion wandered into other (private) matters and various other irrelevancies. |
Sorry for being a bit slow yesterday and rehashing the discussion. I agree with all you say and the fix you propose is the right approach. I am also not 100% sure if is better to have |
The disadvantage of the first option is obviously that it may confuse people when debugging their code. They run something in the REPL and it gives different results to what is happening in the library. The disadvantage of the second option is inconsistency with Julia and AbstractAlgebra which is not so nice for people using the system from the REPL. I'm not sold on either solution, but at least the one I've chosen is consistent with something and easy to remember. But yeah, we can change it later if we want. It's not that critical from my perspective. One thing the discussion yesterday highlights though is that we need a much better system for making proposals, updating proposals based on new considerations, making decisions and altering decisions if we come back to them later and feel that we've changed our minds. @fingolfin has mentioned maybe using a PEP-like approach. But I think we should only use it for critical/breaking decisions on which there is not an obvious way forward that we agree on. And I think we should never make arbitrary decisions, but should instead let a preliminary decision sit for a while until everyone has forgotten about it, then revisit it to make a final decision. And of course a decision should only be made once the pros and cons are fully understood. In some cases a PEP should come with some prototype code. And as we've already discovered, PEP's should only be written when there is some chance of them being accepted. The problem with the divrem/div stuff is I've been trying very hard to fix it for ages, but kept learning new reasons why my proposed approaches would not work. This got very confusing over a period of months, and eventually everyone got sick of it and perhaps even tuned out. So when it came time to make a decision, no one paid any attention. I therefore assumed no one really cared enough to complain. There's much more div/divrem/mod/rem craziness still to come, but I think this is the last change where there are no perfect options. Most of the rest of the stuff has to do with consistency on when we raise exceptions, which at least @fieker and I seem to have been agreeing on. This div/divrem change is also the last really urgent change. If we left it much longer, we'd never be able to fix it. |
Some time next week I will try to see what breakage there is in Hecke, Singular and Oscar in the event this is merged in the future. I know some of the tests in Oscar will fail. But these can probably be removed and put into Nemo anyway. I plan to significantly improve the Nemo tests and docs in the coming months. People can choose to cut'n'paste them for Oscar if they want. That's fine by me. But most of the low level docs and tests actually belong in the low level code, I think. Oscar really just needs to test that things are working mathematically the way the Oscar developers actually want them to work. They shouldn't have to test the functionality to see if it is broken or consistent, etc. That should be the job of the people writing the lower level code in the first place. |
Don't worry about Hecke. I will take care of it. |
Ok. |
AbstractAlgebra internally defines div/divrem differently to Julia for Julia integer types (to agree with mod not rem, so that there's a minimal set of representatives mod n).
This means that the AbstractAlgebra tests for modules over ZZ will pass, but when they are run for modules over ZZ using Nemo, they will fail, as Nemo does not internally define div/divrem in the same way AbstractAlgebra does, but continues to use the Julia definitions.
The test is taken from AbstractAlgebra's test/generic/InvariantFactorDecomposition-test.jl.
The correct fix for this is not to define div/divrem for fmpz differently to Julia (we already agreed they should concur with Julia's definition) but to do the following:
The text was updated successfully, but these errors were encountered: