Ask Your Question
1

Error when calling CRT with list of 1 python int

asked 0 years ago

shpark gravatar image

I noticed that calling CRT with list of 1 python int causes error, while calling multiple python ints is allowed. Is it considered as a bug related to sage Integer and native int?

sage: CRT([1], [2])
1
sage: CRT([int(1), int(1)], [int(2), int(3)])
1
sage: CRT([int(1)], [int(2)])
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[7], line 1
----> 1 CRT([int(Integer(1))], [int(Integer(2))])

File ~/anaconda3/envs/sage/lib/python3.12/site-packages/sage/arith/misc.py:3476, in crt(a, b, m, n)
   3355 r"""
   3356 Return a solution to a Chinese Remainder Theorem problem.
   3357 
   (...)
   3473     58
   3474 """
   3475 if isinstance(a, list):
-> 3476     return CRT_list(a, b)
   3478 try:
   3479     f = (b - a).quo_rem

File ~/anaconda3/envs/sage/lib/python3.12/site-packages/sage/arith/misc.py:3624, in CRT_list(values, moduli)
   3622         return ZZ.zero()
   3623     if len(values) == 1:
-> 3624         return moduli[0].parent()(values[0])
   3626 # The result is computed using a binary tree. In typical cases,
   3627 # this scales much better than folding the list from one side.
   3628 from sage.arith.functions import lcm

AttributeError: 'int' object has no attribute 'parent'
Preview: (hide)

Comments

Please report the issue at https://github.com/sagemath/sage/issues

Max Alekseyev gravatar imageMax Alekseyev ( 0 years ago )

1 Answer

Sort by » oldest newest most voted
0

answered 0 years ago

slelievre gravatar image

One way to fix that would be, in the file

to replace calls such as xx.parent() with parent(xx).

One would need to make sure this does not slow things down. If it does, then maybe first trying xx.parent(), and then, if that fails, parent(xx), would mitigate the slowdown.

To make things work now, start with the following and then run your code.

from sage.structure.coerce import py_scalar_to_element
from sage.arith.misc import XGCD


