sagemath / sage

Main repository of SageMath
https://www.sagemath.org
Other
1.33k stars 453 forks source link

Strange warnings from numpy/matplotlib when sage is built with clang #22799

Closed kiwifb closed 7 years ago

kiwifb commented 7 years ago

Seen with clang+OS X and freeBSD+clang

sage -t --long src/doc/en/prep/Calculus.rst  # 1 doctest failed
sage -t --long src/sage/plot/graphics.py  # 1 doctest failed
sage -t --long src/sage/plot/plot.py  # 1 doctest failed
sage -t --long src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx  # 1 doctest failed
sage -t --long src/sage/structure/coerce.pyx  # 1 doctest failed

All these doctest fail because an unexpected warning is emitted:

File "src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx", line 21, in sage.rings.polynomial.polynomial_real_mpfr_dense
Failed example:
    numpy.float32('1.5') * x
Expected:
    1.50000000000000*x
Got:
    doctest:warning
      File "/usr/home/dima/Sage/sage/src/bin/sage-runtests", line 89, in <module>
        err = DC.run()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/control.py", line 1134, in run
        self.run_doctests()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/control.py", line 858, in run_doctests
        self.dispatcher.dispatch()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 1705, in dispatch
        self.parallel_dispatch()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 1595, in parallel_dispatch
        w.start()  # This might take some time
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 1871, in start
        super(DocTestWorker, self).start()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/multiprocessing/process.py", line 130, in start
        self._popen = Popen(self)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/multiprocessing/forking.py", line 126, in __init__
        code = process_obj._bootstrap()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
        self.run()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 1844, in run
        task(self.options, self.outtmpfile, msgpipe, self.result_queue)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 2137, in __call__
        runner.run(test)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 641, in run
        return self._run(test, compileflags, out)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 503, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 866, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.rings.polynomial.polynomial_real_mpfr_dense[7]>", line 1, in <module>
        numpy.float32('1.5') * x
    :
    RuntimeWarning: invalid value encountered in multiply
    1.50000000000000*x

More specifically, the warning is emitted by the call

sage: x=polygen(RR)
sage: numpy.float32('1.5') * x

seen on freeBSD+clang, OS X+clang and linux+clang.

Similarly, the warning is emitted in

sage: numpy.float64(5)>e

or >= instead of >, or pi instead of e. Note that pi.n() and e.n() are of type RR, so again it points at the direction on mpfr.

Depends on #22582

Upstream: Fixed upstream, but not in a stable release.

CC: @dimpase @jhpalmieri

Component: porting

Author: François Bissey, Dima Pasechnik, Paul Zimmermann

Branch/Commit: fd29778

Reviewer: John Palmieri, Dima Pasechnik

Issue created by migration from https://trac.sagemath.org/ticket/22799

kiwifb commented 7 years ago
comment:1

Both polynomial_real_mpfr_dense.pyx and coerce.py are the same test - more or less

        sage: import numpy
        sage: x = polygen(RR)
        sage: numpy.float32('1.5') * x
        1.50000000000000*x
        sage: x * numpy.float32('1.5')
        1.50000000000000*x

There are references to #8426 and #18076.

kiwifb commented 7 years ago
comment:2

As I suspected, both warning ultimately originate from inside numpy. The multiply warning comes from numpy/core/tests/test_datetime.py??? And greater_equal from numpy/lib/tests/test_nanfunctions.py, comparison with NaN.

jhpalmieri commented 7 years ago
comment:4

I tried to compare the build logs for numpy (on OS X) using gcc vs. clang. I found a few errors or warnings in the clang build that are not present in the gcc build. For example:

