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

reproducible test failure in master: iroot() requires 'mpz','int' arguments #18374

Open
gschintgen opened this issue Jan 18, 2020 · 8 comments
Open

Comments

@gschintgen
Copy link
Contributor

I now have a 100% reproducible local test failure with master:

python3 bin/test test_evalf
=========================================================== test process starts ===========================================================executable:         /usr/bin/python3  (3.6.8-final-0) [CPython]
architecture:       64-bit
cache:              yes
ground types:       gmpy 2.0.8
numpy:              None
random seed:        24739579
hash randomization: on (PYTHONHASHSEED=809980769)

sympy/core/tests/test_evalf.py[54] ...E..f.f.............................................                                            [FAIL]
____________________________________________________________________________________________________________________________________________
____________________________________________ sympy/core/tests/test_evalf.py:test_evalf_powers _____________________________________________Traceback (most recent call last):
  File "/root/sympy/sympy/core/cache.py", line 96, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/root/sympy/sympy/core/power.py", line 313, in __new__
    obj = b._eval_power(e)
  File "/root/sympy/sympy/core/numbers.py", line 2350, in _eval_power
    x, xexact = integer_nthroot(abs(self.p), expt.q)
  File "/root/sympy/sympy/core/power.py", line 75, in integer_nthroot
    x, t = gmpy.iroot(y, n)
TypeError: iroot() requires 'mpz','int' arguments

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/root/sympy/sympy/core/tests/test_evalf.py", line 47, in test_evalf_powers
    assert NS('2**(1/10**50)', 15) == '1.00000000000000'
  File "/root/sympy/sympy/core/tests/test_evalf.py", line 17, in NS
    return sstr(sympify(e).evalf(n, **options), full_prec=True)
  File "/root/sympy/sympy/core/sympify.py", line 381, in sympify
    expr = parse_expr(a, local_dict=locals, transformations=transformations, evaluate=evaluate)
  File "/root/sympy/sympy/parsing/sympy_parser.py", line 1008, in parse_expr
    return eval_expr(code, local_dict, global_dict)
  File "/root/sympy/sympy/parsing/sympy_parser.py", line 903, in eval_expr
    code, global_dict, local_dict)  # take local objects in preference
  File "<string>", line 1, in <module>
  File "/root/sympy/sympy/core/expr.py", line 212, in __pow__
    return self._pow(other)
  File "/root/sympy/sympy/core/decorators.py", line 253, in _func
    return func(self, other)
  File "/root/sympy/sympy/core/decorators.py", line 129, in binary_op_wrapper
    return func(self, other)
  File "/root/sympy/sympy/core/expr.py", line 208, in _pow
    return Pow(self, other)
  File "/root/sympy/sympy/core/cache.py", line 98, in wrapper
    retval = func(*args, **kwargs)
  File "/root/sympy/sympy/core/power.py", line 313, in __new__
    obj = b._eval_power(e)
  File "/root/sympy/sympy/core/numbers.py", line 2350, in _eval_power
    x, xexact = integer_nthroot(abs(self.p), expt.q)
  File "/root/sympy/sympy/core/power.py", line 75, in integer_nthroot
    x, t = gmpy.iroot(y, n)
TypeError: iroot() requires 'mpz','int' arguments

I suppose this has been introduced by #18276.
Ping @Smit-create @asmeurer

@oscarbenjamin
Copy link
Contributor

I can reproduce this. I have gmpy2 installed. It looks like evalf isn't tested in the optional dependency tests so I guess it isn't tested with gmpy2:

