From 5fd431e3326517575f44a5a326b49ba39dfb2aec Mon Sep 17 00:00:00 2001 From: ajpotts Date: Fri, 31 May 2024 07:43:36 -0400 Subject: [PATCH] Closes #3255 move numeric.floor to numpy module (#3257) Co-authored-by: Amanda Potts --- PROTO_tests/tests/numeric_test.py | 64 ++++++++++++++----- PROTO_tests/tests/numpy/numpy_numeric_test.py | 26 ++++++++ arkouda/numeric.py | 34 ++-------- arkouda/numpy/__init__.py | 2 + arkouda/numpy/_numeric.py | 45 +++++++++++++ pytest_PROTO.ini | 3 +- 6 files changed, 129 insertions(+), 45 deletions(-) create mode 100644 PROTO_tests/tests/numpy/numpy_numeric_test.py create mode 100644 arkouda/numpy/_numeric.py diff --git a/PROTO_tests/tests/numeric_test.py b/PROTO_tests/tests/numeric_test.py index 29f7f6cc68..87c1be98ec 100644 --- a/PROTO_tests/tests/numeric_test.py +++ b/PROTO_tests/tests/numeric_test.py @@ -24,10 +24,18 @@ def alternatingTF(n): atf[::2] = True return atf + # The following tuples support a simplification of the trigonometric # and hyperbolic testing. -TRIGONOMETRICS = ((np.sin, ak.sin), (np.cos, ak.cos), (np.tan, ak.tan), (np.arcsin, ak.arcsin), (np.arccos, ak.arccos), (np.arctan, ak.arctan)) +TRIGONOMETRICS = ( + (np.sin, ak.sin), + (np.cos, ak.cos), + (np.tan, ak.tan), + (np.arcsin, ak.arcsin), + (np.arccos, ak.arccos), + (np.arctan, ak.arctan), +) HYPERBOLICS = ( (np.sinh, ak.sinh), @@ -38,7 +46,13 @@ def alternatingTF(n): (np.arctanh, ak.arctanh), ) -INFINITY_EDGE_CASES = ((np.arctan, ak.arctan), (np.sinh, ak.sinh), (np.cosh, ak.cosh), (np.arcsinh, ak.arcsinh), (np.arccosh, ak.arccosh)) +INFINITY_EDGE_CASES = ( + (np.arctan, ak.arctan), + (np.sinh, ak.sinh), + (np.cosh, ak.cosh), + (np.arcsinh, ak.arcsinh), + (np.arccosh, ak.arccosh), +) # as noted in serverConfig.json, only these types are supported @@ -143,16 +157,28 @@ def test_seeded_rng_general(self, prob_size): # Standard Normal assert not (ak.standard_normal(prob_size) == ak.standard_normal(prob_size)).all() - assert (ak.standard_normal(prob_size, seed=seed) == ak.standard_normal(prob_size, seed=seed)).all() + assert ( + ak.standard_normal(prob_size, seed=seed) == ak.standard_normal(prob_size, seed=seed) + ).all() # Strings (uniformly distributed length) - assert not (ak.random_strings_uniform(1, 10, prob_size) == ak.random_strings_uniform(1, 10, prob_size)).all() + assert not ( + ak.random_strings_uniform(1, 10, prob_size) == ak.random_strings_uniform(1, 10, prob_size) + ).all() - assert (ak.random_strings_uniform(1, 10, prob_size, seed=seed) == ak.random_strings_uniform(1, 10, prob_size, seed=seed)).all() + assert ( + ak.random_strings_uniform(1, 10, prob_size, seed=seed) + == ak.random_strings_uniform(1, 10, prob_size, seed=seed) + ).all() # Strings (log-normally distributed length) - assert not (ak.random_strings_lognormal(2, 1, prob_size) == ak.random_strings_lognormal(2, 1, prob_size)).all() - assert (ak.random_strings_lognormal(2, 1, prob_size, seed=seed) == ak.random_strings_lognormal(2, 1, prob_size, seed=seed)).all() + assert not ( + ak.random_strings_lognormal(2, 1, prob_size) == ak.random_strings_lognormal(2, 1, prob_size) + ).all() + assert ( + ak.random_strings_lognormal(2, 1, prob_size, seed=seed) + == ak.random_strings_lognormal(2, 1, prob_size, seed=seed) + ).all() @pytest.mark.parametrize("cast_to", SUPPORTED_TYPES) @pytest.mark.parametrize("prob_size", pytest.prob_size) @@ -271,7 +297,10 @@ def test_abs(self, num_type): assert np.allclose(np.abs(na), ak.abs(pda).to_ndarray()) - assert ak.arange(5, 0, -1, dtype=num_type).to_list() == ak.abs(ak.arange(-5, 0, dtype=num_type)).to_list() + assert ( + ak.arange(5, 0, -1, dtype=num_type).to_list() + == ak.abs(ak.arange(-5, 0, dtype=num_type)).to_list() + ) with pytest.raises(TypeError): ak.abs(np.array([range(0, 10)]).astype(num_type)) @@ -310,7 +339,6 @@ def test_cumsum_and_cumprod(self, num_type): @pytest.mark.parametrize("num_type", NO_BOOL) def test_trig_and_hyp(self, num_type): - for npfunc, akfunc in set(TRIGONOMETRICS + HYPERBOLICS): na = NP_TRIG_ARRAYS[num_type] pda = ak.array(na, dtype=num_type) @@ -367,17 +395,26 @@ def test_arctan2(self, num_type, denom_type): ) assert np.allclose( - [(np.arctan2(na_num[i], na_denom[i]) if truth_np[i] else na_num[i] / na_denom[i]) for i in range(len(na_num))], + [ + (np.arctan2(na_num[i], na_denom[i]) if truth_np[i] else na_num[i] / na_denom[i]) + for i in range(len(na_num)) + ], ak.arctan2(pda_num, pda_denom, where=truth_ak).to_ndarray(), equal_nan=True, ) assert np.allclose( - [(np.arctan2(na_num[0], na_denom[i]) if truth_np[i] else na_num[0] / na_denom[i]) for i in range(len(na_denom))], + [ + (np.arctan2(na_num[0], na_denom[i]) if truth_np[i] else na_num[0] / na_denom[i]) + for i in range(len(na_denom)) + ], ak.arctan2(pda_num[0], pda_denom, where=truth_ak).to_ndarray(), equal_nan=True, ) assert np.allclose( - [(np.arctan2(na_num[i], na_denom[0]) if truth_np[i] else na_num[i] / na_denom[0]) for i in range(len(na_num))], + [ + (np.arctan2(na_num[i], na_denom[0]) if truth_np[i] else na_num[i] / na_denom[0]) + for i in range(len(na_num)) + ], ak.arctan2(pda_num, pda_denom[0], where=truth_ak).to_ndarray(), equal_nan=True, ) @@ -612,7 +649,6 @@ def test_hash(self): @pytest.mark.parametrize("prob_size", pytest.prob_size) @pytest.mark.parametrize("data_type", NUMERIC_TYPES) def test_median(self, prob_size, data_type): - sample_e = np.random.permutation(prob_size).astype(data_type) pda_e = ak.array(sample_e) assert isclose(np.median(sample_e), ak.median(pda_e)) @@ -627,11 +663,9 @@ def test_median(self, prob_size, data_type): @pytest.mark.parametrize("prob_size", pytest.prob_size) def test_count_nonzero(self, prob_size): - # ints, floats for data_type in INT_FLOAT: - sample = np.random.randint(20, size=prob_size).astype(data_type) pda = ak.array(sample) assert np.count_nonzero(sample) == ak.count_nonzero(pda) diff --git a/PROTO_tests/tests/numpy/numpy_numeric_test.py b/PROTO_tests/tests/numpy/numpy_numeric_test.py new file mode 100644 index 0000000000..4c2138be8c --- /dev/null +++ b/PROTO_tests/tests/numpy/numpy_numeric_test.py @@ -0,0 +1,26 @@ +import numpy as np +import pytest + +import arkouda as ak + +NUMERIC_TYPES = [ak.int64, ak.float64, ak.bool, ak.uint64] +NO_BOOL = [ak.int64, ak.float64, ak.uint64] +NO_FLOAT = [ak.int64, ak.bool, ak.uint64] +INT_FLOAT = [ak.int64, ak.float64] + + +class TestNumeric: + @pytest.mark.parametrize("prob_size", pytest.prob_size) + def test_floor_float(self, prob_size): + from arkouda import all as akall + from arkouda.numpy import floor as ak_floor + + a = 0.5 * ak.arange(prob_size, dtype="float64") + a_floor = ak_floor(a) + + expected_size = np.floor((prob_size + 1) / 2).astype("int64") + expected = ak.array(np.repeat(ak.arange(expected_size, dtype="float64").to_ndarray(), 2)) + # To deal with prob_size as an odd number: + expected = expected[0:prob_size] + + assert akall(a_floor == expected) diff --git a/arkouda/numeric.py b/arkouda/numeric.py index c2f0be2154..b402902c2d 100644 --- a/arkouda/numeric.py +++ b/arkouda/numeric.py @@ -247,35 +247,11 @@ def ceil(pda: pdarray) -> pdarray: @typechecked def floor(pda: pdarray) -> pdarray: """ - Return the element-wise floor of the array. - - Parameters - ---------- - pda : pdarray - - Returns - ------- - pdarray - A pdarray containing floor values of the input array elements - - Raises - ------ - TypeError - Raised if the parameter is not a pdarray - - Examples - -------- - >>> ak.floor(ak.linspace(1.1,5.5,5)) - array([1, 2, 3, 4, 5]) + Alias of arkouda.numpy.floor """ - repMsg = generic_msg( - cmd=f"efunc{pda.ndim}D", - args={ - "func": "floor", - "array": pda, - }, - ) - return create_pdarray(type_cast(str, repMsg)) + from arkouda.numpy import floor as ak_floor + + return ak_floor(pda) @typechecked @@ -481,7 +457,7 @@ def isnan(pda: pdarray) -> pdarray: >>> ak.isnan(ak.array[1.0, 2.0, 1.0 / 0.0]) array([False, False, True]) """ - from arkouda.util import is_numeric, is_float + from arkouda.util import is_float, is_numeric if is_numeric(pda) and not is_float(pda): from arkouda.pdarraycreation import full diff --git a/arkouda/numpy/__init__.py b/arkouda/numpy/__init__.py index f1a482225b..ddc71e5af3 100644 --- a/arkouda/numpy/__init__.py +++ b/arkouda/numpy/__init__.py @@ -43,6 +43,7 @@ ulonglong, ushort, ) +from ._numeric import floor __all__ = [ @@ -89,4 +90,5 @@ "uintc", "ulonglong", "ushort", + "floor", ] diff --git a/arkouda/numpy/_numeric.py b/arkouda/numpy/_numeric.py new file mode 100644 index 0000000000..c4315d8d5e --- /dev/null +++ b/arkouda/numpy/_numeric.py @@ -0,0 +1,45 @@ +from typing import cast as type_cast + +from typeguard import typechecked + +from arkouda.client import generic_msg +from arkouda.pdarrayclass import create_pdarray, pdarray +from arkouda.dtypes import int64 as ak_int64, float64 as ak_float64, bool as ak_bool, uint64 as ak_uint64 + +NUMERIC_TYPES = [ak_int64, ak_float64, ak_bool, ak_uint64] + +__all__ = ["floor"] + + +@typechecked +def floor(pda: pdarray) -> pdarray: + """ + Return the element-wise floor of the array. + + Parameters + ---------- + pda : pdarray + + Returns + ------- + pdarray + A pdarray containing floor values of the input array elements + + Raises + ------ + TypeError + Raised if the parameter is not a pdarray + + Examples + -------- + >>> ak.floor(ak.linspace(1.1,5.5,5)) + array([1, 2, 3, 4, 5]) + """ + repMsg = generic_msg( + cmd=f"efunc{pda.ndim}D", + args={ + "func": "floor", + "array": pda, + }, + ) + return create_pdarray(type_cast(str, repMsg)) diff --git a/pytest_PROTO.ini b/pytest_PROTO.ini index 9beae54869..e86793eada 100644 --- a/pytest_PROTO.ini +++ b/pytest_PROTO.ini @@ -23,7 +23,8 @@ testpaths = PROTO_tests/tests/logger_test.py PROTO_tests/tests/message_test.py PROTO_tests/tests/numeric_test.py - PROTO_tests/tests/numpy + PROTO_tests/tests/numpy/numpy_numeric_test.py + PROTO_tests/tests/numpy/numpy_test.py PROTO_tests/tests/operator_test.py PROTO_tests/tests/pdarray_creation_test.py PROTO_tests/tests/random_test.py