def CRT_list(values, moduli=None):
    r"""
    Given a list ``values`` of elements and a list of corresponding
    ``moduli``, find a single element that reduces to each element of
    ``values`` modulo the corresponding moduli.

    This function can also be called with one argument, each element
    of the list is a :mod:`modular integer <sage.rings.finite_rings.integer_mod>`.
    In this case, it returns another modular integer.

    .. SEEALSO::

        - :func:`crt`

    EXAMPLES::

        sage: CRT_list([2,3,2], [3,5,7])
        23
        sage: x = polygen(QQ)
        sage: c = CRT_list([3], [x]); c
        3
        sage: c.parent()
        Univariate Polynomial Ring in x over Rational Field

    It also works if the moduli are not coprime::

        sage: CRT_list([32,2,2],[60,90,150])
        452

    But with non coprime moduli there is not always a solution::

        sage: CRT_list([32,2,1],[60,90,150])
        Traceback (most recent call last):
        ...
        ValueError: no solution to crt problem since gcd(180,150) does not divide 92-1

    Call with one argument::

        sage: x = CRT_list([mod(2,3),mod(3,5),mod(2,7)]); x
        23
        sage: x.parent()
        Ring of integers modulo 105

    The arguments must be lists::

        sage: CRT_list([1,2,3],"not a list")
        Traceback (most recent call last):
        ...
        ValueError: arguments to CRT_list should be lists
        sage: CRT_list("not a list",[2,3])
        Traceback (most recent call last):
        ...
        ValueError: arguments to CRT_list should be lists

    The list of moduli must have the same length as the list of elements::

        sage: CRT_list([1,2,3],[2,3,5])
        23
        sage: CRT_list([1,2,3],[2,3])
        Traceback (most recent call last):
        ...
        ValueError: arguments to CRT_list should be lists of the same length
        sage: CRT_list([1,2,3],[2,3,5,7])
        Traceback (most recent call last):
        ...
        ValueError: arguments to CRT_list should be lists of the same length

    TESTS::

        sage: CRT([32r,2r,2r],[60r,90r,150r])
        452
        sage: from numpy import int8                                                    # needs numpy
        sage: CRT_list([int8(2), int8(3), int8(2)], [int8(3), int8(5), int8(7)])        # needs numpy
        23
        sage: from gmpy2 import mpz
        sage: CRT_list([mpz(2),mpz(3),mpz(2)], [mpz(3),mpz(5),mpz(7)])
        23

    Tests for call with one argument::

        sage: x = CRT_list([mod(2,3)]); x
        2
        sage: x.parent()
        Ring of integers modulo 3
        sage: x = CRT_list([]); x
        0
        sage: x.parent()
        Ring of integers modulo 1
        sage: x = CRT_list([2]); x
        Traceback (most recent call last):
        ...
        TypeError: if one argument is given, it should be a list of IntegerMod

    Make sure we are not mutating the input lists::

        sage: xs = [1,2,3]
        sage: ms = [5,7,9]
        sage: CRT_list(xs, ms)
        156
        sage: xs
        [1, 2, 3]
        sage: ms
        [5, 7, 9]
    """
    if not isinstance(values, list) or (moduli is not None and not isinstance(moduli, list)):
        raise ValueError("arguments to CRT_list should be lists")
    return_mod = moduli is None
    if return_mod:
        from sage.rings.finite_rings.integer_mod import IntegerMod_abstract, Mod
        if not values:
            return Mod(0, 1)
        if not all(isinstance(v, IntegerMod_abstract) for v in values):
            raise TypeError("if one argument is given, it should be a list of IntegerMod")
        if len(values) == 1:
            return values[0]
        moduli = [v.modulus() for v in values]
        values = [v.lift() for v in values]
    else:
        assert moduli is not None
        if len(values) != len(moduli):
            raise ValueError("arguments to CRT_list should be lists of the same length")
        if not values:
            return ZZ.zero()
        if len(values) == 1:
            return parent(moduli[0])(values[0])

    # The result is computed using a binary tree. In typical cases,
    # this scales much better than folding the list from one side.
    from sage.arith.functions import lcm
    while len(values) > 1:
        vs, ms = values[::2], moduli[::2]
        for i, (v, m) in enumerate(zip(values[1::2], moduli[1::2])):
            vs[i] = CRT(vs[i], v, ms[i], m)
            ms[i] = lcm(ms[i], m)
        values, moduli = vs, ms
    if return_mod:
        return Mod(values[0], moduli[0])
    else:
        return values[0] % moduli[0]