test_list = [

I think it's maybe a bug in gmpy2 since it only happens for large integers:

>>> import gmpy2 as gmpy
>>> gmpy.iroot(4, 2)
(mpz(2), True)
>>> gmpy.iroot(4, 200000000000)
(mpz(1), False)
>>> gmpy.iroot(4, 20000000000000)
(mpz(1), False)
>>> gmpy.iroot(4, 2000000000000000)
(mpz(1), False)
>>> gmpy.iroot(4, 200000000000000000)
(mpz(1), False)
>>> gmpy.iroot(4, 200000000000000000000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iroot() requires 'mpz','int' arguments

The cutoff seems to be 2**63:

>>> gmpy.iroot(4, 2**63)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iroot() requires 'mpz','int' arguments
>>> gmpy.iroot(4, 2**63-1)
(mpz(1), False)

Converting to mpz doesn't seem to help:

>>> gmpy.iroot(gmpy.mpz(4), gmpy.mpz(2**63))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iroot() requires 'mpz','int' arguments

Testing with gmpy (version 1, rather than gmpy2) I find that there is no iroot function and there are loads of test failures:

$ bin/test test_evalf
============================================================= test process starts =============================================================
executable:         /Users/enojb/current/sympy/sympy/tmpvenv_gmpy1/bin/python  (3.8.1-final-0) [CPython]
architecture:       64-bit
cache:              yes
ground types:       gmpy 1.17
numpy:              None
random seed:        32249799
hash randomization: on (PYTHONHASHSEED=3706881222)

sympy/core/tests/test_evalf.py[54] .E.E..fEf..EEEEEE.EEE.....E....E.EE.E.EE......EE...EEE                                                [FAIL]
...
AttributeError: module 'gmpy' has no attribute 'iroot'

I guess that there are three issues here:

  1. There is a bug in gmpy which should be reported to them
  2. The function only exists in gmpy2 so there should be a HAS_GMPY >= 2 check.
  3. There is no usable version of iroot in any gmpy so at least for the time being we should not use it.

@Smit-create
Copy link
Member

Smit-create commented Jan 18, 2020

I also found that we must check that the argument must be less than 2**63,
Also for different version of gmpy we have,
for gmpy version 1.17

>>> import gmpy
>>> gmpy.root(16, 2)
(mpz(4), 1)

for gmpy2

>>> import gmpy2
>>> gmpy2.iroot(16, 2)
(mpz(4), True)

Therefore for HAS_GMPY>=2 we should go for iroot and for HAS_GMPY==1 we should go for root and a check of argument range can fix. I on am trying to fix this and will correct it soon.

@Smit-create
Copy link
Member

I tried to fix it in the PR and now it passed the test locally

@asmeurer
Copy link
Member

We might have to add the whole test suite to the optional dependency build as we include gmpy in more of the core.

@Smit-create
Copy link
Member

I have added the test suite of the core to optional dependency.

@Smit-create
Copy link
Member

I have opened an issue in gmpy2 related to this sympy issue here.

@Smit-create
Copy link
Member

Update on gmpy issue(comment).

@tornaria
Copy link

tornaria commented Mar 28, 2022

This is still broken in 32 bit, since ULONG_MAX is 2**32-1 (cf aleaxit/gmpy#257 (comment))

In [1]: integer_nthroot(2, 10**10)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [1], in <cell line: 1>()
----> 1 integer_nthroot(2, 10**10)

File /builddir/sympy-1.10/sympy/core/power.py:82, in integer_nthroot(y, n)
     77 if HAS_GMPY and n < 2**63:
     78     # Currently it works only for n < 2**63, else it produces TypeError
     79     # sympy issue: https://github.com/sympy/sympy/issues/18374
     80     # gmpy2 issue: https://github.com/aleaxit/gmpy/issues/257
     81     if HAS_GMPY >= 2:
---> 82         x, t = gmpy.iroot(y, n)
     83     else:
     84         x, t = gmpy.root(y, n)

ValueError: n must be > 0

In [2]: integer_nthroot(2, 2**32-1)
Out[2]: (1, False)

Note that in 64 bit gmpy2.iroot works ok up to 2**64-1.

Maybe the simplest fix is to just try gmpy.iroot(y, n) and catch ValueError (and maybe TypeError and later OverflowError if gmpy2 is changed to raise that), instead of guessing what's the max value handled by iroot, as in

        try:
            x, t = gmpy.iroot(y, n)
        except ValueError:
            return _integer_nthroot_python(y, n)
        return as_int(x), bool(t)

Alternatively, use 2**(8*ctypes.sizeof(ctypes.c_ulong)) instead of 2**63.

Edit: this was already broken in 1.9, but in 1.10 this gives failures in the testsuite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants