Skip to content

Added code to calculate crt for non-coprime moduli in Integer #39716

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

Merged
merged 8 commits into from
Apr 29, 2025

Conversation

Noel-Roemmele
Copy link
Contributor

Related to issue #32487. Added code to compute crt in Integer when the two moduli are not coprime. Also changed error produced when a solution does not exist. Error message is based of the error message found in the crt method in src\sage\arith\misc.py.

📝 Checklist

  • The title is concise and informative.
  • The description explains in detail what this PR is about.
  • I have linked a relevant issue or discussion.
  • I have created tests covering the changes.
  • I have updated the documentation and checked the documentation preview.

⌛ Dependencies

Copy link

github-actions bot commented Mar 16, 2025

Documentation preview for this PR (built with commit 46f74e1; changes) is ready! 🎉
This preview will update shortly after each push to this PR.

@DaveWitteMorris
Copy link
Member

In line 6965, you need to change mn to lcm(m,n) (but in latex mode). I think you have two options:

  1. Change mn to \\lcm(m,n)
  2. Add r just before """ at the start of the previous line (to make it a raw string), and change mn to \lcm(m,n)

In line 6978, you need double-backticks, not single-backticks, around crt.

In line 6995, please change <> to !=.

I think line 6996 will be more readable if you use an f-string to create the error message: f"no solution to crt problem since gcd({_m},{_n}) does not divide {self} - {_y}"

This is very minor, but you reversed the order of _m and _n at the end of line 6997 and I think it would be better not to do that, since there is no need to change the order: _m.lcm(_n) is slightly better than _n.lcm(_m).

@Noel-Roemmele
Copy link
Contributor Author

@DaveWitteMorris I've made the changes suggested. I also added the modulo _m.lcm(_n) to the case where m and n are co-prime as we changed the documentation to specify that. Let me know if I should change it back.

@Noel-Roemmele
Copy link
Contributor Author

@DaveWitteMorris I think that no more changes are required for this PR. If you could set it to positive review that would be great!

@DaveWitteMorris
Copy link
Member

Looks good, but I think it would be better to get rid of the nested if statements at line 7007:

-        if not g.is_one():
-            if (self % g) != (_y % g):
-                raise ValueError(f"no solution to crt problem since gcd({_m},{_n}) does not divide {self} - {_y}")
+        if not g.is_one() and ((self % g) != (_y % g)):
+            raise ValueError(f"no solution to crt problem since gcd({_m},{_n}) does not divide {self} - {_y}")
         return (self + g * Integer(0).crt((_y - self) // g, _m // g, _n // g)) % _m.lcm(_n)

Also, I think the raise ValueError and return lines (and also line 6978 ["Return the unique integer ..."]) are over 80 characters, so need to be shortened.

Checking not g.is_one() is logically redundant, but I agree that you should keep it, because the most important case is when this evaluates to False, so that should be kept as fast as possible.

I think the CI errors are probably not related to this PR, but I will need to run make ptestlong if they show up again in the next run.

@Noel-Roemmele
Copy link
Contributor Author

@DaveWitteMorris I don't really understand your comment. Firstly you can't really get rid of the nested if statement that easily as the line return (self + g * Integer(0).crt((_y - self) // g, _m // g, _n // g)) % _m.lcm(_n) can only be run if g is not one and an answer exists. if you were to leave this line of code outside of the check for if g is not one then it will always be run even when g = 1 which would be incorrect.

I am also not sure why not g.is_one() is faster? We must evaluate g.is_one() each time we compute crt as we are unsure which case we are in.

I have removed the double if statement and fixed the line length issue in my newest commit. Let me know if my changes make sense. I decided to check if g.is_one() is true and then do that case first.

@DaveWitteMorris
Copy link
Member

Sorry, I misread the code when I suggested getting rid of the nested ifs. Your edit to get rid of it is good.

@DaveWitteMorris
Copy link
Member

My comment about speed was just that I would expect checking g.is_one() to be much faster than checking (self % g) != (_y % g), so we want to avoid doing the longer calculation when it's not necessary (i.e., when g.is_one() is True).

@DaveWitteMorris
Copy link
Member

I ran doctests locally and got no errors, so the CI failure does not seem to be caused by this ticket.

@vbraun vbraun merged commit b36120d into sagemath:develop Apr 29, 2025
19 of 21 checks passed
@Noel-Roemmele Noel-Roemmele deleted the 32487NonCoprimeCRTInteger branch May 2, 2025 04:49
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.

3 participants