def crt(a, b, m=None, n=None):
    r"""
    Return a solution to a Chinese Remainder Theorem problem.

    INPUT:

    - ``a``, ``b`` -- two residues (elements of some ring for which
      extended gcd is available), or two lists, one of residues and
      one of moduli

    - ``m``, ``n`` -- (default: ``None``) two moduli, or ``None``

    OUTPUT:

    If ``m``, ``n`` are not ``None``, returns a solution `x` to the
    simultaneous congruences `x\equiv a \bmod m` and `x\equiv b \bmod
    n`, if one exists. By the Chinese Remainder Theorem, a solution to the
    simultaneous congruences exists if and only if
    `a\equiv b\pmod{\gcd(m,n)}`. The solution `x` is only well-defined modulo
    `\text{lcm}(m,n)`.

    If ``a`` and ``b`` are lists, returns a simultaneous solution to
    the congruences `x\equiv a_i\pmod{b_i}`, if one exists.

    .. SEEALSO::

        - :func:`CRT_list`

    EXAMPLES:

    Using ``crt`` by giving it pairs of residues and moduli::

        sage: crt(2, 1, 3, 5)
        11
        sage: crt(13, 20, 100, 301)
        28013
        sage: crt([2, 1], [3, 5])
        11
        sage: crt([13, 20], [100, 301])
        28013

    You can also use upper case::

        sage: c = CRT(2,3, 3, 5); c
        8
        sage: c % 3 == 2
        True
        sage: c % 5 == 3
        True

    Note that this also works for polynomial rings::

        sage: # needs sage.rings.number_field
        sage: x = polygen(ZZ, 'x')
        sage: K.<a> = NumberField(x^3 - 7)
        sage: R.<y> = K[]
        sage: f = y^2 + 3
        sage: g = y^3 - 5
        sage: CRT(1, 3, f, g)
        -3/26*y^4 + 5/26*y^3 + 15/26*y + 53/26
        sage: CRT(1, a, f, g)
        (-3/52*a + 3/52)*y^4 + (5/52*a - 5/52)*y^3 + (15/52*a - 15/52)*y + 27/52*a + 25/52

    You can also do this for any number of moduli::

        sage: # needs sage.rings.number_field
        sage: K.<a> = NumberField(x^3 - 7)
        sage: R.<x> = K[]
        sage: CRT([], [])
        0
        sage: CRT([a], [x])
        a
        sage: f = x^2 + 3
        sage: g = x^3 - 5
        sage: h = x^5 + x^2 - 9
        sage: k = CRT([1, a, 3], [f, g, h]); k
        (127/26988*a - 5807/386828)*x^9 + (45/8996*a - 33677/1160484)*x^8
         + (2/173*a - 6/173)*x^7 + (133/6747*a - 5373/96707)*x^6
         + (-6/2249*a + 18584/290121)*x^5 + (-277/8996*a + 38847/386828)*x^4
         + (-135/4498*a + 42673/193414)*x^3 + (-1005/8996*a + 470245/1160484)*x^2
         + (-1215/8996*a + 141165/386828)*x + 621/8996*a + 836445/386828
        sage: k.mod(f)
        1
        sage: k.mod(g)
        a
        sage: k.mod(h)
        3

    If the moduli are not coprime, a solution may not exist::

        sage: crt(4, 8, 8, 12)
        20
        sage: crt(4, 6, 8, 12)
        Traceback (most recent call last):
        ...
        ValueError: no solution to crt problem since gcd(8,12) does not divide 4-6

        sage: x = polygen(QQ)
        sage: crt(2, 3, x - 1, x + 1)
        -1/2*x + 5/2
        sage: crt(2, x, x^2 - 1, x^2 + 1)
        -1/2*x^3 + x^2 + 1/2*x + 1
        sage: crt(2, x, x^2 - 1, x^3 - 1)
        Traceback (most recent call last):
        ...
        ValueError: no solution to crt problem since gcd(x^2 - 1,x^3 - 1) does not divide 2-x

        sage: crt(int(2), int(3), int(7), int(11))
        58

    crt also work with numpy and gmpy2 numbers::

        sage: import numpy                                                              # needs numpy
        sage: crt(numpy.int8(2), numpy.int8(3), numpy.int8(7), numpy.int8(11))          # needs numpy
        58
        sage: from gmpy2 import mpz
        sage: crt(mpz(2), mpz(3), mpz(7), mpz(11))
        58
        sage: crt(mpz(2), 3, mpz(7), numpy.int8(11))                                    # needs numpy
        58
    """
    if isinstance(a, list):
        return CRT_list(a, b)

    try:
        f = (b - a).quo_rem
    except (TypeError, AttributeError):
        # Maybe there is no coercion between a and b.
        # Maybe (b-a) does not have a quo_rem attribute
        a = py_scalar_to_element(a)
        b = py_scalar_to_element(b)
        f = (b - a).quo_rem

    g, alpha, beta = XGCD(m, n)
    q, r = f(g)
    if r != 0:
        raise ValueError("no solution to crt problem since gcd(%s,%s) does not divide %s-%s" % (m, n, a, b))
    from sage.arith.functions import lcm

    x = a + q * alpha * py_scalar_to_element(m)
    return x % lcm(m, n)


CRT = crt
Preview: (hide)
link

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 0 years ago

Seen: 82 times

Last updated: May 06