numpy/core/src/multiarray/datetime.c:781:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
    if (out_meta->base == -1) {
        ~~~~~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:1847:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
    if (out_meta->base == -1) {
        ~~~~~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:1976:20: warning: comparison of unsigned enum expression >= 0 is always true [-Wtautological-compare]
    if (meta->base >= 0 && meta->base < (NPY_FR_GENERIC + 1)) {
        ~~~~~~~~~~ ^  ~
numpy/core/src/multiarray/datetime.c:2395:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2411:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1 || meta->base == NPY_FR_GENERIC) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2424:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2463:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2495:28: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
            if (meta->base == -1) {
                ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2522:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2598:28: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
            if (meta->base == -1) {
                ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2609:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2622:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2661:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2730:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:2784:24: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
        if (meta->base == -1) {
            ~~~~~~~~~~ ^  ~~
numpy/core/src/multiarray/datetime.c:3118:26: warning: comparison of constant -1 with expression of type 'NPY_DATETIMEUNIT' is always false [-Wtautological-constant-out-of-range-compare]
    if (inout_meta->base == -1) {
        ~~~~~~~~~~~~~~~~ ^  ~~
16 warnings generated.

There are quite a few warnings in the clang build related to comparisons.

jhpalmieri commented 7 years ago
comment:5

By the way, the page https://www.scipy.org/scipylib/building/macosx.html says that we should use

export FFLAGS=-ff2c

along with the remark 'The Fortran flag “-ff2c” has been reported to be necessary.' We do not do this. Is there any reason to believe that this would help?

kiwifb commented 7 years ago
comment:6

Replying to @jhpalmieri:

By the way, the page https://www.scipy.org/scipylib/building/macosx.html says that we should use

export FFLAGS=-ff2c

along with the remark 'The Fortran flag “-ff2c” has been reported to be necessary.' We do not do this. Is there any reason to believe that this would help?

If we were using g77 for sure it would be necessary. The page itself is dated in my opinion. I'll dig a bit around the compilation warnings, there may be over-optimisation somewhere.

jhpalmieri commented 7 years ago
comment:7

It is at least interesting that we are getting compiler warnings on some of the files related to doctest failures, and furthermore on comparisons.

kiwifb commented 7 years ago
comment:8

Replying to @jhpalmieri:

It is at least interesting that we are getting compiler warnings on some of the files related to doctest failures, and furthermore on comparisons.

It is indeed.

kiwifb commented 7 years ago
comment:9

Just for those wondering: upgrading to numpy 1.12.1 doesn't change a thing.

kiwifb commented 7 years ago
comment:10

I am not sure numpy is the root cause of the problem. I recompiled numpy using x86_64-apple-darwin16.5.0-gcc which is currently installed by gfortran package. I remove gcc, but not more sophisticated names like the above. The error persists. Of course the above compiler is not bootstraped which could have an impact.

However, I am wondering if something funny happens in the coercion framework.

dimpase commented 7 years ago
comment:11

I suspect that the bug is not (only) in coersion, but in numpy's float conversion/truncation module; on FreeBSD/clang I get no warning with numpy.float or numpy.float128, but I do get warnings with numpy.float<k> with k<128:

sage: import numpy as np
sage: x=polygen(RR)
sage: np.float32('1.5')*x
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
1.50000000000000*x
sage: np.float16('1.5')*x
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
1.50000000000000*x
sage: np.float64('1.5')*x
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
1.50000000000000*x
sage: np.float128('1.5')*x
1.50000000000000*x
sage: np.float('1.5')*x
1.50000000000000*x

That's of course still a mystery, and a combination of the fact that it only happens with x coming from RealField() (its precision does not matter, I tried many values, with the same effect).

kiwifb commented 7 years ago
comment:12

Good observation, I had only tried 64.

jdemeyer commented 7 years ago

Replying to @kiwifb:

All these doctest fail because an unexpected warning is emitted:

RuntimeWarning: invalid value encountered in greater_equal

Traceback please (general rule: when posting bug report, never truncate a traceback).

dimpase commented 7 years ago
comment:14

Replying to @jdemeyer:

Replying to @kiwifb:

All these doctest fail because an unexpected warning is emitted:

RuntimeWarning: invalid value encountered in greater_equal

Traceback please (general rule: when posting bug report, never truncate a traceback).

these are very uninformative (it's just a message that comes from the depths of a compiled part of numpy, not causing any interrupts). For instance:

File "src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx", line 21, in sage.rings.polynomial.polynomial_real_mpfr_dense
Failed example:
    numpy.float32('1.5') * x
Expected:
    1.50000000000000*x
Got:
    doctest:warning
      File "/usr/home/dima/Sage/sage/src/bin/sage-runtests", line 89, in <module>
        err = DC.run()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/control.py", line 1134, in run
        self.run_doctests()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/control.py", line 858, in run_doctests
        self.dispatcher.dispatch()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 1705, in dispatch
        self.parallel_dispatch()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 1595, in parallel_dispatch
        w.start()  # This might take some time
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 1871, in start
        super(DocTestWorker, self).start()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/multiprocessing/process.py", line 130, in start
        self._popen = Popen(self)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/multiprocessing/forking.py", line 126, in __init__
        code = process_obj._bootstrap()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
        self.run()
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 1844, in run
        task(self.options, self.outtmpfile, msgpipe, self.result_queue)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 2137, in __call__
        runner.run(test)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 641, in run
        return self._run(test, compileflags, out)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 503, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/usr/home/dima/Sage/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 866, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.rings.polynomial.polynomial_real_mpfr_dense[7]>", line 1, in <module>
        numpy.float32('1.5') * x
    :
    RuntimeWarning: invalid value encountered in multiply
    1.50000000000000*x

It's also pretty hard to extract anything useful at the Sage prompt, I tried to set up a numpy interrupt following numpy docs, but it ends up telling me that the interrupt happends at the top level of ipython.

jdemeyer commented 7 years ago

Description changed:

--- 
+++ 
@@ -10,15 +10,44 @@
 All these doctest fail because an unexpected warning is emitted:

-RuntimeWarning: invalid value encountered in greater_equal -`` -Calculus.rstandgraphics.pythis is frommatplotlib`

-``` +File "src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx", line 21, in sage.rings.polynomial.polynomial_real_mpfr_dense +Failed example:

dimpase commented 7 years ago
comment:16

Could you run numpy tests on clang/OSX? I did so on clang/FreeBSD, with some failures in complex arithmetic/functions (mostly numerical noise, but not only) More precisely:

On FreeBSD I get

Ran 3072 tests in 53.164s
FAILED (KNOWNFAIL=6, SKIP=4, failures=22)

Perhaps we should upgrade to 1.12.1 and see if this helps.

jhpalmieri commented 7 years ago
comment:17

I did ./sage -i nose to install nose, but otherwise followed your instructions. I got

Ran 3072 tests in 47.097s

OK (KNOWNFAIL=6, SKIP=4)

I also got this warning many times:

/Users/palmieri/Desktop/Sage_stuff/sage_builds/TESTING/sage-8.0.beta2/numpy-1.11.1/numpy/core/tests/test_datetime.py:1114: FutureWarning: In the future, NAT != NAT will be True rather than False.
kiwifb commented 7 years ago
comment:18

Replying to @dimpase:

Perhaps we should upgrade to 1.12.1 and see if this helps.

First thing I tried. No changes. But I will try the tests ASAP.

kiwifb commented 7 years ago
comment:19

So numpy-1.12.1

(sage-sh) fbissey@Mirage:tests$ python test*.py
.................................................................................................................................................................................................................................................................................................................................................................................................................................KKK........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................S.................................................................................................................................................................................................................................................................................................................................................S.........................................................................................................................................................................................................................................................................................................K......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................K...SK.S.......S................................................................................
----------------------------------------------------------------------
Ran 3167 tests in 81.934s

OK (KNOWNFAIL=6, SKIP=5)

No warnings.

dimpase commented 7 years ago
comment:20

We're discussing this problem on sage-devel and it appears that Sage does not follow the coercion framework prescription for the case of numpy.float32('1.5')*x, but instead does something that makes numpy unhappy on clang...

jdemeyer commented 7 years ago
comment:21

Replying to @dimpase:

it appears that Sage does not follow the coercion framework prescription for the case of numpy.float32('1.5')*x

This has nothing to do with the coercion framework. When doing a * b, Python usually calls type(a).__mul__(a, b). If a is not a Sage object (as is the case here), then it's the __mul__ method of a which handles this multiplication. Only if this returns NotImplemented, then Python will call type(b).__mul__(a, b).

dimpase commented 7 years ago
comment:22

Replying to @jdemeyer:

Replying to @dimpase:

it appears that Sage does not follow the coercion framework prescription for the case of numpy.float32('1.5')*x

This has nothing to do with the coercion framework. When doing a * b, Python usually calls type(a).__mul__(a, b). If a is not a Sage object (as is the case here), then it's the __mul__ method of a which handles this multiplication. Only if this returns NotImplemented, then Python will call type(b).__mul__(a, b).

Are you saying that the warning comes from type(numpy.float32('1.5')).__mul__() ? OK, this makes sense---I tried this call on clang/FreeBSD and got the warning in question all right. So we know where to look at.

Still, this does not explain why sage.structure.element.coercion_model.explain() lies in this case (or in the case x comes as the 1st argument).

dimpase commented 7 years ago

Description changed:

--- 
+++ 
@@ -51,3 +51,10 @@
     RuntimeWarning: invalid value encountered in multiply
     1.50000000000000*x

+ +More specifically, on FreeBSD the warning is emitted by the call + + +sage: type(numpy.float32('1.5')).__mul__(numpy.float32('1.5'),x) + +

kiwifb commented 7 years ago

Description changed:

--- 
+++ 
@@ -52,9 +52,9 @@
     1.50000000000000*x

-More specifically, on FreeBSD the warning is emitted by the call +More specifically, the warning is emitted by the call

 sage: type(numpy.float32('1.5')).__mul__(numpy.float32('1.5'),x)

- +seen on freeBSD+clang, OS X+clang and linux+clang.

dimpase commented 7 years ago
comment:25

Replying to @kiwifb:

Replying to @dimpase:

Perhaps we should upgrade to 1.12.1 and see if this helps.

First thing I tried. No changes. But I will try the tests ASAP.

by the way, __mul__ is changing in 1.12. On 1.11 I get

sage: import numpy as np
sage: v=np.float32('1.5')
sage: v*"bla"
/home/dima/Sage/sage-dev/src/bin/sage-ipython:1: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
  #!/usr/bin/env python
'bla'

while on 1.12

sage: v*"bla"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-10-f57c3b7020a0> in <module>()
----> 1 v*"bla"

TypeError: 'numpy.float32' object cannot be interpreted as an index
jdemeyer commented 7 years ago
comment:26

Replying to @dimpase:

Still, this does not explain why sage.structure.element.coercion_model.explain() lies in this case

cm.explain() answers what the coercion model would do if asked to perform this multiplication. It doesn't answer what Python does when asked to perform this multiplication.

dimpase commented 7 years ago
comment:27

Replying to @jdemeyer:

Replying to @dimpase:

Still, this does not explain why sage.structure.element.coercion_model.explain() lies in this case

cm.explain() answers what the coercion model would do if asked to perform this multiplication. It doesn't answer what Python does when asked to perform this multiplication.

jdemeyer commented 7 years ago
comment:28

Replying to @dimpase:

  • Do you mean that x*numpy.float32('1.5') does not use coersion, either?

No, that would immediately use the coercion model. If you think that there is a bug with coercion_model.explain() please open a new self-contained bug.

dimpase commented 7 years ago
comment:29

I think that the multiplication in question is done entirely in numpy. (Yes, numpy does have its own polynomial class).

sage: import numpy as np
sage: v=np.float32('1.5')
sage: x=polygen(RealField())
sage: np.multiply(v,x)
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
1.50000000000000*x
sage: np.multiply(x,v)
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
1.50000000000000*x

I have no idea whether RR['x'] was designed to be compatible with numpy's polynomials, or this is a coincidence. More computations:

sage: np.multiply(x^3,x-x^2)
-x^5 + x^4
sage: np.multiply(v+v*x^3,x-x^2)
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in add
  #!/usr/bin/env python
-1.50000000000000*x^5 + 1.50000000000000*x^4 - 1.50000000000000*x^2 + 1.50000000000000*x
sage: np.multiply(v,v)
2.25

this is all for clang/FreeBSD (on Linux with gcc, all of the above passes without warnings).

jdemeyer commented 7 years ago

Description changed:

--- 
+++ 
@@ -55,6 +55,7 @@
 More specifically, the warning is emitted by the call

+sage: TODO what is x sage: type(numpy.float32('1.5')).mul(numpy.float32('1.5'),x)

 seen on freeBSD+clang, OS X+clang and linux+clang.
dimpase commented 7 years ago

Description changed:

--- 
+++ 
@@ -55,7 +55,7 @@
 More specifically, the warning is emitted by the call

-sage: TODO what is x +sage: x=polylog(RR) sage: type(numpy.float32('1.5')).mul(numpy.float32('1.5'),x)

 seen on freeBSD+clang, OS X+clang and linux+clang.
dimpase commented 7 years ago

Description changed:

--- 
+++ 
@@ -55,7 +55,7 @@
 More specifically, the warning is emitted by the call

-sage: x=polylog(RR) +sage: x=polygen(RR) sage: type(numpy.float32('1.5')).mul(numpy.float32('1.5'),x)

 seen on freeBSD+clang, OS X+clang and linux+clang.
jhpalmieri commented 7 years ago

Description changed:

--- 
+++ 
@@ -56,6 +56,6 @@

sage: x=polygen(RR) -sage: type(numpy.float32('1.5')).mul(numpy.float32('1.5'),x) +sage: numpy.float32('1.5') * x

 seen on freeBSD+clang, OS X+clang and linux+clang.
jhpalmieri commented 7 years ago
comment:34

I don't see why the doctest

    sage: numpy.float32('1.5') * x
    1.50000000000000*x

in sage.rings.polynomial.polynomial_real_mpfr_dense should pass in the first place, since no Sage coercion is taking place. Do we need to add some sort of conversion from Sage types to numpy types?

jdemeyer commented 7 years ago
comment:35

Replying to @jhpalmieri:

I don't see why the doctest

    sage: numpy.float32('1.5') * x
    1.50000000000000*x

in sage.rings.polynomial.polynomial_real_mpfr_dense should pass in the first place, since no Sage coercion is taking place.

Wrong. Let me explain what happens:

  1. Python calls type(numpy.float32('1.5')).__mul__(numpy.float32('1.5'), x).

  2. Numpy tries to do this multiplication but realizes that it cannot, so it returns NotImplemented.

  3. Python calls type(x).__mul__(..., ...) which involves the coercion model.

  4. The coercion model knows how to handle this.

So the difference between GCC and Clang almost certainly lies in step 2 above.

jhpalmieri commented 7 years ago
comment:36

In case it helps, I think the RuntimeWarning message comes from line 122 of numpy-1.11.1/numpy/core/src/umath/ufunc_object.c.

jdemeyer commented 7 years ago
comment:37

Hmm, I was not entirely right. The correct sequence looks like:

  1. Python calls type(numpy.float32('1.5')).__mul__(numpy.float32('1.5'), x).

  2. Numpy tries to do this multiplication but realizes that it cannot.

  3. Numpy "coerces" numpy.float32(1.5) to float(1.5) (a Python float) and calls float(1.5) * x instead.

  4. Python realizes that it cannot do this multiplication.

  5. Python calls type(x).__mul__(1.5, x) which is handled by the coercion model.

Still, the difference must be in step 2.

jhpalmieri commented 7 years ago
comment:38

If I apply this patch to numpy, then the failing doctests don't fail any more:

--- a/numpy/core/src/umath/ufunc_object.c   2016-06-25 16:59:40.000000000 -0700
+++ b/numpy/core/src/umath/ufunc_object.c   2017-04-24 13:10:59.000000000 -0700
@@ -120,9 +120,6 @@
     switch(method) {
     case UFUNC_ERR_WARN:
         PyOS_snprintf(msg, sizeof(msg), "%s encountered in %s", errtype, name);
-        if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) {
-            goto fail;
-        }
         break;
     case UFUNC_ERR_RAISE:
         PyErr_Format(PyExc_FloatingPointError, "%s encountered in %s",

This does not explain what's going on, and I don't see a particular reason to think that this is the right solution, but maybe someone who understands Python and/or numpy better might be able to make something productive out of it.

dimpase commented 7 years ago
comment:39

Replying to @jdemeyer:

Hmm, I was not entirely right. The correct sequence looks like:

  1. Python calls type(numpy.float32('1.5')).__mul__(numpy.float32('1.5'), x).

  2. Numpy tries to do this multiplication but realizes that it cannot.

  3. Numpy "coerces" numpy.float32(1.5) to float(1.5) (a Python float) and calls float(1.5) * x instead.

  4. Python realizes that it cannot do this multiplication.

  5. Python calls type(x).__mul__(1.5, x) which is handled by the coercion model.

Still, the difference must be in step 2.

this theory does not work, as step 2 has nothing to do with type(x)---but type(x) matters, as can be seen here:

sage: type(x)
<type 'sage.symbolic.expression.Expression'>
sage: type(numpy.float32('1.5')).__mul__(numpy.float32('1.5'), x)
1.5*x
sage: x=polygen(RDF)
sage: type(numpy.float32('1.5')).__mul__(numpy.float32('1.5'), x)
1.5*x
sage: x=polygen(RR)
sage: type(numpy.float32('1.5')).__mul__(numpy.float32('1.5'), x)
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
1.50000000000000*x
sage: float(1.5)*x
1.50000000000000*x
dimpase commented 7 years ago

Upstream: Reported upstream. No feedback yet.

dimpase commented 7 years ago
comment:40

I have created https://github.com/numpy/numpy/issues/9007

jhpalmieri commented 7 years ago
comment:41

You can't multiply a type by a number, or if you can, I don't know what sort of answer you would expect. Note also that your working example at the end is with float, not numpy.float32. So I claim that your example doesn't make any sense. I get this:

sage: numpy.float32('1.5') * x
/Users/palmieri/Desktop/Sage_stuff/sage_builds/TESTING/sage-8.0.beta3/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
1.50000000000000*x

That is, it just comes from plain multiplication in numpy.

dimpase commented 7 years ago
comment:42

Replying to @jhpalmieri:

You can't multiply a type by a number,

in this case the type has __mul__

sage: import numpy
sage: v=numpy.float32('1.5')
sage: t=type(v)
sage: t.__mul__?
Type:           wrapper_descriptor
String form:    <slot wrapper '__mul__' of 'numpy.generic' objects>
File:           
Docstring:      x.__mul__(y) <==> x*y
...
sage: t.__mul__(v,2)
3.0

of course, in this case this is the same as v*2, just some levels down the code path.

One can unwind it a bit more:

sage: v.__mul__
<method-wrapper '__mul__' of numpy.float32 object at 0x7f4ad5773318>
sage: v.__mul__(2)
3.0
sage: v.__mul__(polygen(RR))
/usr/home/dima/Sage/sage/src/bin/sage-ipython:1: RuntimeWarning: invalid value encountered in multiply
  #!/usr/bin/env python
1.50000000000000*x

by the way, the same warning with __add__ and __sub__.

jhpalmieri commented 7 years ago
comment:43

Right, so isn't

numpy.float32('1.5') * polygen(RR)

a simple illustration of the problem, with no type involved?

dimpase commented 7 years ago
comment:44

Replying to @jhpalmieri:

Right, so isn't

numpy.float32('1.5') * polygen(RR)

a simple illustration of the problem, with no type involved?

it's less clear this way whether or how Sage's coersion is involved.

numpy.float32('1.5').__mul__(polygen(RR))

also does not call type explicitly, and is closer to the end of the codepath of this computation.

jhpalmieri commented 7 years ago
comment:45

First, sorry, I misunderstood about the use of type in the original example. Second, doesn't the problem happen before Sage's coercion? Third, it is not clear how numpy decides whether or not it can do a multiplication (in the language of Jeroen's step 2), so the type of x could very well be relevant there, couldn't it?

Maybe someone who is comfortable with gdb and related tools (= not me) should try the problematic operation in Sage + gcc and also in Sage + clang to see what is happening differently in the two cases.

dimpase commented 7 years ago

Changed upstream from Reported upstream. No feedback yet. to Reported upstream. Developers acknowledge bug.

dimpase commented 7 years ago
comment:46

Numpy devs say a lot on ​https://github.com/numpy/numpy/issues/9007 - that apparently Sage might be setting the FPU flag which is read by numpy, and leads to this warning. Also, they are able to show how to exclude np.float32 and np.float64 types from being under suspicion.

Perhaps we should upgrade to numpy 1.12.1, so that we're all on the same version (I am on 1.12.1)

jdemeyer commented 7 years ago
comment:47

Replying to @jhpalmieri:

You can't multiply a type by a number

Sorry, as Dima said, type(A).__mul__(A, B) is just a contrived way of writing A.__mul__(B). I wrote it with type() because that's closer to what Python internally actually does.

Note that A.__mul__(B) is not the same as A * B: essentially A * B first calls A.__mul__(B). When this returns NotImplemented, Python tries the reversed multiplication.

jhpalmieri commented 7 years ago
comment:48

Replying to @jdemeyer:

Replying to @jhpalmieri:

You can't multiply a type by a number

Sorry, as Dima said, type(A).__mul__(A, B) is just a contrived way of writing A.__mul__(B).

Right, I understand this now, as was vaguely implied in comment:45.

kiwifb commented 7 years ago
comment:49

Replying to @dimpase:

Numpy devs say a lot on ​https://github.com/numpy/numpy/issues/9007 - that apparently Sage might be setting the FPU flag which is read by numpy, and leads to this warning. Also, they are able to show how to exclude np.float32 and np.float64 types from being under suspicion.

Perhaps we should upgrade to numpy 1.12.1, so that we're all on the same version (I am on 1.12.1)

Yes we could make a ticket numpy-1.12.1, we could drop at least one patch and I don't expect anything else to break.

The discussion on the numpy tracker goes in the direction I suspected it would. numpy is issuing the warning because of something happening in sage. I had arrived at that conclusion by recompiling numpy (1.12.1 at the time) with gcc on a full clang install on OS X. And the problem didn't go away, implying something sage-side is happening when compiled with clang.