Skip to content

Commit 290b261

Browse files
author
Release Manager
committed
gh-38986: Allow CRT_list() to be called with one argument As in the title. Opinion: should we allow `crt()` / `CRT()` to be called with one list also? Note that currently it is callable with two lists and does the exact same thing as `CRT_list()`. Opinion: is returning `Mod(0, 1)` for empty list a sane idea? Problem is later we may want to implement (pseudocode) ```python CRT_list([mod(x-1, x^2+1), mod(x+1, x^2-1)]) ``` and in that case the correct thing to return is not clear when the list is empty. More generally, if it's given elements `x₁ ∈ R/I₁, …, xₙ ∈ R/Iₙ` where `Iᵢ = xᵢ.parent().defining_ideal()` and all `R = xᵢ.parent()` are the same for all `i`, it should returns `x ∈ R/(I₁.intersection(I₂).intersection(I₃).….intersection(Iₙ))`. But this is not well-defined when `values` is empty. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. (not aware of one) - [x] I have created tests covering the changes. - [x] I have updated the documentation and checked the documentation preview. URL: #38986 Reported by: user202729 Reviewer(s): Travis Scrimshaw, user202729
2 parents 0a278fc + 7f199f2 commit 290b261

File tree

1 file changed

+52
-11
lines changed

1 file changed

+52
-11
lines changed

src/sage/arith/misc.py

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,7 +1841,6 @@ def gcd(a, b=None, **kwargs):
18411841
except TypeError:
18421842
return m(py_scalar_to_element(b), **kwargs)
18431843

1844-
from sage.structure.sequence import Sequence
18451844
seq = Sequence(py_scalar_to_element(el) for el in a)
18461845
if seq.universe() is ZZ:
18471846
return GCD_list(seq)
@@ -3498,11 +3497,16 @@ def crt(a, b, m=None, n=None):
34983497
CRT = crt
34993498

35003499

3501-
def CRT_list(values, moduli):
3502-
r""" Given a list ``values`` of elements and a list of corresponding
3500+
def CRT_list(values, moduli=None):
3501+
r"""
3502+
Given a list ``values`` of elements and a list of corresponding
35033503
``moduli``, find a single element that reduces to each element of
35043504
``values`` modulo the corresponding moduli.
35053505
3506+
This function can also be called with one argument, each element
3507+
of the list is a :mod:`modular integer <sage.rings.finite_rings.integer_mod>`.
3508+
In this case, it returns another modular integer.
3509+
35063510
.. SEEALSO::
35073511
35083512
- :func:`crt`
@@ -3529,6 +3533,13 @@ def CRT_list(values, moduli):
35293533
...
35303534
ValueError: no solution to crt problem since gcd(180,150) does not divide 92-1
35313535
3536+
Call with one argument::
3537+
3538+
sage: x = CRT_list([mod(2,3),mod(3,5),mod(2,7)]); x
3539+
23
3540+
sage: x.parent()
3541+
Ring of integers modulo 105
3542+
35323543
The arguments must be lists::
35333544
35343545
sage: CRT_list([1,2,3],"not a list")
@@ -3564,6 +3575,21 @@ def CRT_list(values, moduli):
35643575
sage: CRT_list([mpz(2),mpz(3),mpz(2)], [mpz(3),mpz(5),mpz(7)])
35653576
23
35663577
3578+
Tests for call with one argument::
3579+
3580+
sage: x = CRT_list([mod(2,3)]); x
3581+
2
3582+
sage: x.parent()
3583+
Ring of integers modulo 3
3584+
sage: x = CRT_list([]); x
3585+
0
3586+
sage: x.parent()
3587+
Ring of integers modulo 1
3588+
sage: x = CRT_list([2]); x
3589+
Traceback (most recent call last):
3590+
...
3591+
TypeError: if one argument is given, it should be a list of IntegerMod
3592+
35673593
Make sure we are not mutating the input lists::
35683594
35693595
sage: xs = [1,2,3]
@@ -3575,14 +3601,26 @@ def CRT_list(values, moduli):
35753601
sage: ms
35763602
[5, 7, 9]
35773603
"""
3578-
if not isinstance(values, list) or not isinstance(moduli, list):
3604+
if not isinstance(values, list) or (moduli is not None and not isinstance(moduli, list)):
35793605
raise ValueError("arguments to CRT_list should be lists")
3580-
if len(values) != len(moduli):
3581-
raise ValueError("arguments to CRT_list should be lists of the same length")
3582-
if not values:
3583-
return ZZ.zero()
3584-
if len(values) == 1:
3585-
return moduli[0].parent()(values[0])
3606+
return_mod = moduli is None
3607+
if return_mod:
3608+
from sage.rings.finite_rings.integer_mod import IntegerMod_abstract, Mod
3609+
if not values:
3610+
return Mod(0, 1)
3611+
if not all(isinstance(v, IntegerMod_abstract) for v in values):
3612+
raise TypeError("if one argument is given, it should be a list of IntegerMod")
3613+
if len(values) == 1:
3614+
return values[0]
3615+
moduli = [v.modulus() for v in values]
3616+
values = [v.lift() for v in values]
3617+
else:
3618+
if len(values) != len(moduli):
3619+
raise ValueError("arguments to CRT_list should be lists of the same length")
3620+
if not values:
3621+
return ZZ.zero()
3622+
if len(values) == 1:
3623+
return moduli[0].parent()(values[0])
35863624

35873625
# The result is computed using a binary tree. In typical cases,
35883626
# this scales much better than folding the list from one side.
@@ -3593,7 +3631,10 @@ def CRT_list(values, moduli):
35933631
vs[i] = CRT(vs[i], v, ms[i], m)
35943632
ms[i] = lcm(ms[i], m)
35953633
values, moduli = vs, ms
3596-
return values[0] % moduli[0]
3634+
if return_mod:
3635+
return Mod(values[0], moduli[0])
3636+
else:
3637+
return values[0] % moduli[0]
35973638

35983639

35993640
def CRT_basis(moduli):

0 commit comments

Comments
 (0)