Skip to content

Commit

Permalink
Closes 3208-Index.equals (Bears-R-Us#3209)
Browse files Browse the repository at this point in the history
Co-authored-by: Amanda Potts <[email protected]>
  • Loading branch information
ajpotts and ajpotts authored May 20, 2024
1 parent 4bb8093 commit e27825d
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 16 deletions.
46 changes: 46 additions & 0 deletions PROTO_tests/tests/index_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,52 @@ def test_inferred_type(self):
m = ak.MultiIndex([ak.arange(size), ak.arange(size) * -1], names=["test", "test2"])
assert m.inferred_type == "mixed"

def assert_equal(self, pda1, pda2):
from arkouda import sum as aksum

assert pda1.size == pda2.size
assert aksum(pda1 != pda2) == 0

def test_eq(self):
i = ak.Index([1, 2, 3])
i_cpy = ak.Index([1, 2, 3])
self.assert_equal(i == i_cpy, ak.array([True, True, True]))
self.assert_equal(i != i_cpy, ak.array([False, False, False]))
assert i.equals(i_cpy)

i2 = ak.Index([1, 2, 3], allow_list=True)
i2_cpy = ak.Index([1, 2, 3], allow_list=True)
self.assert_equal(i2 == i2_cpy, ak.array([True, True, True]))
self.assert_equal(i2 != i2_cpy, ak.array([False, False, False]))
assert i2.equals(i2_cpy)

self.assert_equal(i == i2, ak.array([True, True, True]))
self.assert_equal(i != i2, ak.array([False, False, False]))
assert i.equals(i2)

i3 = ak.Index(["a", "b", "c"], allow_list=True)
i3_cpy = ak.Index(["a", "b", "c"], allow_list=True)
self.assert_equal(i3 == i3_cpy, ak.array([True, True, True]))
self.assert_equal(i3 != i3_cpy, ak.array([False, False, False]))
assert i3.equals(i3_cpy)

i4 = ak.Index(["a", "x", "c"], allow_list=True)
self.assert_equal(i3 == i4, ak.array([True, False, True]))
self.assert_equal(i3 != i4, ak.array([False, True, False]))
assert not i3.equals(i4)

i5 = ak.Index(["a", "b", "c", "d"], allow_list=True)
with pytest.raises(ValueError):
i4 == i5

with pytest.raises(ValueError):
i4 != i5

assert not i4.equals(i5)

with pytest.raises(TypeError):
i.equals("string")

@pytest.mark.parametrize("size", pytest.prob_size)
def test_memory_usage(self, size):
from arkouda.dtypes import BigInt
Expand Down
21 changes: 16 additions & 5 deletions PROTO_tests/tests/operator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,13 @@ def test_bool_bool_addition_binop(self):
ak_x = ak.array(np_x)
ak_y = ak.array(np_y)
# Vector-Vector Case
assert (np_x+np_y).tolist() == (ak_x+ak_y).to_list()
assert (np_x + np_y).tolist() == (ak_x + ak_y).to_list()
# Scalar-Vector Case
assert (np_x[0]+np_y).tolist() == (ak_x[0]+ak_y).to_list()
assert (np_x[-1]+np_y).tolist() == (ak_x[-1]+ak_y).to_list()
assert (np_x[0] + np_y).tolist() == (ak_x[0] + ak_y).to_list()
assert (np_x[-1] + np_y).tolist() == (ak_x[-1] + ak_y).to_list()
# Vector-Scalar Case
assert (np_x+np_y[0]).tolist() == (ak_x+ak_y[0]).to_list()
assert (np_x+np_y[-1]).tolist() == (ak_x+ak_y[-1]).to_list()
assert (np_x + np_y[0]).tolist() == (ak_x + ak_y[0]).to_list()
assert (np_x + np_y[-1]).tolist() == (ak_x + ak_y[-1]).to_list()

def test_bool_bool_addition_opeq(self):
np_x = np.array([True, True, False, False])
Expand Down Expand Up @@ -849,3 +849,14 @@ def type_helper(x):
npf_copy %= 2.14
akf_copy %= 2.14
assert np.allclose(akf_copy.to_ndarray(), npf_copy, equal_nan=True)

def test_equals(self):
size = 10
a1 = ak.arange(size)
a1_cpy = ak.arange(size)
a2 = 2 * ak.arange(size)
a3 = ak.arange(size + 1)

assert a1.equals(a1_cpy)
assert not a1.equals(a2)
assert not a1.equals(a3)
45 changes: 40 additions & 5 deletions arkouda/index.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import json
from typing import TYPE_CHECKING, List, Optional, Union
from typing import TYPE_CHECKING, List, Optional, Union, Tuple

import pandas as pd # type: ignore
from numpy import array as ndarray
Expand Down Expand Up @@ -129,10 +129,32 @@ def __repr__(self):
def __len__(self):
return len(self.index)

def __eq__(self, v):
if isinstance(v, Index):
return self.index == v.index
return self.index == v
def _get_arrays_for_comparison(
self, other
) -> Tuple[Union[pdarray, Strings, Categorical], Union[pdarray, Strings, Categorical]]:
if isinstance(self.values, list):
values = array(self.values)
else:
values = self.values

if isinstance(other, Index):
other_values = other.values
else:
other_values = other

if isinstance(other_values, list):
other_values = array(other_values)
return values, other_values

def __eq__(self, other):
values, other_values = self._get_arrays_for_comparison(other)

return values == other_values

def __ne__(self, other):
values, other_values = self._get_arrays_for_comparison(other)

return values != other_values

def _dtype_of_list_values(self, lst):
from arkouda.dtypes import dtype
Expand Down Expand Up @@ -228,6 +250,19 @@ def from_return_msg(cls, rep_msg):

return cls.factory(idx) if len(idx) > 1 else cls.factory(idx[0])

def equals(self, other: Union[Index, pdarray, Strings, Categorical, list]) -> bool:
if not isinstance(other, (Index, pdarray, Strings, Categorical, list)):
raise TypeError("other must be of type Index, pdarray, Strings, Categorical, list")

if isinstance(other, list) and self.size != len(other):
return False
elif not isinstance(other, list) and self.size != other.size:
return False

from arkouda.pdarrayclass import all as akall

return akall(self == other)

def memory_usage(self, unit="B"):
"""
Return the memory usage of the Index values.
Expand Down
12 changes: 12 additions & 0 deletions arkouda/pdarrayclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,18 @@ def max_bits(self, max_bits):
generic_msg(cmd="set_max_bits", args={"array": self, "max_bits": max_bits})
self._max_bits = max_bits

def equals(self, other) -> bool:
"""
Whether pdarrays are the same size and all entries are equal.
"""
if isinstance(other, pdarray):
if other.size != self.size:
return False
else:
return all(self == other)
else:
return False

def format_other(self, other) -> str:
"""
Attempt to cast scalar other to the element dtype of this pdarray,
Expand Down
37 changes: 37 additions & 0 deletions tests/index_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,43 @@ def test_inferred_type(self):
m = ak.MultiIndex([ak.arange(size), ak.arange(size) * -1], names=["test", "test2"])
self.assertEqual(m.inferred_type, "mixed")

def assert_equal(self, pda1, pda2):
from arkouda import sum as aksum

assert pda1.size == pda2.size
assert aksum(pda1 != pda2) == 0

def test_eq(self):
i = ak.Index([1, 2, 3])
i_cpy = ak.Index([1, 2, 3])
self.assert_equal(i == i_cpy, ak.array([True, True, True]))
self.assert_equal(i != i_cpy, ak.array([False, False, False]))
assert i.equals(i_cpy)

i2 = ak.Index([1, 2, 3], allow_list=True)
i2_cpy = ak.Index([1, 2, 3], allow_list=True)
self.assert_equal(i2 == i2_cpy, ak.array([True, True, True]))
self.assert_equal(i2 != i2_cpy, ak.array([False, False, False]))
assert i2.equals(i2_cpy)

self.assert_equal(i == i2, ak.array([True, True, True]))
self.assert_equal(i != i2, ak.array([False, False, False]))
assert i.equals(i2)

i3 = ak.Index(["a", "b", "c"], allow_list=True)
i3_cpy = ak.Index(["a", "b", "c"], allow_list=True)
self.assert_equal(i3 == i3_cpy, ak.array([True, True, True]))
self.assert_equal(i3 != i3_cpy, ak.array([False, False, False]))
assert i3.equals(i3_cpy)

i4 = ak.Index(["a", "x", "c"], allow_list=True)
self.assert_equal(i3 == i4, ak.array([True, False, True]))
self.assert_equal(i3 != i4, ak.array([False, True, False]))
assert not i3.equals(i4)

i5 = ak.Index(["a", "b", "c", "d"], allow_list=True)
assert not i4.equals(i5)

def test_memory_usage(self):
from arkouda.dtypes import BigInt
from arkouda.index import Index, MultiIndex
Expand Down
23 changes: 17 additions & 6 deletions tests/operator_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,13 @@ def test_bool_bool_addition_binop(self):
ak_x = ak.array(np_x)
ak_y = ak.array(np_y)
# Vector-Vector Case
self.assertListEqual((np_x+np_y).tolist(), (ak_x+ak_y).to_list())
self.assertListEqual((np_x + np_y).tolist(), (ak_x + ak_y).to_list())
# Scalar-Vector Case
self.assertListEqual((np_x[0]+np_y).tolist(), (ak_x[0]+ak_y).to_list())
self.assertListEqual((np_x[-1]+np_y).tolist(), (ak_x[-1]+ak_y).to_list())
self.assertListEqual((np_x[0] + np_y).tolist(), (ak_x[0] + ak_y).to_list())
self.assertListEqual((np_x[-1] + np_y).tolist(), (ak_x[-1] + ak_y).to_list())
# Vector-Scalar Case
self.assertListEqual((np_x+np_y[0]).tolist(), (ak_x+ak_y[0]).to_list())
self.assertListEqual((np_x+np_y[-1]).tolist(), (ak_x+ak_y[-1]).to_list())
self.assertListEqual((np_x + np_y[0]).tolist(), (ak_x + ak_y[0]).to_list())
self.assertListEqual((np_x + np_y[-1]).tolist(), (ak_x + ak_y[-1]).to_list())

def test_bool_bool_addition_opeq(self):
np_x = np.array([True, True, False, False])
Expand All @@ -341,7 +341,7 @@ def test_bool_bool_addition_opeq(self):
np_false += np_y
ak_false += ak_y
self.assertListEqual(np_x.tolist(), ak_x.to_list())

def test_uint_bool_binops(self):
# Test fix for issue #1932
# Adding support to binopvv to correctly handle uint and bool types
Expand Down Expand Up @@ -1168,6 +1168,17 @@ def type_helper(x):
akf_copy %= 2.14
self.assertTrue(np.allclose(akf_copy.to_ndarray(), npf_copy, equal_nan=True))

def test_equals(self):
size = 10
a1 = ak.arange(size)
a1_cpy = ak.arange(size)
a2 = 2 * ak.arange(size)
a3 = ak.arange(size + 1)

self.assertTrue(a1.equals(a1_cpy))
self.assertFalse(a1.equals(a2))
self.assertFalse(a1.equals(a3))


if __name__ == "__main__":
"""
Expand Down

0 comments on commit e27825d

Please sign in to comment.