diff --git a/.github/workflows/array-api-skips.txt b/.github/workflows/array-api-skips.txt index cccb79a51c5c..9589c591f5cb 100644 --- a/.github/workflows/array-api-skips.txt +++ b/.github/workflows/array-api-skips.txt @@ -29,7 +29,3 @@ array_api_tests/test_operators_and_elementwise_functions.py::test_clip # unexpected result is returned - unmute when dpctl-1986 is resolved array_api_tests/test_operators_and_elementwise_functions.py::test_asin array_api_tests/test_operators_and_elementwise_functions.py::test_asinh - -# missing 'correction' keyword argument -array_api_tests/test_signatures.py::test_func_signature[std] -array_api_tests/test_signatures.py::test_func_signature[var] diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index 4f5d885da15c..4e3625efa6c2 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -1732,6 +1732,7 @@ def std( *, where=True, mean=None, + correction=None, ): """ Returns the standard deviation of the array elements, along given axis. @@ -1741,7 +1742,15 @@ def std( """ return dpnp.std( - self, axis, dtype, out, ddof, keepdims, where=where, mean=mean + self, + axis, + dtype, + out, + ddof, + keepdims, + where=where, + mean=mean, + correction=correction, ) @property @@ -1942,6 +1951,7 @@ def var( *, where=True, mean=None, + correction=None, ): """ Returns the variance of the array elements, along given axis. @@ -1951,7 +1961,15 @@ def var( """ return dpnp.var( - self, axis, dtype, out, ddof, keepdims, where=where, mean=mean + self, + axis, + dtype, + out, + ddof, + keepdims, + where=where, + mean=mean, + correction=correction, ) diff --git a/dpnp/dpnp_iface_nanfunctions.py b/dpnp/dpnp_iface_nanfunctions.py index 281f72a89bf0..c57256b6fd38 100644 --- a/dpnp/dpnp_iface_nanfunctions.py +++ b/dpnp/dpnp_iface_nanfunctions.py @@ -113,15 +113,18 @@ def nanargmax(a, axis=None, out=None, *, keepdims=False): Input array. axis : {None, int}, optional Axis along which to operate. By default flattened input is used. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional If provided, the result will be inserted into this array. It should be of the appropriate shape and dtype. + Default: ``None``. keepdims : {None, bool}, optional If this is set to ``True``, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the array. + Default: ``False``. Returns @@ -184,15 +187,18 @@ def nanargmin(a, axis=None, out=None, *, keepdims=False): Input array. axis : {None, int}, optional Axis along which to operate. By default flattened input is used. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional If provided, the result will be inserted into this array. It should be of the appropriate shape and dtype. + Default: ``None``. keepdims : {None, bool}, optional If this is set to ``True``, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the array. + Default: ``False``. Returns @@ -257,19 +263,24 @@ def nancumprod(a, axis=None, dtype=None, out=None): Input array. axis : {None, int}, optional Axis along which the cumulative product is computed. The default - (``None``) is to compute the cumulative product over the flattened - array. + is to compute the cumulative product over the flattened array. + + Default: ``None``. dtype : {None, dtype}, optional Type of the returned array and of the accumulator in which the elements are summed. If `dtype` is not specified, it defaults to the dtype of `a`, unless `a` has an integer dtype with a precision less than that of the default platform integer. In that case, the default platform integer is used. + + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternative output array in which to place the result. It must have the same shape and buffer length as the expected output but the type will be cast if necessary. + Default: ``None``. + Returns ------- out : dpnp.ndarray @@ -321,19 +332,25 @@ def nancumsum(a, axis=None, dtype=None, out=None): a : {dpnp.ndarray, usm_ndarray} Input array. axis : {None, int}, optional - Axis along which the cumulative sum is computed. The default (``None``) - is to compute the cumulative sum over the flattened array. + Axis along which the cumulative sum is computed. The default is to + compute the cumulative sum over the flattened array. + + Default: ``None``. dtype : {None, dtype}, optional Type of the returned array and of the accumulator in which the elements are summed. If `dtype` is not specified, it defaults to the dtype of `a`, unless `a` has an integer dtype with a precision less than that of the default platform integer. In that case, the default platform integer is used. + + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternative output array in which to place the result. It must have the same shape and buffer length as the expected output but the type will be cast if necessary. + Default: ``None``. + Returns ------- out : dpnp.ndarray @@ -386,15 +403,19 @@ def nanmax(a, axis=None, out=None, keepdims=False, initial=None, where=True): Axis or axes along which maximum values must be computed. By default, the maximum value must be computed over the entire array. If a tuple of integers, maximum values must be computed over multiple axes. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional If provided, the result will be inserted into this array. It should be of the appropriate shape and dtype. + + Default: ``None``. keepdims : {None, bool}, optional If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. + Default: ``False``. Returns @@ -476,6 +497,7 @@ def nanmean(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True): Axis or axes along which the arithmetic means must be computed. If a tuple of unique integers, the means are computed over multiple axes. If ``None``, the mean is computed over the entire array. + Default: ``None``. dtype : {None, dtype}, optional Type to use in computing the mean. By default, if `a` has a @@ -484,16 +506,22 @@ def nanmean(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True): If `a` has a boolean or integral data type, the returned array will have the default floating point data type for the device where input array `a` is allocated. + + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternative output array in which to place the result. It must have the same shape as the expected output but the type (of the calculated - values) will be cast if necessary. Default: ``None``. + values) will be cast if necessary. + + Default: ``None``. keepdims : {None, bool}, optional If ``True``, the reduced axes (dimensions) are included in the result as singleton dimensions, so that the returned array remains compatible with the input array according to Array Broadcasting rules. Otherwise, if ``False``, the reduced axes are not included in - the returned array. Default: ``False``. + the returned array. + + Default: ``False``. Returns ------- @@ -588,11 +616,13 @@ def nanmedian(a, axis=None, out=None, overwrite_input=False, keepdims=False): the array. If a sequence of axes, the array is first flattened along the given axes, then the median is computed along the resulting flattened axis. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternative output array in which to place the result. It must have the same shape as the expected output but the type (of the calculated values) will be cast if necessary. + Default: ``None``. overwrite_input : bool, optional If ``True``, then allow use of memory of input array `a` for @@ -600,6 +630,7 @@ def nanmedian(a, axis=None, out=None, overwrite_input=False, keepdims=False): :obj:`dpnp.nanmedian`. This will save memory when you do not need to preserve the contents of the input array. Treat the input as undefined, but it will probably be fully or partially sorted. + Default: ``False``. keepdims : bool, optional If ``True``, the reduced axes (dimensions) are included in the result @@ -607,6 +638,7 @@ def nanmedian(a, axis=None, out=None, overwrite_input=False, keepdims=False): compatible with the input array according to Array Broadcasting rules. Otherwise, if ``False``, the reduced axes are not included in the returned array. + Default: ``False``. Returns @@ -687,15 +719,19 @@ def nanmin(a, axis=None, out=None, keepdims=False, initial=None, where=True): Axis or axes along which minimum values must be computed. By default, the minimum value must be computed over the entire array. If a tuple of integers, minimum values must be computed over multiple axes. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional If provided, the result will be inserted into this array. It should be of the appropriate shape and dtype. + + Default: ``None``. keepdims : {None, bool}, optional If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. + Default: ``False``. Returns @@ -785,6 +821,7 @@ def nanprod( axis : {None, int or tuple of ints}, optional Axis or axes along which the product is computed. The default is to compute the product of the flattened array. + Default: ``None``. dtype : {None, dtype}, optional The type of the returned array and of the accumulator in which the @@ -793,17 +830,20 @@ def nanprod( the platform (u)intp. In that case, the default will be either (u)int32 or (u)int64 depending on whether the platform is 32 or 64 bits. For inexact inputs, dtype must be inexact. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternate output array in which to place the result. If provided, it must have the same shape as the expected output, but the type will be cast if necessary. The casting of NaN to integer can yield unexpected results. + Default: ``None``. keepdims : {None, bool}, optional If ``True``, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original `a`. + Default: ``False``. Returns @@ -878,6 +918,7 @@ def nansum( axis : {None, int or tuple of ints}, optional Axis or axes along which the sum is computed. The default is to compute the sum of the flattened array. + Default: ``None``. dtype : {None, dtype}, optional The type of the returned array and of the accumulator in which the @@ -886,17 +927,20 @@ def nansum( (u)intp. In that case, the default will be either (u)int32 or (u)int64 depending on whether the platform is 32 or 64 bits. For inexact inputs, dtype must be inexact. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternate output array in which to place the result. If provided, it must have the same shape as the expected output, but the type will be cast if necessary. The casting of NaN to integer can yield unexpected results. + Default: ``None``. keepdims : {None, bool}, optional If this is set to ``True``, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original `a`. + Default: ``False``. Returns @@ -966,6 +1010,7 @@ def nanstd( *, where=True, mean=None, + correction=None, ): """ Compute the standard deviation along the specified axis, @@ -1018,6 +1063,12 @@ def nanstd( Default: ``None``. + correction : {None, int, float}, optional + Array API compatible name for the `ddof` parameter. Only one of them + can be provided at the same time. + + Default: ``None``. + Returns ------- out : dpnp.ndarray @@ -1094,6 +1145,7 @@ def nanstd( keepdims=keepdims, where=where, mean=mean, + correction=correction, ) return dpnp.sqrt(res, out=res) @@ -1108,6 +1160,7 @@ def nanvar( *, where=True, mean=None, + correction=None, ): """ Compute the variance along the specified axis, while ignoring NaNs. @@ -1158,6 +1211,12 @@ def nanvar( Default: ``None``. + correction : {None, int, float}, optional + Array API compatible name for the `ddof` parameter. Only one of them + can be provided at the same time. + + Default: ``None``. + Returns ------- out : dpnp.ndarray @@ -1231,6 +1290,7 @@ def nanvar( ddof=ddof, keepdims=keepdims, where=where, + correction=correction, ) if dtype is not None: @@ -1243,6 +1303,13 @@ def nanvar( if not dpnp.issubdtype(out.dtype, dpnp.inexact): raise TypeError("If input is inexact, then out must be inexact.") + if correction is not None: + if ddof != 0: + raise ValueError( + "ddof and correction can't be provided simultaneously." + ) + ddof = correction + # Compute mean cnt = dpnp.sum( ~mask, axis=axis, dtype=dpnp.intp, keepdims=True, where=where diff --git a/dpnp/dpnp_iface_statistics.py b/dpnp/dpnp_iface_statistics.py index e462dc806ea0..7f320a166cab 100644 --- a/dpnp/dpnp_iface_statistics.py +++ b/dpnp/dpnp_iface_statistics.py @@ -205,6 +205,7 @@ def average(a, axis=None, weights=None, returned=False, *, keepdims=False): Axis or axes along which the averages must be computed. If a tuple of unique integers, the averages are computed over multiple axes. If ``None``, the average is computed over the entire array. + Default: ``None``. weights : {array_like}, optional An array of weights associated with the values in `a`. Each value in @@ -212,16 +213,19 @@ def average(a, axis=None, weights=None, returned=False, *, keepdims=False): The weights array can either be 1-D (in which case its length must be the size of `a` along the given axis) or of the same shape as `a`. If `weights=None`, then all data in `a` are assumed to have a - weight equal to one. The 1-D calculation is:: + weight equal to one. The 1-D calculation is:: avg = sum(a * weights) / sum(weights) The only constraint on `weights` is that `sum(weights)` must not be 0. + + Default: ``None``. returned : {bool}, optional If ``True``, the tuple (`average`, `sum_of_weights`) is returned, otherwise only the average is returned. If `weights=None`, `sum_of_weights` is equivalent to the number of elements over which the average is taken. + Default: ``False``. keepdims : {None, bool}, optional If ``True``, the reduced axes (dimensions) are included in the result @@ -229,6 +233,7 @@ def average(a, axis=None, weights=None, returned=False, *, keepdims=False): compatible with the input array according to Array Broadcasting rules. Otherwise, if ``False``, the reduced axes are not included in the returned array. + Default: ``False``. Returns @@ -367,15 +372,18 @@ def corrcoef(x, y=None, rowvar=True, *, dtype=None): y : {None, dpnp.ndarray, usm_ndarray}, optional An additional set of variables and observations. `y` has the same shape as `x`. + Default: ``None``. rowvar : {bool}, optional If `rowvar` is ``True``, then each row represents a variable, with observations in the columns. Otherwise, the relationship is transposed: each column represents a variable, while the rows contain observations. + Default: ``True``. dtype : {None, dtype}, optional Data-type of the result. + Default: ``None``. Returns @@ -812,15 +820,18 @@ def max(a, axis=None, out=None, keepdims=False, initial=None, where=True): Axis or axes along which to operate. By default, flattened input is used. If this is a tuple of integers, the minimum is selected over multiple axes, instead of a single axis or all the axes as before. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternative output array in which to place the result. Must be of the same shape and buffer length as the expected output. + Default: ``None``. keepdims : {None, bool}, optional If this is set to ``True``, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the input array. + Default: ``False``. Returns @@ -895,6 +906,7 @@ def mean(a, /, axis=None, dtype=None, out=None, keepdims=False, *, where=True): Axis or axes along which the arithmetic means must be computed. If a tuple of unique integers, the means are computed over multiple axes. If ``None``, the mean is computed over the entire array. + Default: ``None``. dtype : {None, dtype}, optional Type to use in computing the mean. By default, if `a` has a @@ -903,10 +915,13 @@ def mean(a, /, axis=None, dtype=None, out=None, keepdims=False, *, where=True): If `a` has a boolean or integral data type, the returned array will have the default floating point data type for the device where input array `a` is allocated. + + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternative output array in which to place the result. It must have the same shape as the expected output but the type (of the calculated values) will be cast if necessary. + Default: ``None``. keepdims : {None, bool}, optional If ``True``, the reduced axes (dimensions) are included in the result @@ -914,6 +929,7 @@ def mean(a, /, axis=None, dtype=None, out=None, keepdims=False, *, where=True): compatible with the input array according to Array Broadcasting rules. Otherwise, if ``False``, the reduced axes are not included in the returned array. + Default: ``False``. Returns @@ -979,11 +995,13 @@ def median(a, axis=None, out=None, overwrite_input=False, keepdims=False): the array. If a sequence of axes, the array is first flattened along the given axes, then the median is computed along the resulting flattened axis. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternative output array in which to place the result. It must have the same shape as the expected output but the type (of the calculated values) will be cast if necessary. + Default: ``None``. overwrite_input : bool, optional If ``True``, then allow use of memory of input array `a` for @@ -991,6 +1009,7 @@ def median(a, axis=None, out=None, overwrite_input=False, keepdims=False): :obj:`dpnp.median`. This will save memory when you do not need to preserve the contents of the input array. Treat the input as undefined, but it will probably be fully or partially sorted. + Default: ``False``. keepdims : bool, optional If ``True``, the reduced axes (dimensions) are included in the result @@ -998,6 +1017,7 @@ def median(a, axis=None, out=None, overwrite_input=False, keepdims=False): compatible with the input array according to Array Broadcasting rules. Otherwise, if ``False``, the reduced axes are not included in the returned array. + Default: ``False``. Returns @@ -1077,15 +1097,18 @@ def min(a, axis=None, out=None, keepdims=False, initial=None, where=True): Axis or axes along which to operate. By default, flattened input is used. If this is a tuple of integers, the minimum is selected over multiple axes, instead of a single axis or all the axes as before. + Default: ``None``. out : {None, dpnp.ndarray, usm_ndarray}, optional Alternative output array in which to place the result. Must be of the same shape and buffer length as the expected output. + Default: ``None``. keepdims : {None, bool}, optional If this is set to ``True``, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the input array. + Default: ``False``. Returns @@ -1158,20 +1181,39 @@ def ptp( For full documentation refer to :obj:`numpy.ptp`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array. + axis : {None, int, tuple of ints}, optional + Axis along which to find the peaks. By default, flatten the array. + `axis` may be negative, in which case it counts from the last to the + first axis. If this is a tuple of ints, a reduction is performed on + multiple axes, instead of a single axis or all the axes as before. + + Default: ``None``. + out : {None, dpnp.ndarray, usm_ndarray}, optional + Alternative output array in which to place the result. It must have the + same shape and buffer length as the expected output, but the type of + the output values will be cast if necessary. + + Default: ``None``. + keepdims : {None, bool}, optional + If this is set to ``True``, the axes which are reduced are left in the + result as dimensions with size one. With this option, the result will + broadcast correctly against the input array. + + Default: ``None``. + Returns ------- ptp : dpnp.ndarray The range of a given array. - Limitations - ----------- - Input array is supported as :class:`dpnp.dpnp.ndarray` or - :class:`dpctl.tensor.usm_ndarray`. - Examples -------- >>> import dpnp as np - >>> x = np.array([[4, 9, 2, 10],[6, 9, 7, 12]]) + >>> x = np.array([[4, 9, 2, 10], [6, 9, 7, 12]]) >>> np.ptp(x, axis=1) array([8, 6]) @@ -1181,6 +1223,16 @@ def ptp( >>> np.ptp(x) array(10) + This example shows that a negative value can be returned when the input is + an array of signed integers: + + >>> y = np.array([[1, 127], + ... [0, 127], + ... [-1, 127], + ... [-2, 127]], dtype="i1") + >>> np.ptp(y, axis=1) + array([ 126, 127, -128, -127], dtype=int8) + """ return dpnp.subtract( @@ -1201,6 +1253,7 @@ def std( *, where=True, mean=None, + correction=None, ): r""" Compute the standard deviation along the specified axis. @@ -1253,6 +1306,12 @@ def std( Default: ``None``. + correction : {None, int, float}, optional + Array API compatible name for the `ddof` parameter. Only one of them + can be provided at the same time. + + Default: ``None``. + Returns ------- out : dpnp.ndarray @@ -1344,6 +1403,13 @@ def std( dpnp.check_supported_arrays_type(a) dpnp.check_limitations(where=where) + if correction is not None: + if ddof != 0: + raise ValueError( + "ddof and correction can't be provided simultaneously." + ) + ddof = correction + if not isinstance(ddof, (int, float)): raise TypeError( f"An integer or float is required, but got {type(ddof)}" @@ -1382,6 +1448,7 @@ def var( *, where=True, mean=None, + correction=None, ): r""" Compute the variance along the specified axis. @@ -1433,6 +1500,12 @@ def var( Default: ``None``. + correction : {None, int, float}, optional + Array API compatible name for the `ddof` parameter. Only one of them + can be provided at the same time. + + Default: ``None``. + Returns ------- out : dpnp.ndarray @@ -1518,6 +1591,13 @@ def var( dpnp.check_supported_arrays_type(a) dpnp.check_limitations(where=where) + if correction is not None: + if ddof != 0: + raise ValueError( + "ddof and correction can't be provided simultaneously." + ) + ddof = correction + if not isinstance(ddof, (int, float)): raise TypeError( f"An integer or float is required, but got {type(ddof)}" diff --git a/dpnp/tests/test_nanfunctions.py b/dpnp/tests/test_nanfunctions.py index 92dda789b78b..19ffb28e92b0 100644 --- a/dpnp/tests/test_nanfunctions.py +++ b/dpnp/tests/test_nanfunctions.py @@ -9,6 +9,7 @@ assert_array_equal, assert_equal, assert_raises, + assert_raises_regex, ) import dpnp @@ -24,6 +25,7 @@ numpy_version, ) from .third_party.cupy import testing +from .third_party.cupy.testing import with_requires class TestNanArgmaxNanArgmin: @@ -750,6 +752,28 @@ def test_mean_keyword(self, dtype, axis, keepdims): ) assert_dtype_allclose(result, expected) + @with_requires("numpy>=2.0") + def test_correction(self): + a = numpy.array([127, numpy.nan, numpy.nan, 39, 93, 87, numpy.nan, 46]) + ia = dpnp.array(a) + + expected = getattr(numpy, self.func)(a, correction=0.5) + result = getattr(dpnp, self.func)(ia, correction=0.5) + assert_dtype_allclose(result, expected) + + @with_requires("numpy>=2.0") + @pytest.mark.parametrize("xp", [dpnp, numpy]) + def test_both_ddof_correction_are_set(self, xp): + a = xp.array([5, xp.nan, -2]) + + err_msg = "ddof and correction can't be provided simultaneously." + + with assert_raises_regex(ValueError, err_msg): + getattr(xp, self.func)(a, ddof=0.5, correction=0.5) + + with assert_raises_regex(ValueError, err_msg): + getattr(xp, self.func)(a, ddof=1, correction=0) + def test_error(self): ia = dpnp.arange(5, dtype=dpnp.float32) ia[0] = dpnp.nan diff --git a/dpnp/tests/test_statistics.py b/dpnp/tests/test_statistics.py index d5d0e72b030d..0cc7b76c4498 100644 --- a/dpnp/tests/test_statistics.py +++ b/dpnp/tests/test_statistics.py @@ -5,6 +5,7 @@ from numpy.testing import ( assert_allclose, assert_array_equal, + assert_raises_regex, ) import dpnp @@ -763,6 +764,29 @@ def test_scalar(self): result = getattr(ia, self.func)() assert_dtype_allclose(result, expected) + @with_requires("numpy>=2.0") + def test_correction(self): + a = numpy.array([1, -1, 1, -1]) + ia = dpnp.array(a) + + # numpy doesn't support `correction` keyword in std/var methods + expected = getattr(numpy, self.func)(a, correction=1) + result = getattr(ia, self.func)(correction=1) + assert_dtype_allclose(result, expected) + + @with_requires("numpy>=2.0") + @pytest.mark.parametrize("xp", [dpnp, numpy]) + def test_both_ddof_correction_are_set(self, xp): + a = xp.array([1, -1, 1, -1]) + + err_msg = "ddof and correction can't be provided simultaneously." + + with assert_raises_regex(ValueError, err_msg): + getattr(xp, self.func)(a, ddof=1, correction=0) + + with assert_raises_regex(ValueError, err_msg): + getattr(xp, self.func)(a, ddof=1, correction=1) + def test_error(self): ia = dpnp.arange(5) # where keyword is not implemented diff --git a/pyproject.toml b/pyproject.toml index 4863cdc60cf9..ccaf3bf2c466 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ exclude-protected = ["_create_from_usm_ndarray"] max-args = 11 max-positional-arguments = 9 max-locals = 30 -max-branches = 15 +max-branches = 16 max-returns = 8 [tool.pylint.format]