summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/2.0.0-notes.rst7
-rw-r--r--numpy/core/numeric.py90
-rw-r--r--numpy/core/src/multiarray/dtype_transfer.c4
-rw-r--r--numpy/core/tests/test_numeric.py124
-rw-r--r--numpy/fft/fftpack.py2
-rw-r--r--numpy/fft/tests/test_fftpack.py12
-rw-r--r--numpy/fft/tests/test_helper.py67
7 files changed, 272 insertions, 34 deletions
diff --git a/doc/release/2.0.0-notes.rst b/doc/release/2.0.0-notes.rst
index defdc9c00..7c2bfa8a5 100644
--- a/doc/release/2.0.0-notes.rst
+++ b/doc/release/2.0.0-notes.rst
@@ -94,6 +94,13 @@ A generic sampling function has been added which will generate samples from
a given array-like. The samples can be with or without replacement, and
with uniform or given non-uniform probabilities.
+New function isclose
+--------------------
+
+Returns a boolean array where two arrays are element-wise equal within a
+tolerance. Both relative and absolute tolerance can be specified. The
+function is NA aware.
+
Preliminary multi-dimensional support in the polynomial package
---------------------------------------------------------------
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
index bb13d573e..846429016 100644
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -12,7 +12,7 @@ __all__ = ['newaxis', 'ndarray', 'flatiter', 'nditer', 'nested_iters', 'ufunc',
'array_repr', 'array_str', 'set_string_function',
'little_endian', 'require',
'fromiter', 'array_equal', 'array_equiv',
- 'indices', 'fromfunction',
+ 'indices', 'fromfunction', 'isclose',
'load', 'loads', 'isscalar', 'binary_repr', 'base_repr',
'ones', 'identity', 'allclose', 'compare_chararrays', 'putmask',
'seterr', 'geterr', 'setbufsize', 'getbufsize',
@@ -2024,6 +2024,94 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8):
y = y[~xinf]
return all(less_equal(absolute(x-y), atol + rtol * absolute(y)))
+def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
+ """
+ Returns a boolean array where two arrays are element-wise equal within a
+ tolerance.
+
+ The tolerance values are positive, typically very small numbers. The
+ relative difference (`rtol` * abs(`b`)) and the absolute difference
+ `atol` are added together to compare against the absolute difference
+ between `a` and `b`.
+
+ Parameters
+ ----------
+ a, b : array_like
+ Input arrays to compare.
+ rtol : float
+ The relative tolerance parameter (see Notes).
+ atol : float
+ The absolute tolerance parameter (see Notes).
+ equal_nan : bool
+ Whether to compare NaN's as equal. If True, NaN's in `a` will be
+ considered equal to NaN's in `b` in the output array.
+
+ Returns
+ -------
+ y : array_like
+ Returns a boolean array of where `a` and `b` are equal within the
+ given tolerance. If both `a` and `b` are scalars, returns a single
+ boolean value.
+
+ See Also
+ --------
+ allclose
+
+ Notes
+ -----
+ .. versionadded:: 1.7.0
+
+ For finite values, isclose uses the following equation to test whether
+ two floating point values are equivalent.
+
+ absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`))
+
+ The above equation is not symmetric in `a` and `b`, so that
+ `isclose(a, b)` might be different from `isclose(b, a)` in
+ some rare cases.
+
+ Examples
+ --------
+ >>> np.isclose([1e10,1e-7], [1.00001e10,1e-8])
+ array([True, False])
+ >>> np.isclose([1e10,1e-8], [1.00001e10,1e-9])
+ array([True, True])
+ >>> np.isclose([1e10,1e-8], [1.0001e10,1e-9])
+ array([False, True])
+ >>> np.isclose([1.0, np.nan], [1.0, np.nan])
+ array([True, False])
+ >>> np.isclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
+ array([True, True])
+ """
+ def within_tol(x, y, atol, rtol):
+ result = less_equal(abs(x-y), atol + rtol * abs(y))
+ if isscalar(a) and isscalar(b):
+ result = bool(result)
+ return result
+ x = array(a, copy=False, subok=True, ndmin=1)
+ y = array(b, copy=False, subok=True, ndmin=1)
+ xfin = isfinite(x)
+ yfin = isfinite(y)
+ if all(xfin, skipna=True) and all(yfin, skipna=True):
+ return within_tol(x, y, atol, rtol)
+ else:
+ finite = xfin & yfin
+ cond = zeros_like(finite, subok=True, maskna=finite.flags.maskna)
+ # Because we're using boolean indexing, x & y must be the same shape.
+ # Ideally, we'd just do x, y = broadcast_arrays(x, y). It's in
+ # lib.stride_tricks, though, so we can't import it here.
+ x = x * ones_like(cond)
+ y = y * ones_like(cond)
+ # Avoid subtraction with infinite/nan values and indexing with na...
+ finite[isna(finite)] = False
+ cond[finite] = within_tol(x[finite], y[finite], atol, rtol)
+ # Check for equality of infinite values...
+ cond[~finite] = (x[~finite] == y[~finite])
+ if equal_nan:
+ # Make NaN == NaN
+ cond[isnan(x) & isnan(y)] = True
+ return cond
+
def array_equal(a1, a2):
"""
True if two arrays have the same shape and elements, False otherwise.
diff --git a/numpy/core/src/multiarray/dtype_transfer.c b/numpy/core/src/multiarray/dtype_transfer.c
index 47c487338..46acd046f 100644
--- a/numpy/core/src/multiarray/dtype_transfer.c
+++ b/numpy/core/src/multiarray/dtype_transfer.c
@@ -3846,9 +3846,9 @@ PyArray_CastRawArrays(npy_intp count,
}
/* Check data alignment */
- aligned = (((npy_intp)src_dtype | src_stride) &
+ aligned = (((npy_intp)src | src_stride) &
(src_dtype->alignment - 1)) == 0 &&
- (((npy_intp)dst_dtype | dst_stride) &
+ (((npy_intp)dst | dst_stride) &
(dst_dtype->alignment - 1)) == 0;
/* Get the function to do the casting */
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
index de41f0c1f..5233d0f88 100644
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -1220,6 +1220,130 @@ class TestAllclose(object):
assert_array_equal(y,array([0,inf]))
+class TestIsclose(object):
+ rtol = 1e-5
+ atol = 1e-8
+
+ def setup(self):
+ atol = self.atol
+ rtol = self.rtol
+ arr = array([100,1000])
+ aran = arange(125).reshape((5,5,5))
+
+ self.all_close_tests = [
+ ([1, 0], [1, 0]),
+ ([atol], [0]),
+ ([1], [1 + rtol + atol]),
+ (arr, arr + arr*rtol),
+ (arr, arr + arr*rtol + atol),
+ (aran, aran + aran*rtol),
+ (inf, inf),
+ (inf, [inf]),
+ ([inf, -inf], [inf, -inf]),
+ ]
+ self.none_close_tests = [
+ ([inf, 0], [1, inf]),
+ ([inf, -inf], [1, 0]),
+ ([inf, inf], [1, -inf]),
+ ([inf, inf], [1, 0]),
+ ([nan, 0], [nan, -inf]),
+ ([atol*2], [0]),
+ ([1], [1 + rtol + atol*2]),
+ (aran, aran + rtol*1.1*aran + atol*1.1),
+ (array([inf, 1]), array([0, inf])),
+ ]
+ self.some_close_tests = [
+ ([inf, 0], [inf, atol*2]),
+ ([atol, 1, 1e6*(1 + 2*rtol) + atol], [0, nan, 1e6]),
+ (arange(3), [0, 1, 2.1]),
+ (nan, [nan, nan, nan]),
+ ([0], [atol, inf, -inf, nan]),
+ (0, [atol, inf, -inf, nan]),
+ ]
+ self.some_close_results = [
+ [True, False],
+ [True, False, False],
+ [True, True, False],
+ [False, False, False],
+ [True, False, False, False],
+ [True, False, False, False],
+ ]
+
+ def test_ip_isclose(self):
+ self.setup()
+ tests = self.some_close_tests
+ results = self.some_close_results
+ for (x, y), result in zip(tests, results):
+ yield (assert_array_equal, isclose(x, y), result)
+
+ def tst_all_isclose(self, x, y):
+ assert_(all(isclose(x, y)), "%s and %s not close" % (x, y))
+
+ def tst_none_isclose(self, x, y):
+ msg = "%s and %s shouldn't be close"
+ assert_(not any(isclose(x, y)), msg % (x, y))
+
+ def tst_isclose_allclose(self, x, y):
+ msg = "isclose.all() and allclose aren't same for %s and %s"
+ assert_array_equal(isclose(x, y).all(), allclose(x, y), msg % (x, y))
+
+ def test_ip_all_isclose(self):
+ self.setup()
+ for (x,y) in self.all_close_tests:
+ yield (self.tst_all_isclose, x, y)
+
+ def test_ip_none_isclose(self):
+ self.setup()
+ for (x,y) in self.none_close_tests:
+ yield (self.tst_none_isclose, x, y)
+
+ def test_ip_isclose_allclose(self):
+ self.setup()
+ tests = (self.all_close_tests + self.none_close_tests +
+ self.some_close_tests)
+ for (x, y) in tests:
+ yield (self.tst_isclose_allclose, x, y)
+
+ def test_equal_nan(self):
+ assert_array_equal(isclose(nan, nan, equal_nan=True), [True])
+ arr = array([1.0, nan])
+ assert_array_equal(isclose(arr, arr, equal_nan=True), [True, True])
+
+ def test_masked_arrays(self):
+ x = np.ma.masked_where([True, True, False], np.arange(3))
+ assert_(type(x) == type(isclose(2, x)))
+
+ x = np.ma.masked_where([True, True, False], [nan, inf, nan])
+ assert_(type(x) == type(isclose(inf, x)))
+
+ x = np.ma.masked_where([True, True, False], [nan, nan, nan])
+ y = isclose(nan, x, equal_nan=True)
+ assert_(type(x) == type(y))
+ # Ensure that the mask isn't modified...
+ assert_array_equal([True, True, False], y.mask)
+
+ def test_maskna_arrays(self):
+ x = array([NA, 1, 2, 3])
+ y = array([0, 1, 2, NA])
+ assert_array_equal(isclose(x, y), array([NA, True, True, NA]))
+
+ assert_array_equal(isclose(NA, arange(3)), array([NA, NA, NA]))
+
+ x = array([NA, nan, 2, 3])
+ y = array([nan, 1, 2, NA])
+ assert_array_equal(isclose(x, y), array([NA, False, True, NA]))
+
+ def test_scalar_return(self):
+ assert_(isscalar(isclose(1, 1)))
+
+ def test_no_parameter_modification(self):
+ x = array([inf, 1])
+ y = array([0, inf])
+ isclose(x, y)
+ assert_array_equal(x, array([inf, 1]))
+ assert_array_equal(y, array([0, inf]))
+
+
class TestStdVar(TestCase):
def setUp(self):
self.A = array([1,-1,1,-1])
diff --git a/numpy/fft/fftpack.py b/numpy/fft/fftpack.py
index 2f19ba3d8..80d21ec1d 100644
--- a/numpy/fft/fftpack.py
+++ b/numpy/fft/fftpack.py
@@ -511,7 +511,7 @@ def _cook_nd_args(a, s=None, axes=None, invreal=0):
if len(s) != len(axes):
raise ValueError("Shape and axes have different lengths.")
if invreal and shapeless:
- s[axes[-1]] = (s[axes[-1]] - 1) * 2
+ s[-1] = (a.shape[axes[-1]] - 1) * 2
return s, axes
diff --git a/numpy/fft/tests/test_fftpack.py b/numpy/fft/tests/test_fftpack.py
index 4f70d3bc5..dceb3bd89 100644
--- a/numpy/fft/tests/test_fftpack.py
+++ b/numpy/fft/tests/test_fftpack.py
@@ -1,18 +1,22 @@
-from numpy.testing import *
+from __future__ import division
+
import numpy as np
+from numpy.testing import TestCase, run_module_suite, assert_array_almost_equal
def fft1(x):
L = len(x)
phase = -2j*np.pi*(np.arange(L)/float(L))
- phase = np.arange(L).reshape(-1,1) * phase
- return np.sum(x*np.exp(phase),axis=1)
+ phase = np.arange(L).reshape(-1, 1) * phase
+ return np.sum(x*np.exp(phase), axis=1)
class TestFFTShift(TestCase):
+
def test_fft_n(self):
- self.assertRaises(ValueError,np.fft.fft,[1,2,3],0)
+ self.assertRaises(ValueError, np.fft.fft, [1, 2, 3], 0)
class TestFFT1D(TestCase):
+
def test_basic(self):
rand = np.random.random
x = rand(30) + 1j*rand(30)
diff --git a/numpy/fft/tests/test_helper.py b/numpy/fft/tests/test_helper.py
index 8ddac931f..c5578d390 100644
--- a/numpy/fft/tests/test_helper.py
+++ b/numpy/fft/tests/test_helper.py
@@ -2,48 +2,63 @@
# Copied from fftpack.helper by Pearu Peterson, October 2005
""" Test functions for fftpack.helper module
"""
+from __future__ import division
-from numpy.testing import *
-from numpy.fft import fftshift,ifftshift,fftfreq
-
+import numpy as np
+from numpy.testing import TestCase, run_module_suite, assert_array_almost_equal
+from numpy import fft
from numpy import pi
-def random(size):
- return rand(*size)
class TestFFTShift(TestCase):
+
def test_definition(self):
- x = [0,1,2,3,4,-4,-3,-2,-1]
- y = [-4,-3,-2,-1,0,1,2,3,4]
- assert_array_almost_equal(fftshift(x),y)
- assert_array_almost_equal(ifftshift(y),x)
- x = [0,1,2,3,4,-5,-4,-3,-2,-1]
- y = [-5,-4,-3,-2,-1,0,1,2,3,4]
- assert_array_almost_equal(fftshift(x),y)
- assert_array_almost_equal(ifftshift(y),x)
+ x = [0, 1, 2, 3, 4, -4, -3, -2, -1]
+ y = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
+ assert_array_almost_equal(fft.fftshift(x), y)
+ assert_array_almost_equal(fft.ifftshift(y), x)
+ x = [0, 1, 2, 3, 4, -5, -4, -3, -2, -1]
+ y = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
+ assert_array_almost_equal(fft.fftshift(x), y)
+ assert_array_almost_equal(fft.ifftshift(y), x)
def test_inverse(self):
for n in [1,4,9,100,211]:
- x = random((n,))
- assert_array_almost_equal(ifftshift(fftshift(x)),x)
-
+ x = np.random.random((n,))
+ assert_array_almost_equal(fft.ifftshift(fft.fftshift(x)), x)
+
def test_axes_keyword(self):
freqs = [[ 0, 1, 2], [ 3, 4, -4], [-3, -2, -1]]
shifted = [[-1, -3, -2], [ 2, 0, 1], [-4, 3, 4]]
- assert_array_almost_equal(fftshift(freqs, axes=(0, 1)), shifted)
- assert_array_almost_equal(fftshift(freqs, axes=0), fftshift(freqs, axes=(0,)))
- assert_array_almost_equal(ifftshift(shifted, axes=(0, 1)), freqs)
- assert_array_almost_equal(ifftshift(shifted, axes=0), ifftshift(shifted, axes=(0,)))
+ assert_array_almost_equal(fft.fftshift(freqs, axes=(0, 1)), shifted)
+ assert_array_almost_equal(fft.fftshift(freqs, axes=0),
+ fft.fftshift(freqs, axes=(0,)))
+ assert_array_almost_equal(fft.ifftshift(shifted, axes=(0, 1)), freqs)
+ assert_array_almost_equal(fft.ifftshift(shifted, axes=0),
+ fft.ifftshift(shifted, axes=(0,)))
class TestFFTFreq(TestCase):
+
def test_definition(self):
- x = [0,1,2,3,4,-4,-3,-2,-1]
- assert_array_almost_equal(9*fftfreq(9),x)
- assert_array_almost_equal(9*pi*fftfreq(9,pi),x)
- x = [0,1,2,3,4,-5,-4,-3,-2,-1]
- assert_array_almost_equal(10*fftfreq(10),x)
- assert_array_almost_equal(10*pi*fftfreq(10,pi),x)
+ x = [0, 1, 2, 3, 4, -4, -3, -2, -1]
+ assert_array_almost_equal(9*fft.fftfreq(9), x)
+ assert_array_almost_equal(9*pi*fft.fftfreq(9, pi), x)
+ x = [0, 1, 2, 3, 4, -5, -4, -3, -2, -1]
+ assert_array_almost_equal(10*fft.fftfreq(10), x)
+ assert_array_almost_equal(10*pi*fft.fftfreq(10, pi), x)
+
+
+class TestIRFFTN(TestCase):
+
+ def test_not_last_axis_success(self):
+ ar, ai = np.random.random((2, 16, 8, 32))
+ a = ar + 1j*ai
+
+ axes = (-2,)
+
+ # Should not raise error
+ fft.irfftn(a, axes=axes)
if __name__ == "__main__":