diff options
-rw-r--r-- | numpy/lib/arraysetops.py | 26 | ||||
-rw-r--r-- | numpy/lib/tests/test_arraysetops.py | 44 |
2 files changed, 61 insertions, 9 deletions
diff --git a/numpy/lib/arraysetops.py b/numpy/lib/arraysetops.py index 8ae00aeae..7597866a4 100644 --- a/numpy/lib/arraysetops.py +++ b/numpy/lib/arraysetops.py @@ -516,12 +516,13 @@ def setxor1d(ar1, ar2, assume_unique=False): return aux[flag[1:] & flag[:-1]] -def _in1d_dispatcher(ar1, ar2, assume_unique=None, invert=None): +def _in1d_dispatcher(ar1, ar2, assume_unique=None, invert=None, + _slow_integer=None): return (ar1, ar2) @array_function_dispatch(_in1d_dispatcher) -def in1d(ar1, ar2, assume_unique=False, invert=False): +def in1d(ar1, ar2, assume_unique=False, invert=False, _slow_integer=None): """ Test whether each element of a 1-D array is also present in a second array. @@ -544,6 +545,10 @@ def in1d(ar1, ar2, assume_unique=False, invert=False): False where an element of `ar1` is in `ar2` and True otherwise). Default is False. ``np.in1d(a, b, invert=True)`` is equivalent to (but is faster than) ``np.invert(in1d(a, b))``. + _slow_integer : bool/None, optional + If True, defaults to the old algorithm for integers. This is + used for debugging and testing purposes. The default, None, + selects the best based on estimated performance. .. versionadded:: 1.8.0 @@ -603,7 +608,7 @@ def in1d(ar1, ar2, assume_unique=False, invert=False): integer_arrays = (np.issubdtype(ar1.dtype, np.integer) and np.issubdtype(ar2.dtype, np.integer)) - if integer_arrays: + if integer_arrays and _slow_integer in [None, False]: ar2_min = np.min(ar2) ar2_max = np.max(ar2) ar2_size = ar2.size @@ -624,7 +629,7 @@ def in1d(ar1, ar2, assume_unique=False, invert=False): optimal_parameters = False # Use the fast integer algorithm - if optimal_parameters: + if optimal_parameters or _slow_integer == False: if invert: outgoing_array = np.ones_like(ar1, dtype=np.bool_) @@ -690,12 +695,14 @@ def in1d(ar1, ar2, assume_unique=False, invert=False): return ret[rev_idx] -def _isin_dispatcher(element, test_elements, assume_unique=None, invert=None): +def _isin_dispatcher(element, test_elements, assume_unique=None, invert=None, + _slow_integer=None): return (element, test_elements) @array_function_dispatch(_isin_dispatcher) -def isin(element, test_elements, assume_unique=False, invert=False): +def isin(element, test_elements, assume_unique=False, invert=False, + _slow_integer=None): """ Calculates ``element in test_elements``, broadcasting over `element` only. Returns a boolean array of the same shape as `element` that is True @@ -717,6 +724,10 @@ def isin(element, test_elements, assume_unique=False, invert=False): calculating `element not in test_elements`. Default is False. ``np.isin(a, b, invert=True)`` is equivalent to (but faster than) ``np.invert(np.isin(a, b))``. + _slow_integer : bool/None, optional + If True, defaults to the old algorithm for integers. This is + used for debugging and testing purposes. The default, None, + selects the best based on measured performance. Returns ------- @@ -790,7 +801,8 @@ def isin(element, test_elements, assume_unique=False, invert=False): """ element = np.asarray(element) return in1d(element, test_elements, assume_unique=assume_unique, - invert=invert).reshape(element.shape) + invert=invert, _slow_integer=_slow_integer + ).reshape(element.shape) def _union1d_dispatcher(ar1, ar2): diff --git a/numpy/lib/tests/test_arraysetops.py b/numpy/lib/tests/test_arraysetops.py index 707c84101..8de1cee6f 100644 --- a/numpy/lib/tests/test_arraysetops.py +++ b/numpy/lib/tests/test_arraysetops.py @@ -204,8 +204,8 @@ class TestSetOps: return a in b isin_slow = np.vectorize(_isin_slow, otypes=[bool], excluded={1}) - def assert_isin_equal(a, b): - x = isin(a, b) + def assert_isin_equal(a, b, old_algorithm=None): + x = isin(a, b, _slow_integer=old_algorithm) y = isin_slow(a, b) assert_array_equal(x, y) @@ -213,28 +213,39 @@ class TestSetOps: a = np.arange(24).reshape([2, 3, 4]) b = np.array([[10, 20, 30], [0, 1, 3], [11, 22, 33]]) assert_isin_equal(a, b) + assert_isin_equal(a, b, old_algorithm=True) # array-likes as both arguments c = [(9, 8), (7, 6)] d = (9, 7) assert_isin_equal(c, d) + assert_isin_equal(c, d, old_algorithm=True) # zero-d array: f = np.array(3) assert_isin_equal(f, b) assert_isin_equal(a, f) assert_isin_equal(f, f) + assert_isin_equal(f, b, old_algorithm=True) + assert_isin_equal(a, f, old_algorithm=True) + assert_isin_equal(f, f, old_algorithm=True) # scalar: assert_isin_equal(5, b) assert_isin_equal(a, 6) assert_isin_equal(5, 6) + assert_isin_equal(5, b, old_algorithm=True) + assert_isin_equal(a, 6, old_algorithm=True) + assert_isin_equal(5, 6, old_algorithm=True) # empty array-like: x = [] assert_isin_equal(x, b) assert_isin_equal(a, x) assert_isin_equal(x, x) + assert_isin_equal(x, b, old_algorithm=True) + assert_isin_equal(a, x, old_algorithm=True) + assert_isin_equal(x, x, old_algorithm=True) def test_in1d(self): # we use two different sizes for the b array here to test the @@ -246,16 +257,22 @@ class TestSetOps: ec = np.array([True, False, True, True]) c = in1d(a, b, assume_unique=True) assert_array_equal(c, ec) + c = in1d(a, b, assume_unique=True, _slow_integer=True) + assert_array_equal(c, ec) a[0] = 8 ec = np.array([False, False, True, True]) c = in1d(a, b, assume_unique=True) assert_array_equal(c, ec) + c = in1d(a, b, assume_unique=True, _slow_integer=True) + assert_array_equal(c, ec) a[0], a[3] = 4, 8 ec = np.array([True, False, True, False]) c = in1d(a, b, assume_unique=True) assert_array_equal(c, ec) + c = in1d(a, b, assume_unique=True, _slow_integer=True) + assert_array_equal(c, ec) a = np.array([5, 4, 5, 3, 4, 4, 3, 4, 3, 5, 2, 1, 5, 5]) b = [2, 3, 4] * mult @@ -263,36 +280,48 @@ class TestSetOps: False, True, False, False, False] c = in1d(a, b) assert_array_equal(c, ec) + c = in1d(a, b, _slow_integer=True) + assert_array_equal(c, ec) b = b + [5, 5, 4] * mult ec = [True, True, True, True, True, True, True, True, True, True, True, False, True, True] c = in1d(a, b) assert_array_equal(c, ec) + c = in1d(a, b, _slow_integer=True) + assert_array_equal(c, ec) a = np.array([5, 7, 1, 2]) b = np.array([2, 4, 3, 1, 5] * mult) ec = np.array([True, False, True, True]) c = in1d(a, b) assert_array_equal(c, ec) + c = in1d(a, b, _slow_integer=True) + assert_array_equal(c, ec) a = np.array([5, 7, 1, 1, 2]) b = np.array([2, 4, 3, 3, 1, 5] * mult) ec = np.array([True, False, True, True, True]) c = in1d(a, b) assert_array_equal(c, ec) + c = in1d(a, b, _slow_integer=True) + assert_array_equal(c, ec) a = np.array([5, 5]) b = np.array([2, 2] * mult) ec = np.array([False, False]) c = in1d(a, b) assert_array_equal(c, ec) + c = in1d(a, b, _slow_integer=True) + assert_array_equal(c, ec) a = np.array([5]) b = np.array([2]) ec = np.array([False]) c = in1d(a, b) assert_array_equal(c, ec) + c = in1d(a, b, _slow_integer=True) + assert_array_equal(c, ec) assert_array_equal(in1d([], []), []) @@ -382,6 +411,8 @@ class TestSetOps: a = np.array([5, 4, 5, 3, 4, 4, 3, 4, 3, 5, 2, 1, 5, 5]) b = [2, 3, 4] * mult assert_array_equal(np.invert(in1d(a, b)), in1d(a, b, invert=True)) + assert_array_equal(np.invert(in1d(a, b)), + in1d(a, b, invert=True, _slow_integer=True)) for mult in (1, 10): a = np.array([5, 4, 5, 3, 4, 4, 3, 4, 3, 5, 2, 1, 5, 5], @@ -389,6 +420,8 @@ class TestSetOps: b = [2, 3, 4] * mult b = np.array(b, dtype=np.float32) assert_array_equal(np.invert(in1d(a, b)), in1d(a, b, invert=True)) + assert_array_equal(np.invert(in1d(a, b)), + in1d(a, b, invert=True, _slow_integer=True)) def test_in1d_ravel(self): # Test that in1d ravels its input arrays. This is not documented @@ -402,10 +435,15 @@ class TestSetOps: assert_array_equal(in1d(a, b, assume_unique=False), ec) assert_array_equal(in1d(a, long_b, assume_unique=True), ec) assert_array_equal(in1d(a, long_b, assume_unique=False), ec) + assert_array_equal(in1d(a, b, assume_unique=True, _slow_integer=True), ec) + assert_array_equal(in1d(a, b, assume_unique=False, _slow_integer=True), ec) + assert_array_equal(in1d(a, long_b, assume_unique=True, _slow_integer=True), ec) + assert_array_equal(in1d(a, long_b, assume_unique=False, _slow_integer=True), ec) def test_in1d_hit_alternate_algorithm(self): """Hit the standard isin code with integers""" # Need extreme range to hit standard code + # This hits it without the use of _slow_integer a = np.array([5, 4, 5, 3, 4, 4, 1e9], dtype=np.int64) b = np.array([2, 3, 4, 1e9], dtype=np.int64) expected = np.array([0, 1, 0, 1, 1, 1, 1], dtype=np.bool) @@ -424,7 +462,9 @@ class TestSetOps: b = np.array([False, False, False]) expected = np.array([False, True]) assert_array_equal(expected, in1d(a, b)) + assert_array_equal(expected, in1d(a, b, _slow_integer=True)) assert_array_equal(np.invert(expected), in1d(a, b, invert=True)) + assert_array_equal(np.invert(expected), in1d(a, b, invert=True, _slow_integer=True)) def test_in1d_first_array_is_object(self): ar1 = [None] |