For certain values, astropy.units.allclose does not match numpy.allclose
The I/O to be the same, excepting unit considerations.
When comparing two numbers where the first array has elements very close to 0 and the second array is all zeros, numpy allclose works as expected, but units.allclose returns False, regardless of "rtol"
>>> import numpy as np
>>> np.allclose([1e-17, 0, 0], [0, 0, 0], rtol=1e-5)
True
>>> import astropy.units as u
>>> u.allclose([1e-17, 0, 0] * u.m, [0, 0, 0] * u.m, rtol=1e-5)
False
macOS-10.15.7-x86_64-i386-64bit
Python 3.8.2 | packaged by conda-forge | (default, Apr 24 2020, 07:56:27)
[Clang 9.0.1 ]
Numpy 1.18.4
astropy 4.2.dev877+g4eef52a1c
Scipy 1.4.1
Matplotlib 3.2.1
This isn't actually a bug, but a conceptual difference between how allclose can operate on unit-less and unit-ful input. As the docstring of numpy.allclose notes:
If the following equation is element-wise True, then allclose returns True.
absolute(a - b) <= (atol + rtol * absolute(b))
In numpy.allclose, atol=1e-8 (by default) because there can be a truly absolute comparison without having to scale the inputs. In the case of astropy.units.allclose, there is no natural way to set atol because it will depend on units. If you look at the call signatures of the two functions, you'll see that atol=None in astropy.units.allclose. If you set atol in the units case, you get the same results:
>>> u.allclose([1e-17, 0, 0] * u.m, [0, 0, 0] * u.m, rtol=1e-5, atol=1e-8*u.m)
True
@nstarman Would it have helped you if there was an explicit note about this in the docstring of astropy.units.allclose?
That would be very useful. The explanation you wrote above would've been perfect.
Most helpful comment
This isn't actually a bug, but a conceptual difference between how
allclosecan operate on unit-less and unit-ful input. As the docstring ofnumpy.allclosenotes:In
numpy.allclose,atol=1e-8(by default) because there can be a truly absolute comparison without having to scale the inputs. In the case ofastropy.units.allclose, there is no natural way to setatolbecause it will depend on units. If you look at the call signatures of the two functions, you'll see thatatol=Noneinastropy.units.allclose. If you setatolin the units case, you get the same results: