From 9949e27c43f705edb0e2acdb5cce9dcf1378e674 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Tue, 25 Feb 2025 00:44:20 -0800 Subject: [PATCH 1/6] Use `nan_to_num` instead of `_replace_nan` in nansum and nanprod --- dpnp/dpnp_iface_nanfunctions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dpnp/dpnp_iface_nanfunctions.py b/dpnp/dpnp_iface_nanfunctions.py index c1f62dac85d5..e0ad08ed91e2 100644 --- a/dpnp/dpnp_iface_nanfunctions.py +++ b/dpnp/dpnp_iface_nanfunctions.py @@ -884,7 +884,7 @@ def nanprod( """ - a, _ = _replace_nan(a, 1) + a = dpnp.nan_to_num(a, nan=1.0, posinf=dpnp.inf, neginf=-dpnp.inf) return dpnp.prod( a, axis=axis, @@ -988,7 +988,7 @@ def nansum( """ - a, _ = _replace_nan(a, 0) + a = dpnp.nan_to_num(a, nan=0.0, posinf=dpnp.inf, neginf=-dpnp.inf) return dpnp.sum( a, axis=axis, From 67d7efd46c135586f90960816dd5ff9006266fb7 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Thu, 27 Feb 2025 23:38:15 -0800 Subject: [PATCH 2/6] Reuse nan_to_num in nancumprod and nancumsum --- dpnp/dpnp_iface_nanfunctions.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/dpnp/dpnp_iface_nanfunctions.py b/dpnp/dpnp_iface_nanfunctions.py index e0ad08ed91e2..68ab47b85772 100644 --- a/dpnp/dpnp_iface_nanfunctions.py +++ b/dpnp/dpnp_iface_nanfunctions.py @@ -60,6 +60,31 @@ ] +def _replace_nan_no_mask(a, val): + """ + Replace NaNs in array `a` with `val`. + + If `a` is of inexact type, make a copy of `a`, replace NaNs with + the `val` value, and return the copy together. If `a` is not of + inexact type, do nothing and return `a`. + + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array. + val : float + NaN values are set to `val` before doing the operation. + + Returns + ------- + out : {dpnp.ndarray} + If `a` is of inexact type, return a copy of `a` with the NaNs + replaced by the fill value, otherwise return `a`. + """ + + return dpnp.nan_to_num(a, nan=val, posinf=dpnp.inf, neginf=-dpnp.inf) + + def _replace_nan(a, val): """ Replace NaNs in array `a` with `val`. @@ -315,7 +340,7 @@ def nancumprod(a, axis=None, dtype=None, out=None): """ - a, _ = _replace_nan(a, 1) + a = _replace_nan_no_mask(a, 1.0) return dpnp.cumprod(a, axis=axis, dtype=dtype, out=out) @@ -385,7 +410,7 @@ def nancumsum(a, axis=None, dtype=None, out=None): """ - a, _ = _replace_nan(a, 0) + a = _replace_nan_no_mask(a, 0.0) return dpnp.cumsum(a, axis=axis, dtype=dtype, out=out) @@ -884,7 +909,7 @@ def nanprod( """ - a = dpnp.nan_to_num(a, nan=1.0, posinf=dpnp.inf, neginf=-dpnp.inf) + a = _replace_nan_no_mask(a, 1.0) return dpnp.prod( a, axis=axis, @@ -988,7 +1013,7 @@ def nansum( """ - a = dpnp.nan_to_num(a, nan=0.0, posinf=dpnp.inf, neginf=-dpnp.inf) + a = _replace_nan_no_mask(a, 0.0) return dpnp.sum( a, axis=axis, From 08464929538dfdae2f7c93104a5108b9513b0714 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Fri, 28 Feb 2025 08:32:43 -0800 Subject: [PATCH 3/6] Fix `_replace_nan_no_mask` docstring per PR review --- dpnp/dpnp_iface_nanfunctions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_nanfunctions.py b/dpnp/dpnp_iface_nanfunctions.py index 68ab47b85772..a103a490864f 100644 --- a/dpnp/dpnp_iface_nanfunctions.py +++ b/dpnp/dpnp_iface_nanfunctions.py @@ -77,9 +77,10 @@ def _replace_nan_no_mask(a, val): Returns ------- - out : {dpnp.ndarray} + out : dpnp.ndarray If `a` is of inexact type, return a copy of `a` with the NaNs replaced by the fill value, otherwise return `a`. + """ return dpnp.nan_to_num(a, nan=val, posinf=dpnp.inf, neginf=-dpnp.inf) From 1ffd3c3525bd3ba5bd8b17ca785f304f2dbafc73 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Fri, 28 Feb 2025 12:05:42 -0800 Subject: [PATCH 4/6] `_replace_nan_no_mask` should not copy if a is not of inexact type --- dpnp/dpnp_iface_nanfunctions.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dpnp/dpnp_iface_nanfunctions.py b/dpnp/dpnp_iface_nanfunctions.py index a103a490864f..68a67378dc10 100644 --- a/dpnp/dpnp_iface_nanfunctions.py +++ b/dpnp/dpnp_iface_nanfunctions.py @@ -65,8 +65,8 @@ def _replace_nan_no_mask(a, val): Replace NaNs in array `a` with `val`. If `a` is of inexact type, make a copy of `a`, replace NaNs with - the `val` value, and return the copy together. If `a` is not of - inexact type, do nothing and return `a`. + the `val` value, and return the copy. If `a` is not of inexact type, + do nothing and return `a`. Parameters ---------- @@ -83,7 +83,11 @@ def _replace_nan_no_mask(a, val): """ - return dpnp.nan_to_num(a, nan=val, posinf=dpnp.inf, neginf=-dpnp.inf) + dpnp.check_supported_arrays_type(a) + if dpnp.issubdtype(a.dtype, dpnp.inexact): + return dpnp.nan_to_num(a, nan=val, posinf=dpnp.inf, neginf=-dpnp.inf) + + return a def _replace_nan(a, val): From bb44b2d9ac358940a3c4de6842618047ea5e3ec2 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Fri, 28 Feb 2025 14:08:49 -0800 Subject: [PATCH 5/6] Add synchronization warning to `nanargmin` and `nanargmax` documentation --- dpnp/dpnp_iface_nanfunctions.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dpnp/dpnp_iface_nanfunctions.py b/dpnp/dpnp_iface_nanfunctions.py index 68a67378dc10..769791b71f8a 100644 --- a/dpnp/dpnp_iface_nanfunctions.py +++ b/dpnp/dpnp_iface_nanfunctions.py @@ -137,6 +137,13 @@ def nanargmax(a, axis=None, out=None, *, keepdims=False): For full documentation refer to :obj:`numpy.nanargmax`. + Warning + ------- + This function synchronizes in order to test for all-NaN slices in the array. + This may harm performance in some applications. To avoid synchronization, + the user is recommended to filter NaNs themselves and use `dpnp.argmax` + on the filtered array. + Parameters ---------- a : {dpnp.ndarray, usm_ndarray} @@ -211,6 +218,13 @@ def nanargmin(a, axis=None, out=None, *, keepdims=False): For full documentation refer to :obj:`numpy.nanargmin`. + Warning + ------- + This function synchronizes in order to test for all-NaN slices in the array. + This may harm performance in some applications. To avoid synchronization, + the user is recommended to filter NaNs themselves and use `dpnp.argmax` + on the filtered array. + Parameters ---------- a : {dpnp.ndarray, usm_ndarray} From 1995cd577cbdf7e79bce55688116f2aaf27c40cd Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Sun, 2 Mar 2025 11:07:32 -0800 Subject: [PATCH 6/6] Change `nanargmin` and `nanargmax` docstring warnings Moved warnings relating to all-NaN and all-negative-inf slices to near the synchronization warning --- dpnp/dpnp_iface_nanfunctions.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dpnp/dpnp_iface_nanfunctions.py b/dpnp/dpnp_iface_nanfunctions.py index 769791b71f8a..a4029636d489 100644 --- a/dpnp/dpnp_iface_nanfunctions.py +++ b/dpnp/dpnp_iface_nanfunctions.py @@ -144,6 +144,11 @@ def nanargmax(a, axis=None, out=None, *, keepdims=False): the user is recommended to filter NaNs themselves and use `dpnp.argmax` on the filtered array. + Warning + ------- + The results cannot be trusted if a slice contains only NaNs + and -Infs. + Parameters ---------- a : {dpnp.ndarray, usm_ndarray} @@ -173,8 +178,6 @@ def nanargmax(a, axis=None, out=None, *, keepdims=False): values ignoring NaNs. The returned array must have the default array index data type. For all-NaN slices ``ValueError`` is raised. - Warning: the results cannot be trusted if a slice contains only NaNs - and -Infs. Limitations ----------- @@ -225,6 +228,11 @@ def nanargmin(a, axis=None, out=None, *, keepdims=False): the user is recommended to filter NaNs themselves and use `dpnp.argmax` on the filtered array. + Warning + ------- + The results cannot be trusted if a slice contains only NaNs + and -Infs. + Parameters ---------- a : {dpnp.ndarray, usm_ndarray} @@ -254,8 +262,6 @@ def nanargmin(a, axis=None, out=None, *, keepdims=False): values ignoring NaNs. The returned array must have the default array index data type. For all-NaN slices ``ValueError`` is raised. - Warning: the results cannot be trusted if a slice contains only NaNs - and Infs. Limitations -----------