From a09549bc00d84085d54a215bb57835022be798ad Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Thu, 19 Oct 2023 03:46:27 -0500 Subject: [PATCH 1/9] Update dpnp.geomspace and dpnp.logspace functions --- dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi | 113 ------- dpnp/dpnp_algo/dpnp_arraycreation.py | 277 ++++++++++++++++++ dpnp/dpnp_iface_arraycreation.py | 152 +++++----- tests/skipped_tests.tbl | 1 - tests/skipped_tests_gpu.tbl | 2 - tests/test_arraycreation.py | 17 +- tests/test_sycl_queue.py | 12 +- tests/test_usm_type.py | 26 +- .../cupy/creation_tests/test_ranges.py | 8 - 9 files changed, 401 insertions(+), 207 deletions(-) create mode 100644 dpnp/dpnp_algo/dpnp_arraycreation.py diff --git a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi index 5ebb8d157a7..7b90ff1285f 100644 --- a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi +++ b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi @@ -38,9 +38,6 @@ and the rest of the library __all__ += [ "dpnp_copy", "dpnp_diag", - "dpnp_geomspace", - "dpnp_linspace", - "dpnp_logspace", "dpnp_ptp", "dpnp_trace", "dpnp_vander", @@ -138,116 +135,6 @@ cpdef utils.dpnp_descriptor dpnp_diag(utils.dpnp_descriptor v, int k): return result -cpdef utils.dpnp_descriptor dpnp_geomspace(start, stop, num, endpoint, dtype, axis): - cdef shape_type_c obj_shape = utils._object_to_tuple(num) - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py(obj_shape, dtype, None) - - if endpoint: - steps_count = num - 1 - else: - steps_count = num - - # if there are steps, then fill values - if steps_count > 0: - step = dpnp.power(dpnp.float64(stop) / start, 1.0 / steps_count) - mult = step - for i in range(1, result.size): - result.get_pyobj()[i] = start * mult - mult = mult * step - else: - step = dpnp.nan - - # if result is not empty, then fiil first and last elements - if num > 0: - result.get_pyobj()[0] = start - if endpoint and result.size > 1: - result.get_pyobj()[result.size - 1] = stop - - return result - - -def dpnp_linspace(start, stop, num, dtype=None, device=None, usm_type=None, sycl_queue=None, endpoint=True, retstep=False, axis=0): - usm_type_alloc, sycl_queue_alloc = utils_py.get_usm_allocations([start, stop]) - - # Get sycl_queue. - if sycl_queue is None and device is None: - sycl_queue = sycl_queue_alloc - sycl_queue_normalized = dpnp.get_normalized_queue_device(sycl_queue=sycl_queue, device=device) - - # Get temporary usm_type for getting dtype. - if usm_type is None: - _usm_type = "device" if usm_type_alloc is None else usm_type_alloc - else: - _usm_type = usm_type - - # Get dtype. - if not hasattr(start, "dtype") and not dpnp.isscalar(start): - start = dpnp.asarray(start, usm_type=_usm_type, sycl_queue=sycl_queue_normalized) - if not hasattr(stop, "dtype") and not dpnp.isscalar(stop): - stop = dpnp.asarray(stop, usm_type=_usm_type, sycl_queue=sycl_queue_normalized) - dt = numpy.result_type(start, stop, float(num)) - dt = utils_py.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) - if dtype is None: - dtype = dt - - if dpnp.isscalar(start) and dpnp.isscalar(stop): - # Call linspace() function for scalars. - res = dpnp_container.linspace(start, - stop, - num, - dtype=dt, - usm_type=_usm_type, - sycl_queue=sycl_queue_normalized, - endpoint=endpoint) - else: - num = operator.index(num) - if num < 0: - raise ValueError("Number of points must be non-negative") - - # Get final usm_type and copy arrays if needed with current dtype, usm_type and sycl_queue. - # Do not need to copy usm_ndarray by usm_type if it is not explicitly stated. - if usm_type is None: - usm_type = _usm_type - if not hasattr(start, "usm_type"): - _start = dpnp.asarray(start, dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - else: - _start = dpnp.asarray(start, dtype=dt, sycl_queue=sycl_queue_normalized) - if not hasattr(stop, "usm_type"): - _stop = dpnp.asarray(stop, dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - else: - _stop = dpnp.asarray(stop, dtype=dt, sycl_queue=sycl_queue_normalized) - else: - _start = dpnp.asarray(start, dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - _stop = dpnp.asarray(stop, dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - - # FIXME: issue #1304. Mathematical operations with scalar don't follow data type. - _num = dpnp.asarray((num - 1) if endpoint else num, dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - - step = (_stop - _start) / _num - - res = dpnp_container.arange(0, - stop=num, - step=1, - dtype=dt, - usm_type=usm_type, - sycl_queue=sycl_queue_normalized) - - res = res.reshape((-1,) + (1,) * step.ndim) - res = res * step + _start - - if endpoint and num > 1: - res[-1] = dpnp_container.full(step.shape, _stop) - - if numpy.issubdtype(dtype, dpnp.integer): - dpnp.floor(res, out=res) - return res.astype(dtype) - - -cpdef utils.dpnp_descriptor dpnp_logspace(start, stop, num, endpoint, base, dtype, axis): - temp = dpnp.linspace(start, stop, num=num, endpoint=endpoint) - return dpnp.get_dpnp_descriptor(dpnp.astype(dpnp.power(base, temp), dtype)) - - cpdef dpnp_ptp(utils.dpnp_descriptor arr, axis=None): cdef shape_type_c shape_arr = arr.shape cdef shape_type_c output_shape diff --git a/dpnp/dpnp_algo/dpnp_arraycreation.py b/dpnp/dpnp_algo/dpnp_arraycreation.py new file mode 100644 index 00000000000..dd75d62c686 --- /dev/null +++ b/dpnp/dpnp_algo/dpnp_arraycreation.py @@ -0,0 +1,277 @@ +import operator + +import numpy + +import dpnp +import dpnp.dpnp_container as dpnp_container +import dpnp.dpnp_utils as utils + +__all__ = [ + "dpnp_geomspace", + "dpnp_linspace", + "dpnp_logspace", +] + + +def _get_sycl_queue(sycl_queue_alloc, sycl_queue, device): + if sycl_queue is None and device is None: + sycl_queue = sycl_queue_alloc + return dpnp.get_normalized_queue_device( + sycl_queue=sycl_queue, device=device + ) + + +def _get_temporary_usm_type(usm_type_alloc, usm_type): + if usm_type is None: + usm_type = "device" if usm_type_alloc is None else usm_type_alloc + return usm_type + + +def _list_to_array(a, usm_type, sycl_queue, scalar=False): + if not hasattr(a, "dtype") and (scalar or not dpnp.isscalar(a)): + return dpnp.asarray(a, usm_type=usm_type, sycl_queue=sycl_queue) + return a + + +def _copy_by_usm_type(a, dtype, usm_type, tmp_usm_type, sycl_queue_normalized): + if usm_type is None: + usm_type = tmp_usm_type + if not hasattr(a, "usm_type"): + res = dpnp.asarray( + a, + dtype=dtype, + usm_type=usm_type, + sycl_queue=sycl_queue_normalized, + ) + else: + res = dpnp.asarray(a, dtype=dtype, sycl_queue=sycl_queue_normalized) + else: + res = dpnp.asarray( + a, dtype=dtype, usm_type=usm_type, sycl_queue=sycl_queue_normalized + ) + return res + + +def dpnp_geomspace( + start, + stop, + num, + dtype=None, + device=None, + usm_type=None, + sycl_queue=None, + endpoint=True, + axis=0, +): + usm_type_alloc, sycl_queue_alloc = utils.get_usm_allocations([start, stop]) + + sycl_queue_normalized = _get_sycl_queue( + sycl_queue_alloc, sycl_queue, device + ) + + _usm_type = _get_temporary_usm_type(usm_type_alloc, usm_type) + + start = _list_to_array(start, _usm_type, sycl_queue_normalized, scalar=True) + stop = _list_to_array(stop, _usm_type, sycl_queue_normalized, scalar=True) + + dt = numpy.result_type(start, stop, float(num)) + dt = utils.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) + if dtype is None: + dtype = dt + + if dpnp.any(start == 0) or dpnp.any(stop == 0): + raise ValueError("Geometric sequence cannot include zero") + + out_sign = dpnp.ones( + dpnp.broadcast_arrays(start, stop)[0].shape, + dtype=dt, + usm_type=_usm_type, + sycl_queue=sycl_queue_normalized, + ) + # Avoid negligible real or imaginary parts in output by rotating to + # positive real, calculating, then undoing rotation + if dpnp.issubdtype(dt, dpnp.complexfloating): + all_imag = (start.real == 0.0) & (stop.real == 0.0) + if dpnp.any(all_imag): + start[all_imag] = start[all_imag].imag + stop[all_imag] = stop[all_imag].imag + out_sign[all_imag] = 1j + + both_negative = (dpnp.sign(start) == -1) & (dpnp.sign(stop) == -1) + if dpnp.any(both_negative): + dpnp.negative(start, out=start, where=both_negative) + dpnp.negative(stop, out=stop, where=both_negative) + dpnp.negative(out_sign, out=out_sign, where=both_negative) + + log_start = dpnp.log10(start) + log_stop = dpnp.log10(stop) + result = dpnp_logspace( + log_start, + log_stop, + num=num, + endpoint=endpoint, + base=10.0, + dtype=dtype, + usm_type=_usm_type, + sycl_queue=sycl_queue_normalized, + ) + + if num > 0: + result[0] = start + if num > 1 and endpoint: + result[-1] = stop + + result = out_sign * result + + if axis != 0: + result = dpnp.moveaxis(result, 0, axis) + + return result.astype(dtype, copy=False) + + +def dpnp_linspace( + start, + stop, + num, + dtype=None, + device=None, + usm_type=None, + sycl_queue=None, + endpoint=True, + axis=0, +): + usm_type_alloc, sycl_queue_alloc = utils.get_usm_allocations([start, stop]) + + sycl_queue_normalized = _get_sycl_queue( + sycl_queue_alloc, sycl_queue, device + ) + + _usm_type = _get_temporary_usm_type(usm_type_alloc, usm_type) + + start = _list_to_array(start, _usm_type, sycl_queue_normalized) + stop = _list_to_array(stop, _usm_type, sycl_queue_normalized) + + dt = numpy.result_type(start, stop, float(num)) + dt = utils.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) + if dtype is None: + dtype = dt + + if dpnp.isscalar(start) and dpnp.isscalar(stop): + # Call linspace() function for scalars. + res = dpnp_container.linspace( + start, + stop, + num, + dtype=dt, + usm_type=_usm_type, + sycl_queue=sycl_queue_normalized, + endpoint=endpoint, + ) + else: + num = operator.index(num) + if num < 0: + raise ValueError("Number of points must be non-negative") + + _start = _copy_by_usm_type( + start, dt, usm_type, _usm_type, sycl_queue_normalized + ) + _stop = _copy_by_usm_type( + stop, dt, usm_type, _usm_type, sycl_queue_normalized + ) + + _num = (num - 1) if endpoint else num + + step = (_stop - _start) / _num + + res = dpnp_container.arange( + 0, + stop=num, + step=1, + dtype=dt, + usm_type=_usm_type, + sycl_queue=sycl_queue_normalized, + ) + + res = res.reshape((-1,) + (1,) * step.ndim) + res = res * step + _start + + if endpoint and num > 1: + res[-1] = dpnp_container.full(step.shape, _stop) + + if axis != 0: + res = dpnp.moveaxis(res, 0, axis) + + if numpy.issubdtype(dtype, dpnp.integer): + dpnp.floor(res, out=res) + + return res.astype(dtype, copy=False) + + +def dpnp_logspace( + start, + stop, + num=50, + device=None, + usm_type=None, + sycl_queue=None, + endpoint=True, + base=10.0, + dtype=None, + axis=0, +): + usm_type_alloc, sycl_queue_alloc = utils.get_usm_allocations( + [start, stop, base] + ) + + sycl_queue_normalized = _get_sycl_queue( + sycl_queue_alloc, sycl_queue, device + ) + + _usm_type = _get_temporary_usm_type(usm_type_alloc, usm_type) + + start = _list_to_array(start, _usm_type, sycl_queue_normalized) + stop = _list_to_array(stop, _usm_type, sycl_queue_normalized) + base = _list_to_array(base, _usm_type, sycl_queue_normalized) + + dt = numpy.result_type(start, stop, float(num)) + dt = utils.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) + if dtype is None: + dtype = dt + + if dpnp.isscalar(start) and dpnp.isscalar(stop): + # Call linspace() function for scalars. + res = dpnp_container.linspace( + start, + stop, + num, + dtype=dt, + usm_type=_usm_type, + sycl_queue=sycl_queue_normalized, + endpoint=endpoint, + ) + + else: + _start = _copy_by_usm_type( + start, dt, usm_type, _usm_type, sycl_queue_normalized + ) + _stop = _copy_by_usm_type( + stop, dt, usm_type, _usm_type, sycl_queue_normalized + ) + res = dpnp_linspace( + _start, + _stop, + num=num, + usm_type=_usm_type, + sycl_queue=sycl_queue_normalized, + endpoint=endpoint, + axis=axis, + ) + + _base = _copy_by_usm_type( + base, dt, usm_type, _usm_type, sycl_queue_normalized + ) + + _base = dpnp.expand_dims(_base, axis=axis) + if dtype is None: + return dpnp.power(_base, res) + return dpnp.power(_base, res).astype(dtype, copy=False) diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 2a8d80fc389..172ee5ea794 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -50,6 +50,12 @@ from dpnp.dpnp_algo import * from dpnp.dpnp_utils import * +from .dpnp_algo.dpnp_arraycreation import ( + dpnp_geomspace, + dpnp_linspace, + dpnp_logspace, +) + __all__ = [ "arange", "array", @@ -1019,16 +1025,24 @@ def full_like( return numpy.full_like(x1, fill_value, dtype, order, subok, shape) -def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): +def geomspace( + start, + stop, + /, + num, + *, + dtype=None, + device=None, + usm_type=None, + sycl_queue=None, + endpoint=True, + axis=0, +): """ Return numbers spaced evenly on a log scale (a geometric progression). For full documentation refer to :obj:`numpy.geomspace`. - Limitations - ----------- - Parameter `axis` is supported only with default value ``0``. - See Also -------- :obj:`dpnp.logspace` : Similar to geomspace, but with endpoints specified @@ -1041,24 +1055,25 @@ def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): Examples -------- >>> import dpnp as np - >>> x = np.geomspace(1, 1000, num=4) - >>> [i for i in x] - [1.0, 10.0, 100.0, 1000.0] + >>> np.geomspace(1, 1000, num=4) + array([ 1., 10., 100., 1000.]) + >>> x2 = np.geomspace(1, 1000, num=4, endpoint=False) - >>> [i for i in x2] - [1.0, 5.62341325, 31.6227766, 177.827941] + array([ 1. , 5.62341325, 31.6227766 , 177.827941 ]) """ - if not use_origin_backend(): - if axis != 0: - pass - else: - return dpnp_geomspace( - start, stop, num, endpoint, dtype, axis - ).get_pyobj() - - return call_origin(numpy.geomspace, start, stop, num, endpoint, dtype, axis) + return dpnp_geomspace( + start, + stop, + num, + dtype=dtype, + device=device, + usm_type=usm_type, + sycl_queue=sycl_queue, + endpoint=endpoint, + axis=axis, + ) def identity( @@ -1135,9 +1150,8 @@ def linspace( Limitations ----------- - Parameter `axis` is supported only with default value ``0``. Parameter `retstep` is supported only with default value ``False``. - Otherwise the function will be executed sequentially on CPU. + Otherwise ``NotImplementedError`` exception will be raised. See Also -------- @@ -1151,36 +1165,29 @@ def linspace( Examples -------- >>> import dpnp as np - >>> x = np.linspace(2.0, 3.0, num=5) - >>> [i for i in x] - [2.0, 2.25, 2.5, 2.75, 3.0] - >>> x2 = np.linspace(2.0, 3.0, num=5, endpoint=False) - >>> [i for i in x2] - [2.0, 2.2, 2.4, 2.6, 2.8] - >>> x3, step = np.linspace(2.0, 3.0, num=5, retstep=True) - >>> [i for i in x3], step - ([2.0, 2.25, 2.5, 2.75, 3.0], 0.25) + >>> np.linspace(2.0, 3.0, num=5) + array([2. , 2.25, 2.5 , 2.75, 3. ]) + + >>> np.linspace(2.0, 3.0, num=5, endpoint=False) + array([2. , 2.2, 2.4, 2.6, 2.8]) """ if retstep is not False: - pass - elif axis != 0: - pass - else: - return dpnp_linspace( - start, - stop, - num, - dtype=dtype, - device=device, - usm_type=usm_type, - sycl_queue=sycl_queue, - endpoint=endpoint, + raise NotImplementedError( + f"retstep={retstep} is currently not supported" ) - return call_origin( - numpy.linspace, start, stop, num, endpoint, retstep, dtype, axis + return dpnp_linspace( + start, + stop, + num, + dtype=dtype, + device=device, + usm_type=usm_type, + sycl_queue=sycl_queue, + endpoint=endpoint, + axis=axis, ) @@ -1210,16 +1217,25 @@ def loadtxt(fname, **kwargs): return call_origin(numpy.loadtxt, fname, **kwargs) -def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0): +def logspace( + start, + stop, + /, + num=50, + *, + device=None, + usm_type=None, + sycl_queue=None, + endpoint=True, + base=10.0, + dtype=None, + axis=0, +): """ Return numbers spaced evenly on a log scale. For full documentation refer to :obj:`numpy.logspace`. - Limitations - ----------- - Parameter `axis` is supported only with default value ``0``. - See Also -------- :obj:`dpnp.arange` : Similar to linspace, with the step size specified @@ -1234,28 +1250,28 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0): Examples -------- >>> import dpnp as np - >>> x = np.logspace(2.0, 3.0, num=4) - >>> [i for i in x] - [100.0, 215.443469, 464.15888336, 1000.0] - >>> x2 = np.logspace(2.0, 3.0, num=4, endpoint=False) - >>> [i for i in x2] - [100.0, 177.827941, 316.22776602, 562.34132519] - >>> x3 = np.logspace(2.0, 3.0, num=4, base=2.0) - >>> [i for i in x3] - [4.0, 5.0396842, 6.34960421, 8.0] + >>> np.logspace(2.0, 3.0, num=4) + array([ 100. , 215.443469 , 464.15888336, 1000. ]) - """ + >>> np.logspace(2.0, 3.0, num=4, endpoint=False) + array([100. , 177.827941 , 316.22776602, 562.34132519]) - if not use_origin_backend(): - if axis != 0: - checker_throw_value_error("linspace", "axis", axis, 0) + >>> np.logspace(2.0, 3.0, num=4, base=2.0) + array([4. , 5.0396842 , 6.34960421, 8. ]) - return dpnp_logspace( - start, stop, num, endpoint, base, dtype, axis - ).get_pyobj() + """ - return call_origin( - numpy.logspace, start, stop, num, endpoint, base, dtype, axis + return dpnp_logspace( + start, + stop, + num=num, + device=device, + usm_type=usm_type, + sycl_queue=sycl_queue, + endpoint=endpoint, + base=base, + dtype=dtype, + axis=axis, ) diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index 7cfab9a6263..e2c41ceb7df 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -221,7 +221,6 @@ tests/third_party/cupy/creation_tests/test_ranges.py::TestMgrid::test_mgrid3 tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid3 tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid4 tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid5 -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_array_start_stop_axis1 tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_one_num_no_endopoint_with_retstep tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_with_retstep tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_zero_num_no_endopoint_with_retstep diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 7ba437240c4..9bc18c56dd8 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -343,11 +343,9 @@ tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid4 tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid5 tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_arange_negative_size tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_arange_no_dtype_int -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_array_start_stop_axis1 tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_one_num_no_endopoint_with_retstep tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_with_retstep tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_zero_num_no_endopoint_with_retstep -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_logspace_zero_num tests/third_party/cupy/fft_tests/test_fft.py::TestFft2_param_1_{axes=None, norm=None, s=(1, None), shape=(3, 4)}::test_fft2 tests/third_party/cupy/fft_tests/test_fft.py::TestFft2_param_7_{axes=(), norm=None, s=None, shape=(3, 4)}::test_fft2 diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index 9c7fd6bf060..652ddd6ee69 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -201,7 +201,6 @@ def test_fromstring(dtype): assert_array_equal(func(dpnp), func(numpy)) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize("dtype", get_all_dtypes()) @pytest.mark.parametrize("num", [2, 4, 8, 3, 9, 27]) @pytest.mark.parametrize("endpoint", [True, False]) @@ -209,17 +208,14 @@ def test_geomspace(dtype, num, endpoint): start = 2 stop = 256 - func = lambda xp: xp.geomspace(start, stop, num, endpoint, dtype) + func = lambda xp: xp.geomspace( + start, stop, num, endpoint=endpoint, dtype=dtype + ) np_res = func(numpy) dpnp_res = func(dpnp) - # Note that the above may not produce exact integers: - # (c) https://numpy.org/doc/stable/reference/generated/numpy.geomspace.html - if dtype in [numpy.int64, numpy.int32]: - assert_allclose(dpnp_res, np_res, atol=1) - else: - assert_allclose(dpnp_res, np_res) + assert_allclose(dpnp_res, np_res) @pytest.mark.parametrize("n", [0, 1, 4], ids=["0", "1", "4"]) @@ -716,3 +712,8 @@ def test_set_shape(shape): da.shape = shape assert_array_equal(na, da) + + +def test_linspace_retstep_error(): + with pytest.raises(NotImplementedError): + dpnp.linspace(2, 5, 3, retstep=True) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index e7e649de290..4d7e29c1400 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -85,8 +85,10 @@ def vvsort(val, vec, size, xp): pytest.param("arange", [-25.7], {"stop": 10**8, "step": 15}), pytest.param("full", [(2, 2)], {"fill_value": 5}), pytest.param("eye", [4, 2], {}), + pytest.param("geomspace", [1, 4, 8], {}), pytest.param("identity", [4], {}), pytest.param("linspace", [0, 4, 8], {}), + pytest.param("logspace", [0, 4, 8], {}), pytest.param("ones", [(2, 2)], {}), pytest.param("tri", [3, 5, 2], {}), pytest.param("zeros", [(2, 2)], {}), @@ -140,12 +142,16 @@ def test_empty_like(device_x, device_y): "func, args, kwargs", [ pytest.param("full_like", ["x0"], {"fill_value": 5}), + pytest.param("geomspace", ["x0[0:3]", "8", "4"], {}), + pytest.param("geomspace", ["1", "x0[3:5]", "4"], {}), + pytest.param("linspace", ["x0[0:2]", "8", "4"], {}), + pytest.param("linspace", ["0", "x0[3:5]", "4"], {}), + pytest.param("logspace", ["x0[0:2]", "8", "4"], {}), + pytest.param("logspace", ["0", "x0[3:5]", "4"], {}), pytest.param("ones_like", ["x0"], {}), - pytest.param("zeros_like", ["x0"], {}), pytest.param("tril", ["x0.reshape((2,2))"], {}), pytest.param("triu", ["x0.reshape((2,2))"], {}), - pytest.param("linspace", ["x0", "4", "4"], {}), - pytest.param("linspace", ["1", "x0", "4"], {}), + pytest.param("zeros_like", ["x0"], {}), ], ) @pytest.mark.parametrize( diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 122f7165158..1192384d572 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -140,13 +140,17 @@ def test_coerced_usm_types_power(usm_type_x, usm_type_y): @pytest.mark.parametrize( "func, args", [ + pytest.param("empty_like", ["x0"]), pytest.param("full", ["10", "x0[3]"]), pytest.param("full_like", ["x0", "4"]), - pytest.param("zeros_like", ["x0"]), - pytest.param("ones_like", ["x0"]), - pytest.param("empty_like", ["x0"]), - pytest.param("linspace", ["x0[0:2]", "4", "4"]), + pytest.param("geomspace", ["x0[0:3]", "8", "4"]), + pytest.param("geomspace", ["1", "x0[3:5]", "4"]), + pytest.param("linspace", ["x0[0:2]", "8", "4"]), pytest.param("linspace", ["0", "x0[3:5]", "4"]), + pytest.param("logspace", ["x0[0:2]", "8", "4"]), + pytest.param("logspace", ["0", "x0[3:5]", "4"]), + pytest.param("ones_like", ["x0"]), + pytest.param("zeros_like", ["x0"]), ], ) @pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types) @@ -168,8 +172,10 @@ def test_array_creation_from_an_array(func, args, usm_type_x, usm_type_y): pytest.param("arange", [-25.7], {"stop": 10**8, "step": 15}), pytest.param("full", [(2, 2)], {"fill_value": 5}), pytest.param("eye", [4, 2], {}), + pytest.param("geomspace", [1, 4, 8], {}), pytest.param("identity", [4], {}), pytest.param("linspace", [0, 4, 8], {}), + pytest.param("logspace", [0, 4, 8], {}), pytest.param("ones", [(2, 2)], {}), pytest.param("tri", [3, 5, 2], {}), pytest.param("zeros", [(2, 2)], {}), @@ -189,6 +195,18 @@ def test_array_creation_from_scratch(func, arg, kwargs, usm_type): assert dpnp_array.usm_type == usm_type +@pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types) +@pytest.mark.parametrize("usm_type_y", list_of_usm_types, ids=list_of_usm_types) +def test_logspace_base(usm_type_x, usm_type_y): + x0 = dp.full(10, 2, usm_type=usm_type_x) + + x = dp.logspace([2, 2], 8, 4, base=x0[3:5]) + y = dp.logspace([2, 2], 8, 4, base=x0[3:5], usm_type=usm_type_y) + + assert x.usm_type == usm_type_x + assert y.usm_type == usm_type_y + + @pytest.mark.parametrize( "func", [ diff --git a/tests/third_party/cupy/creation_tests/test_ranges.py b/tests/third_party/cupy/creation_tests/test_ranges.py index be2f113a318..46b1fbe9180 100644 --- a/tests/third_party/cupy/creation_tests/test_ranges.py +++ b/tests/third_party/cupy/creation_tests/test_ranges.py @@ -214,13 +214,11 @@ def test_linspace_start_stop_list(self, xp, dtype): stop = [100, 16] return xp.linspace(start, stop, num=50, dtype=dtype) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_logspace(self, xp, dtype): return xp.logspace(0, 2, 5, dtype=dtype) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_logspace2(self, xp, dtype): @@ -231,29 +229,24 @@ def test_logspace2(self, xp, dtype): def test_logspace_zero_num(self, xp, dtype): return xp.logspace(0, 2, 0, dtype=dtype) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_logspace_one_num(self, xp, dtype): return xp.logspace(0, 2, 1, dtype=dtype) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_logspace_no_endpoint(self, xp, dtype): return xp.logspace(0, 2, 5, dtype=dtype, endpoint=False) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.numpy_cupy_allclose(rtol=1e-4, type_check=has_support_aspect64()) def test_logspace_no_dtype_int(self, xp): return xp.logspace(0, 2) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.numpy_cupy_allclose(rtol=1e-4, type_check=has_support_aspect64()) def test_logspace_no_dtype_float(self, xp): return xp.logspace(0.0, 2.0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.numpy_cupy_allclose() def test_logspace_float_args_with_int_dtype(self, xp): return xp.logspace(0.1, 2.1, 11, dtype=int) @@ -263,7 +256,6 @@ def test_logspace_neg_num(self): with pytest.raises(ValueError): xp.logspace(0, 10, -1) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose(rtol=1e-04) def test_logspace_base(self, xp, dtype): From 1f559fba8deb1139fd60b1c7e0ad9d0452bbc4a5 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Thu, 19 Oct 2023 12:53:20 -0500 Subject: [PATCH 2/9] Added more test for geomspace and logspace functions --- dpnp/dpnp_algo/dpnp_arraycreation.py | 8 +-- tests/test_arraycreation.py | 90 ++++++++++++++++++++++------ 2 files changed, 77 insertions(+), 21 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_arraycreation.py b/dpnp/dpnp_algo/dpnp_arraycreation.py index dd75d62c686..6f2ebe1516a 100644 --- a/dpnp/dpnp_algo/dpnp_arraycreation.py +++ b/dpnp/dpnp_algo/dpnp_arraycreation.py @@ -99,9 +99,9 @@ def dpnp_geomspace( both_negative = (dpnp.sign(start) == -1) & (dpnp.sign(stop) == -1) if dpnp.any(both_negative): - dpnp.negative(start, out=start, where=both_negative) - dpnp.negative(stop, out=stop, where=both_negative) - dpnp.negative(out_sign, out=out_sign, where=both_negative) + dpnp.negative(start[both_negative], out=start[both_negative]) + dpnp.negative(stop[both_negative], out=stop[both_negative]) + dpnp.negative(out_sign[both_negative], out=out_sign[both_negative]) log_start = dpnp.log10(start) log_stop = dpnp.log10(stop) @@ -271,7 +271,7 @@ def dpnp_logspace( base, dt, usm_type, _usm_type, sycl_queue_normalized ) - _base = dpnp.expand_dims(_base, axis=axis) + print(res.shape) if dtype is None: return dpnp.power(_base, res) return dpnp.power(_base, res).astype(dtype, copy=False) diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index 652ddd6ee69..e159b8a7885 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -201,23 +201,6 @@ def test_fromstring(dtype): assert_array_equal(func(dpnp), func(numpy)) -@pytest.mark.parametrize("dtype", get_all_dtypes()) -@pytest.mark.parametrize("num", [2, 4, 8, 3, 9, 27]) -@pytest.mark.parametrize("endpoint", [True, False]) -def test_geomspace(dtype, num, endpoint): - start = 2 - stop = 256 - - func = lambda xp: xp.geomspace( - start, stop, num, endpoint=endpoint, dtype=dtype - ) - - np_res = func(numpy) - dpnp_res = func(dpnp) - - assert_allclose(dpnp_res, np_res) - - @pytest.mark.parametrize("n", [0, 1, 4], ids=["0", "1", "4"]) @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_identity(n, dtype): @@ -690,6 +673,12 @@ def test_linspace_complex(): assert_allclose(func(numpy), func(dpnp)) +@pytest.mark.parametrize("axis", [0, 1]) +def test_linspace_axis(axis): + func = lambda xp: xp.linspace([2, 3], [20, 15], num=10, axis=axis) + assert_allclose(func(numpy), func(dpnp)) + + @pytest.mark.parametrize( "arrays", [[], [[1]], [[1, 2, 3], [4, 5, 6]], [[1, 2], [3, 4], [5, 6]]], @@ -717,3 +706,70 @@ def test_set_shape(shape): def test_linspace_retstep_error(): with pytest.raises(NotImplementedError): dpnp.linspace(2, 5, 3, retstep=True) + + +def test_space_num_error(): + with pytest.raises(ValueError): + dpnp.linspace(2, 5, -3) + dpnp.geomspace(2, 5, -3) + dpnp.logspace(2, 5, -3) + + +@pytest.mark.parametrize("sign", [-1, 1]) +@pytest.mark.parametrize("dtype", get_all_dtypes()) +@pytest.mark.parametrize("num", [2, 4, 8, 3, 9, 27]) +@pytest.mark.parametrize("endpoint", [True, False]) +def test_geomspace(sign, dtype, num, endpoint): + start = 2 * sign + stop = 256 * sign + + func = lambda xp: xp.geomspace( + start, stop, num, endpoint=endpoint, dtype=dtype + ) + + np_res = func(numpy) + dpnp_res = func(dpnp) + + assert_allclose(dpnp_res, np_res) + + +@pytest.mark.usefixtures("allow_fall_back_on_numpy") +# dpnp.sign raise numpy fall back for complex dtype +def test_geomspace_complex(): + func = lambda xp: xp.geomspace(1j, 10j, num=10) + assert_allclose(func(numpy), func(dpnp)) + + +@pytest.mark.parametrize("axis", [0, 1]) +def test_geomspace_axis(axis): + func = lambda xp: xp.geomspace([2, 3], [20, 15], num=10, axis=axis) + assert_allclose(func(numpy), func(dpnp)) + + +@pytest.mark.parametrize("dtype", get_all_dtypes()) +@pytest.mark.parametrize("num", [2, 4, 8, 3, 9, 27]) +@pytest.mark.parametrize("base", [-2, 2]) +@pytest.mark.parametrize("endpoint", [True, False]) +def test_logspace(dtype, num, endpoint, base): + start = 2 + stop = 5 + + func = lambda xp: xp.logspace( + start, stop, num, endpoint=endpoint, dtype=dtype, base=base + ) + + np_res = func(numpy) + dpnp_res = func(dpnp) + + if dtype in [numpy.int64, numpy.int32]: + assert_allclose(dpnp_res, np_res, rtol=1) + else: + assert_allclose(dpnp_res, np_res) + + +@pytest.mark.parametrize("axis", [0, 1]) +def test_logspace_axis(axis): + func = lambda xp: xp.logspace( + [2, 3], [20, 15], num=2, base=[[1, 3], [5, 7]], axis=axis + ) + assert_allclose(func(numpy), func(dpnp)) From e64576f8c6b18a3c5e6bf0ce1437e51ac4ce5991 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Thu, 19 Oct 2023 15:40:41 -0500 Subject: [PATCH 3/9] Added tests for geomspace zero error --- dpnp/dpnp_algo/dpnp_arraycreation.py | 2 -- tests/test_arraycreation.py | 10 ++++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_arraycreation.py b/dpnp/dpnp_algo/dpnp_arraycreation.py index 6f2ebe1516a..28a8d1e8df5 100644 --- a/dpnp/dpnp_algo/dpnp_arraycreation.py +++ b/dpnp/dpnp_algo/dpnp_arraycreation.py @@ -235,8 +235,6 @@ def dpnp_logspace( dt = numpy.result_type(start, stop, float(num)) dt = utils.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) - if dtype is None: - dtype = dt if dpnp.isscalar(start) and dpnp.isscalar(stop): # Call linspace() function for scalars. diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index e159b8a7885..36d82acc1a6 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -708,11 +708,21 @@ def test_linspace_retstep_error(): dpnp.linspace(2, 5, 3, retstep=True) +def test_geomspace_zero_error(): + with pytest.raises(ValueError): + dpnp.geomspace(0, 5, 3) + dpnp.geomspace(2, 0, 3) + dpnp.geomspace(0, 0, 3) + + def test_space_num_error(): with pytest.raises(ValueError): dpnp.linspace(2, 5, -3) dpnp.geomspace(2, 5, -3) dpnp.logspace(2, 5, -3) + dpnp.linspace([2, 3], 5, -3) + dpnp.geomspace([2, 3], 5, -3) + dpnp.logspace([2, 3], 5, -3) @pytest.mark.parametrize("sign", [-1, 1]) From 3470248a51b5ef3c8c419e87d32628de6c9b8cd9 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Tue, 31 Oct 2023 03:30:16 -0500 Subject: [PATCH 4/9] address comments --- dpnp/dpnp_algo/dpnp_arraycreation.py | 205 ++++++++---------- dpnp/dpnp_iface_arraycreation.py | 11 +- tests/skipped_tests.tbl | 3 - tests/skipped_tests_gpu.tbl | 3 - tests/test_arraycreation.py | 40 ++-- .../cupy/creation_tests/test_ranges.py | 41 ++++ 6 files changed, 158 insertions(+), 145 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_arraycreation.py b/dpnp/dpnp_algo/dpnp_arraycreation.py index 28a8d1e8df5..f7c315c42e5 100644 --- a/dpnp/dpnp_algo/dpnp_arraycreation.py +++ b/dpnp/dpnp_algo/dpnp_arraycreation.py @@ -13,45 +13,6 @@ ] -def _get_sycl_queue(sycl_queue_alloc, sycl_queue, device): - if sycl_queue is None and device is None: - sycl_queue = sycl_queue_alloc - return dpnp.get_normalized_queue_device( - sycl_queue=sycl_queue, device=device - ) - - -def _get_temporary_usm_type(usm_type_alloc, usm_type): - if usm_type is None: - usm_type = "device" if usm_type_alloc is None else usm_type_alloc - return usm_type - - -def _list_to_array(a, usm_type, sycl_queue, scalar=False): - if not hasattr(a, "dtype") and (scalar or not dpnp.isscalar(a)): - return dpnp.asarray(a, usm_type=usm_type, sycl_queue=sycl_queue) - return a - - -def _copy_by_usm_type(a, dtype, usm_type, tmp_usm_type, sycl_queue_normalized): - if usm_type is None: - usm_type = tmp_usm_type - if not hasattr(a, "usm_type"): - res = dpnp.asarray( - a, - dtype=dtype, - usm_type=usm_type, - sycl_queue=sycl_queue_normalized, - ) - else: - res = dpnp.asarray(a, dtype=dtype, sycl_queue=sycl_queue_normalized) - else: - res = dpnp.asarray( - a, dtype=dtype, usm_type=usm_type, sycl_queue=sycl_queue_normalized - ) - return res - - def dpnp_geomspace( start, stop, @@ -65,14 +26,25 @@ def dpnp_geomspace( ): usm_type_alloc, sycl_queue_alloc = utils.get_usm_allocations([start, stop]) - sycl_queue_normalized = _get_sycl_queue( - sycl_queue_alloc, sycl_queue, device + if sycl_queue is None and device is None: + sycl_queue = sycl_queue_alloc + sycl_queue_normalized = dpnp.get_normalized_queue_device( + sycl_queue=sycl_queue, device=device ) - _usm_type = _get_temporary_usm_type(usm_type_alloc, usm_type) + if usm_type is None: + _usm_type = "device" if usm_type_alloc is None else usm_type_alloc + else: + _usm_type = usm_type - start = _list_to_array(start, _usm_type, sycl_queue_normalized, scalar=True) - stop = _list_to_array(stop, _usm_type, sycl_queue_normalized, scalar=True) + if not hasattr(start, "dtype"): + start = dpnp.asarray( + start, usm_type=_usm_type, sycl_queue=sycl_queue_normalized + ) + if not hasattr(stop, "dtype"): + stop = dpnp.asarray( + stop, usm_type=_usm_type, sycl_queue=sycl_queue_normalized + ) dt = numpy.result_type(start, stop, float(num)) dt = utils.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) @@ -138,24 +110,46 @@ def dpnp_linspace( usm_type=None, sycl_queue=None, endpoint=True, + retstep=False, axis=0, ): usm_type_alloc, sycl_queue_alloc = utils.get_usm_allocations([start, stop]) - sycl_queue_normalized = _get_sycl_queue( - sycl_queue_alloc, sycl_queue, device + if sycl_queue is None and device is None: + sycl_queue = sycl_queue_alloc + sycl_queue_normalized = dpnp.get_normalized_queue_device( + sycl_queue=sycl_queue, device=device ) - _usm_type = _get_temporary_usm_type(usm_type_alloc, usm_type) + if usm_type is None: + _usm_type = "device" if usm_type_alloc is None else usm_type_alloc + else: + _usm_type = usm_type - start = _list_to_array(start, _usm_type, sycl_queue_normalized) - stop = _list_to_array(stop, _usm_type, sycl_queue_normalized) + if not hasattr(start, "dtype") and not dpnp.isscalar(start): + start = dpnp.asarray( + start, usm_type=_usm_type, sycl_queue=sycl_queue_normalized + ) + if not hasattr(stop, "dtype") and not dpnp.isscalar(stop): + stop = dpnp.asarray( + stop, usm_type=_usm_type, sycl_queue=sycl_queue_normalized + ) dt = numpy.result_type(start, stop, float(num)) dt = utils.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) if dtype is None: dtype = dt + num = operator.index(num) + if num < 0: + raise ValueError("Number of points must be non-negative") + step_num = (num - 1) if endpoint else num + + step_nan = False + if step_num == 0: + step_nan = True + step = dpnp.nan + if dpnp.isscalar(start) and dpnp.isscalar(stop): # Call linspace() function for scalars. res = dpnp_container.linspace( @@ -167,22 +161,19 @@ def dpnp_linspace( sycl_queue=sycl_queue_normalized, endpoint=endpoint, ) + if retstep is True and step_nan is False: + step = (stop - start) / step_num else: - num = operator.index(num) - if num < 0: - raise ValueError("Number of points must be non-negative") - - _start = _copy_by_usm_type( - start, dt, usm_type, _usm_type, sycl_queue_normalized + _start = dpnp.asarray( + start, + dtype=dt, + usm_type=_usm_type, + sycl_queue=sycl_queue_normalized, ) - _stop = _copy_by_usm_type( - stop, dt, usm_type, _usm_type, sycl_queue_normalized + _stop = dpnp.asarray( + stop, dtype=dt, usm_type=_usm_type, sycl_queue=sycl_queue_normalized ) - _num = (num - 1) if endpoint else num - - step = (_stop - _start) / _num - res = dpnp_container.arange( 0, stop=num, @@ -192,8 +183,10 @@ def dpnp_linspace( sycl_queue=sycl_queue_normalized, ) - res = res.reshape((-1,) + (1,) * step.ndim) - res = res * step + _start + if step_nan is False: + step = (_stop - _start) / step_num + res = res.reshape((-1,) + (1,) * step.ndim) + res = res * step + _start if endpoint and num > 1: res[-1] = dpnp_container.full(step.shape, _stop) @@ -204,7 +197,16 @@ def dpnp_linspace( if numpy.issubdtype(dtype, dpnp.integer): dpnp.floor(res, out=res) - return res.astype(dtype, copy=False) + res = res.astype(dtype, copy=False) + + if retstep is True: + if dpnp.isscalar(step): + step = dpnp.asarray( + step, usm_type=res.usm_type, sycl_queue=res.sycl_queue + ) + return [res, step] + + return res def dpnp_logspace( @@ -219,57 +221,38 @@ def dpnp_logspace( dtype=None, axis=0, ): - usm_type_alloc, sycl_queue_alloc = utils.get_usm_allocations( - [start, stop, base] - ) - - sycl_queue_normalized = _get_sycl_queue( - sycl_queue_alloc, sycl_queue, device - ) - - _usm_type = _get_temporary_usm_type(usm_type_alloc, usm_type) - - start = _list_to_array(start, _usm_type, sycl_queue_normalized) - stop = _list_to_array(stop, _usm_type, sycl_queue_normalized) - base = _list_to_array(base, _usm_type, sycl_queue_normalized) - - dt = numpy.result_type(start, stop, float(num)) - dt = utils.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) - - if dpnp.isscalar(start) and dpnp.isscalar(stop): - # Call linspace() function for scalars. - res = dpnp_container.linspace( - start, - stop, - num, - dtype=dt, - usm_type=_usm_type, - sycl_queue=sycl_queue_normalized, - endpoint=endpoint, + if not dpnp.isscalar(base): + usm_type_alloc, sycl_queue_alloc = utils.get_usm_allocations( + [start, stop, base] ) - else: - _start = _copy_by_usm_type( - start, dt, usm_type, _usm_type, sycl_queue_normalized - ) - _stop = _copy_by_usm_type( - stop, dt, usm_type, _usm_type, sycl_queue_normalized - ) - res = dpnp_linspace( - _start, - _stop, - num=num, - usm_type=_usm_type, - sycl_queue=sycl_queue_normalized, - endpoint=endpoint, - axis=axis, + if sycl_queue is None and device is None: + sycl_queue = sycl_queue_alloc + sycl_queue = dpnp.get_normalized_queue_device( + sycl_queue=sycl_queue, device=device ) - _base = _copy_by_usm_type( - base, dt, usm_type, _usm_type, sycl_queue_normalized + if usm_type is None: + usm_type = "device" if usm_type_alloc is None else usm_type_alloc + else: + usm_type = usm_type + start = dpnp.asarray(start, usm_type=usm_type, sycl_queue=sycl_queue) + stop = dpnp.asarray(stop, usm_type=usm_type, sycl_queue=sycl_queue) + base = dpnp.asarray(base, usm_type=usm_type, sycl_queue=sycl_queue) + [start, stop, base] = dpnp.broadcast_arrays(start, stop, base) + base = dpnp.expand_dims(base, axis=axis) + + res = dpnp_linspace( + start, + stop, + num=num, + device=device, + usm_type=usm_type, + sycl_queue=sycl_queue, + endpoint=endpoint, + axis=axis, ) - print(res.shape) if dtype is None: - return dpnp.power(_base, res) - return dpnp.power(_base, res).astype(dtype, copy=False) + return dpnp.power(base, res) + return dpnp.power(base, res).astype(dtype, copy=False) diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 172ee5ea794..8163395fbcc 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -1148,11 +1148,6 @@ def linspace( For full documentation refer to :obj:`numpy.linspace`. - Limitations - ----------- - Parameter `retstep` is supported only with default value ``False``. - Otherwise ``NotImplementedError`` exception will be raised. - See Also -------- :obj:`dpnp.arange` : Similar to `linspace`, but uses a step size (instead @@ -1173,11 +1168,6 @@ def linspace( """ - if retstep is not False: - raise NotImplementedError( - f"retstep={retstep} is currently not supported" - ) - return dpnp_linspace( start, stop, @@ -1187,6 +1177,7 @@ def linspace( usm_type=usm_type, sycl_queue=sycl_queue, endpoint=endpoint, + retstep=retstep, axis=axis, ) diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index 5bc6d3ca838..c7908909831 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -204,9 +204,6 @@ tests/third_party/cupy/creation_tests/test_ranges.py::TestMgrid::test_mgrid3 tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid3 tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid4 tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid5 -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_one_num_no_endopoint_with_retstep -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_with_retstep -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_zero_num_no_endopoint_with_retstep tests/third_party/cupy/indexing_tests/test_generate.py::TestAxisConcatenator::test_AxisConcatenator_init1 tests/third_party/cupy/indexing_tests/test_generate.py::TestAxisConcatenator::test_len tests/third_party/cupy/indexing_tests/test_generate.py::TestC_::test_c_1 diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 64630dca237..c3ed9154b53 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -322,9 +322,6 @@ tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid4 tests/third_party/cupy/creation_tests/test_ranges.py::TestOgrid::test_ogrid5 tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_arange_negative_size tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_arange_no_dtype_int -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_one_num_no_endopoint_with_retstep -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_with_retstep -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_zero_num_no_endopoint_with_retstep tests/third_party/cupy/fft_tests/test_fft.py::TestFft2_param_1_{axes=None, norm=None, s=(1, None), shape=(3, 4)}::test_fft2 tests/third_party/cupy/fft_tests/test_fft.py::TestFft2_param_7_{axes=(), norm=None, s=None, shape=(3, 4)}::test_fft2 diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index 36d82acc1a6..51ba1c87bc1 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -608,23 +608,28 @@ def test_dpctl_tensor_input(func, args): ) @pytest.mark.parametrize( "num", - [5, numpy.array(10), dpnp.array(17), dpt.asarray(100)], - ids=["5", "numpy.array(10)", "dpnp.array(17)", "dpt.asarray(100)"], + [1, 5, numpy.array(10), dpnp.array(17), dpt.asarray(100)], + ids=["1", "5", "numpy.array(10)", "dpnp.array(17)", "dpt.asarray(100)"], ) @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_float16=False) ) -def test_linspace(start, stop, num, dtype): - func = lambda xp: xp.linspace(start, stop, num, dtype=dtype) +@pytest.mark.parametrize("retstep", [True, False], ids=["True", "False"]) +def test_linspace(start, stop, num, dtype, retstep): + res_np = numpy.linspace(start, stop, num, dtype=dtype, retstep=retstep) + res_dp = dpnp.linspace(start, stop, num, dtype=dtype, retstep=retstep) + + if retstep: + [res_np, step_np] = res_np + [res_dp, step_dp] = res_dp + assert_allclose(step_np, step_dp) if numpy.issubdtype(dtype, dpnp.integer): - assert_allclose(func(numpy), func(dpnp), rtol=1) + assert_allclose(res_np, res_dp, rtol=1) else: if dtype is None and not has_support_aspect64(): dtype = dpnp.float32 - assert_allclose( - func(numpy), func(dpnp), rtol=1e-06, atol=numpy.finfo(dtype).eps - ) + assert_allclose(res_np, res_dp, rtol=1e-06, atol=dpnp.finfo(dtype).eps) @pytest.mark.parametrize( @@ -670,13 +675,13 @@ def test_linspace_arrays(start, stop): def test_linspace_complex(): func = lambda xp: xp.linspace(0, 3 + 2j, num=1000) - assert_allclose(func(numpy), func(dpnp)) + assert_allclose(func(dpnp), func(numpy)) @pytest.mark.parametrize("axis", [0, 1]) def test_linspace_axis(axis): func = lambda xp: xp.linspace([2, 3], [20, 15], num=10, axis=axis) - assert_allclose(func(numpy), func(dpnp)) + assert_allclose(func(dpnp), func(numpy)) @pytest.mark.parametrize( @@ -703,11 +708,6 @@ def test_set_shape(shape): assert_array_equal(na, da) -def test_linspace_retstep_error(): - with pytest.raises(NotImplementedError): - dpnp.linspace(2, 5, 3, retstep=True) - - def test_geomspace_zero_error(): with pytest.raises(ValueError): dpnp.geomspace(0, 5, 3) @@ -747,13 +747,13 @@ def test_geomspace(sign, dtype, num, endpoint): # dpnp.sign raise numpy fall back for complex dtype def test_geomspace_complex(): func = lambda xp: xp.geomspace(1j, 10j, num=10) - assert_allclose(func(numpy), func(dpnp)) + assert_allclose(func(dpnp), func(numpy)) @pytest.mark.parametrize("axis", [0, 1]) def test_geomspace_axis(axis): func = lambda xp: xp.geomspace([2, 3], [20, 15], num=10, axis=axis) - assert_allclose(func(numpy), func(dpnp)) + assert_allclose(func(dpnp), func(numpy)) @pytest.mark.parametrize("dtype", get_all_dtypes()) @@ -779,7 +779,11 @@ def test_logspace(dtype, num, endpoint, base): @pytest.mark.parametrize("axis", [0, 1]) def test_logspace_axis(axis): + if numpy.lib.NumpyVersion(numpy.__version__) < "1.25.0": + pytest.skip( + "numpy.logspace supports a non-scalar base argument since 1.25.0" + ) func = lambda xp: xp.logspace( [2, 3], [20, 15], num=2, base=[[1, 3], [5, 7]], axis=axis ) - assert_allclose(func(numpy), func(dpnp)) + assert_allclose(func(dpnp), func(numpy)) diff --git a/tests/third_party/cupy/creation_tests/test_ranges.py b/tests/third_party/cupy/creation_tests/test_ranges.py index 46b1fbe9180..20e01ca8301 100644 --- a/tests/third_party/cupy/creation_tests/test_ranges.py +++ b/tests/third_party/cupy/creation_tests/test_ranges.py @@ -1,3 +1,4 @@ +import functools import math import sys import unittest @@ -10,6 +11,27 @@ from tests.third_party.cupy import testing +def skip_int_equality_before_numpy_1_20(names=("dtype",)): + """Require numpy/numpy#16841 or skip the equality check.""" + + def decorator(wrapped): + if numpy.lib.NumpyVersion(numpy.__version__) >= "1.20.0": + return wrapped + + @functools.wraps(wrapped) + def wrapper(self, *args, **kwargs): + xp = kwargs["xp"] + dtypes = [kwargs[name] for name in names] + ret = wrapped(self, *args, **kwargs) + if any(numpy.issubdtype(dtype, numpy.integer) for dtype in dtypes): + ret = xp.zeros_like(ret) + return ret + + return wrapper + + return decorator + + @testing.gpu class TestRanges(unittest.TestCase): @testing.for_all_dtypes(no_bool=True) @@ -79,6 +101,14 @@ def test_linspace(self, xp, dtype): def test_linspace2(self, xp, dtype): return xp.linspace(10, 0, 5, dtype=dtype) + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + @skip_int_equality_before_numpy_1_20() + def test_linspace3(self, xp, dtype): + if xp.dtype(dtype).kind == "u": + pytest.skip() + return xp.linspace(-10, 8, 9, dtype=dtype) + @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_array_equal() def test_linspace_zero_num(self, xp, dtype): @@ -261,6 +291,17 @@ def test_logspace_neg_num(self): def test_logspace_base(self, xp, dtype): return xp.logspace(0, 2, 5, base=2.0, dtype=dtype) + # See #7946 and https://github.com/numpy/numpy/issues/24957 + @testing.with_requires("numpy>=1.16, !=1.25.*, !=1.26.*") + @testing.for_all_dtypes_combination( + names=("dtype_range", "dtype_out"), no_bool=True, no_complex=True + ) + @testing.numpy_cupy_allclose(rtol=1e-6, contiguous_check=False) + def test_logspace_array_start_stop_axis1(self, xp, dtype_range, dtype_out): + start = xp.array([0, 2], dtype=dtype_range) + stop = xp.array([2, 0], dtype=dtype_range) + return xp.logspace(start, stop, num=5, dtype=dtype_out, axis=1) + @testing.parameterize( *testing.product( From ce2ccffd53c70157bf7b7d4e5172b1025b90685f Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Tue, 31 Oct 2023 14:34:08 -0500 Subject: [PATCH 5/9] Added tests --- dpnp/dpnp_algo/dpnp_arraycreation.py | 2 +- dpnp/dpnp_iface_arraycreation.py | 45 +++++++++++++++++- tests/test_arraycreation.py | 47 +++++++++++++++---- tests/test_sycl_queue.py | 24 ++++++++-- .../cupy/creation_tests/test_ranges.py | 2 +- 5 files changed, 104 insertions(+), 16 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_arraycreation.py b/dpnp/dpnp_algo/dpnp_arraycreation.py index f7c315c42e5..52456550c78 100644 --- a/dpnp/dpnp_algo/dpnp_arraycreation.py +++ b/dpnp/dpnp_algo/dpnp_arraycreation.py @@ -204,7 +204,7 @@ def dpnp_linspace( step = dpnp.asarray( step, usm_type=res.usm_type, sycl_queue=res.sycl_queue ) - return [res, step] + return (res, step) return res diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 8163395fbcc..c43d75be81f 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -1043,6 +1043,11 @@ def geomspace( For full documentation refer to :obj:`numpy.geomspace`. + Returns + ------- + samples : dpnp.ndarray + num samples, equally spaced on a log scale. + See Also -------- :obj:`dpnp.logspace` : Similar to geomspace, but with endpoints specified @@ -1057,9 +1062,22 @@ def geomspace( >>> import dpnp as np >>> np.geomspace(1, 1000, num=4) array([ 1., 10., 100., 1000.]) - - >>> x2 = np.geomspace(1, 1000, num=4, endpoint=False) + >>> np.geomspace(1, 1000, num=3, endpoint=False) + array([ 1., 10., 100.]) + >>> np.geomspace(1, 1000, num=4, endpoint=False) array([ 1. , 5.62341325, 31.6227766 , 177.827941 ]) + >>> np.geomspace(1, 256, num=9) + array([ 1., 2., 4., 8., 16., 32., 64., 128., 256.]) + + >>> np.geomspace(1, 256, num=9, dtype=int) + array([ 1, 2, 4, 7, 16, 32, 63, 127, 256]) + >>> np.around(np.geomspace(1, 256, num=9)).astype(int) + array([ 1, 2, 4, 8, 16, 32, 64, 128, 256]) + + >>> np.geomspace(1000, 1, num=4) + array([1000., 100., 10., 1.]) + >>> np.geomspace(-1000, -1, num=4) + array([-1000., -100., -10., -1.]) """ @@ -1148,6 +1166,17 @@ def linspace( For full documentation refer to :obj:`numpy.linspace`. + Returns + ------- + samples : dpnp.ndarray + There are num equally spaced samples in the closed interval + [`start`, `stop`] or the half-open interval [`start`, `stop`) + (depending on whether `endpoint` is ``True`` or ``False``). + step : float, optional + Only returned if `retstep` is ``True`` + + Size of spacing between samples. + See Also -------- :obj:`dpnp.arange` : Similar to `linspace`, but uses a step size (instead @@ -1166,6 +1195,9 @@ def linspace( >>> np.linspace(2.0, 3.0, num=5, endpoint=False) array([2. , 2.2, 2.4, 2.6, 2.8]) + >>> np.linspace(2.0, 3.0, num=5, retstep=True) + (array([2. , 2.25, 2.5 , 2.75, 3. ]), array(0.25)) + """ return dpnp_linspace( @@ -1227,6 +1259,11 @@ def logspace( For full documentation refer to :obj:`numpy.logspace`. + Returns + ------- + samples : dpnp.ndarray + num samples, equally spaced on a log scale. + See Also -------- :obj:`dpnp.arange` : Similar to linspace, with the step size specified @@ -1250,6 +1287,10 @@ def logspace( >>> np.logspace(2.0, 3.0, num=4, base=2.0) array([4. , 5.0396842 , 6.34960421, 8. ]) + >>> np.logspace(2.0, 3.0, num=4, base=[2.0, 3.0], axis=-1) + array([[ 4. , 5.0396842 , 6.34960421, 8. ], + [ 9. , 12.98024613, 18.72075441, 27. ]]) + """ return dpnp_logspace( diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index 51ba1c87bc1..fa02c127e67 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -684,6 +684,21 @@ def test_linspace_axis(axis): assert_allclose(func(dpnp), func(numpy)) +def test_linspace_step_nan(): + func = lambda xp: xp.linspace(1, 2, num=0, endpoint=False) + assert_allclose(func(dpnp), func(numpy)) + + +@pytest.mark.parametrize("start", [1, [1, 1]]) +@pytest.mark.parametrize("stop", [10, [10 + 10]]) +def test_linspace_retstep(start, stop): + func = lambda xp: xp.linspace(start, stop, num=10, retstep=True) + np_res = func(numpy) + dpnp_res = func(dpnp) + assert_allclose(dpnp_res[0], np_res[0]) + assert_allclose(dpnp_res[1], np_res[1]) + + @pytest.mark.parametrize( "arrays", [[], [[1]], [[1, 2, 3], [4, 5, 6]], [[1, 2], [3, 4], [5, 6]]], @@ -740,29 +755,45 @@ def test_geomspace(sign, dtype, num, endpoint): np_res = func(numpy) dpnp_res = func(dpnp) - assert_allclose(dpnp_res, np_res) + if dtype in [numpy.int64, numpy.int32]: + assert_allclose(dpnp_res, np_res, rtol=1) + else: + assert_allclose(dpnp_res, np_res, rtol=1e-04) @pytest.mark.usefixtures("allow_fall_back_on_numpy") +@pytest.mark.parametrize("start", [1j, 1 + 1j]) +@pytest.mark.parametrize("stop", [10j, 10 + 10j]) # dpnp.sign raise numpy fall back for complex dtype -def test_geomspace_complex(): - func = lambda xp: xp.geomspace(1j, 10j, num=10) - assert_allclose(func(dpnp), func(numpy)) +def test_geomspace_complex(start, stop): + func = lambda xp: xp.geomspace(start, stop, num=10) + np_res = func(numpy) + dpnp_res = func(dpnp) + assert_allclose(dpnp_res, np_res, rtol=1e-04) @pytest.mark.parametrize("axis", [0, 1]) def test_geomspace_axis(axis): func = lambda xp: xp.geomspace([2, 3], [20, 15], num=10, axis=axis) - assert_allclose(func(dpnp), func(numpy)) + np_res = func(numpy) + dpnp_res = func(dpnp) + assert_allclose(dpnp_res, np_res, rtol=1e-04) + + +def test_geomspace_num0(): + func = lambda xp: xp.geomspace(1, 10, num=0, endpoint=False) + np_res = func(numpy) + dpnp_res = func(dpnp) + assert_allclose(dpnp_res, np_res, rtol=1e-04) @pytest.mark.parametrize("dtype", get_all_dtypes()) @pytest.mark.parametrize("num", [2, 4, 8, 3, 9, 27]) -@pytest.mark.parametrize("base", [-2, 2]) @pytest.mark.parametrize("endpoint", [True, False]) -def test_logspace(dtype, num, endpoint, base): +def test_logspace(dtype, num, endpoint): start = 2 stop = 5 + base = 2 func = lambda xp: xp.logspace( start, stop, num, endpoint=endpoint, dtype=dtype, base=base @@ -774,7 +805,7 @@ def test_logspace(dtype, num, endpoint, base): if dtype in [numpy.int64, numpy.int32]: assert_allclose(dpnp_res, np_res, rtol=1) else: - assert_allclose(dpnp_res, np_res) + assert_allclose(dpnp_res, np_res, rtol=1e-04) @pytest.mark.parametrize("axis", [0, 1]) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 4d7e29c1400..33da6e5af4c 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -143,11 +143,11 @@ def test_empty_like(device_x, device_y): [ pytest.param("full_like", ["x0"], {"fill_value": 5}), pytest.param("geomspace", ["x0[0:3]", "8", "4"], {}), - pytest.param("geomspace", ["1", "x0[3:5]", "4"], {}), + pytest.param("geomspace", ["1", "x0[2:4]", "4"], {}), pytest.param("linspace", ["x0[0:2]", "8", "4"], {}), - pytest.param("linspace", ["0", "x0[3:5]", "4"], {}), + pytest.param("linspace", ["0", "x0[2:4]", "4"], {}), pytest.param("logspace", ["x0[0:2]", "8", "4"], {}), - pytest.param("logspace", ["0", "x0[3:5]", "4"], {}), + pytest.param("logspace", ["0", "x0[2:4]", "4"], {}), pytest.param("ones_like", ["x0"], {}), pytest.param("tril", ["x0.reshape((2,2))"], {}), pytest.param("triu", ["x0.reshape((2,2))"], {}), @@ -168,7 +168,23 @@ def test_array_creation_follow_device(func, args, kwargs, device): dpnp_args = [eval(val, {"x0": x}) for val in args] y = getattr(dpnp, func)(*dpnp_args, **kwargs) - assert_allclose(y_orig, y) + assert_allclose(y_orig, y, rtol=1e-04) + assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) + + +@pytest.mark.parametrize( + "device", + valid_devices, + ids=[device.filter_string for device in valid_devices], +) +def test_array_creation_follow_device_logspace_base(device): + x_orig = numpy.array([1, 2, 3, 4]) + y_orig = numpy.logspace(0, 8, 4, base=x_orig[1:3]) + + x = dpnp.array([1, 2, 3, 4], device=device) + y = dpnp.logspace(0, 8, 4, base=x[1:3]) + + assert_allclose(y_orig, y, rtol=1e-04) assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) diff --git a/tests/third_party/cupy/creation_tests/test_ranges.py b/tests/third_party/cupy/creation_tests/test_ranges.py index 20e01ca8301..623adc409b7 100644 --- a/tests/third_party/cupy/creation_tests/test_ranges.py +++ b/tests/third_party/cupy/creation_tests/test_ranges.py @@ -222,7 +222,7 @@ def test_linspace_mixed_start_stop2(self, xp, dtype_range, dtype_out): @testing.for_all_dtypes_combination( names=("dtype_range", "dtype_out"), no_bool=True, no_complex=True ) - @testing.numpy_cupy_array_equal() + @testing.numpy_cupy_allclose(rtol=1e-04) def test_linspace_array_start_stop_axis1(self, xp, dtype_range, dtype_out): start = xp.array([0, 120], dtype=dtype_range) stop = xp.array([100, 0], dtype=dtype_range) From 61241ccd850ab5c13b103616eb4a9e0a404b5591 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Tue, 31 Oct 2023 15:35:34 -0500 Subject: [PATCH 6/9] skip test logspace base --- tests/test_sycl_queue.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 33da6e5af4c..025a3673bcb 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -172,6 +172,10 @@ def test_array_creation_follow_device(func, args, kwargs, device): assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) +@pytest.mark.skipif( + numpy.lib.NumpyVersion(numpy.__version__) < "1.25.0", + reason="numpy.logspace supports a non-scalar base argument since 1.25.0", +) @pytest.mark.parametrize( "device", valid_devices, From 296102b6f77e1e853378414e494f2bd29c27903f Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Mon, 6 Nov 2023 11:39:04 -0600 Subject: [PATCH 7/9] address comments --- dpnp/dpnp_algo/dpnp_arraycreation.py | 4 ++-- dpnp/dpnp_iface_arraycreation.py | 4 ++-- tests/test_arraycreation.py | 9 +++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_arraycreation.py b/dpnp/dpnp_algo/dpnp_arraycreation.py index 52456550c78..b6d3c612068 100644 --- a/dpnp/dpnp_algo/dpnp_arraycreation.py +++ b/dpnp/dpnp_algo/dpnp_arraycreation.py @@ -37,11 +37,11 @@ def dpnp_geomspace( else: _usm_type = usm_type - if not hasattr(start, "dtype"): + if not dpnp.is_supported_array_type(start): start = dpnp.asarray( start, usm_type=_usm_type, sycl_queue=sycl_queue_normalized ) - if not hasattr(stop, "dtype"): + if not dpnp.is_supported_array_type(stop): stop = dpnp.asarray( stop, usm_type=_usm_type, sycl_queue=sycl_queue_normalized ) diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index c43d75be81f..06e365238e1 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -1045,7 +1045,7 @@ def geomspace( Returns ------- - samples : dpnp.ndarray + out : dpnp.ndarray num samples, equally spaced on a log scale. See Also @@ -1168,7 +1168,7 @@ def linspace( Returns ------- - samples : dpnp.ndarray + out : dpnp.ndarray There are num equally spaced samples in the closed interval [`start`, `stop`] or the half-open interval [`start`, `stop`) (depending on whether `endpoint` is ``True`` or ``False``). diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index fa02c127e67..7c674d265da 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -632,6 +632,11 @@ def test_linspace(start, stop, num, dtype, retstep): assert_allclose(res_np, res_dp, rtol=1e-06, atol=dpnp.finfo(dtype).eps) +@pytest.mark.parametrize( + "func", + ["geomspace", "linspace", "logspace"], + ids=["geomspace", "linspace", "logspace"], +) @pytest.mark.parametrize( "start_dtype", [numpy.float64, numpy.float32, numpy.int64, numpy.int32], @@ -642,10 +647,10 @@ def test_linspace(start, stop, num, dtype, retstep): [numpy.float64, numpy.float32, numpy.int64, numpy.int32], ids=["float64", "float32", "int64", "int32"], ) -def test_linspace_dtype(start_dtype, stop_dtype): +def test_space_numpy_dtype(func, start_dtype, stop_dtype): start = numpy.array([1, 2, 3], dtype=start_dtype) stop = numpy.array([11, 7, -2], dtype=stop_dtype) - dpnp.linspace(start, stop, 10) + getattr(dpnp, func)(start, stop, 10) @pytest.mark.parametrize( From 1f6ee26ce8d002dd25099f12bbcd12db0ddda7fd Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Mon, 6 Nov 2023 16:07:11 -0800 Subject: [PATCH 8/9] Fix linspace docs --- dpnp/dpnp_iface_arraycreation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 06e365238e1..51b9966194d 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -1173,9 +1173,8 @@ def linspace( [`start`, `stop`] or the half-open interval [`start`, `stop`) (depending on whether `endpoint` is ``True`` or ``False``). step : float, optional - Only returned if `retstep` is ``True`` - - Size of spacing between samples. + Only returned if `retstep` is ``True``. + Size of spacing between samples. See Also -------- From 6c94a9d3f330647e38edecd435ef4ce0c794a501 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Tue, 7 Nov 2023 12:40:44 -0800 Subject: [PATCH 9/9] Update dpnp/dpnp_iface_arraycreation.py Co-authored-by: Anton <100830759+antonwolfy@users.noreply.github.com> --- dpnp/dpnp_iface_arraycreation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 51b9966194d..0ed1187cb1d 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -1260,7 +1260,7 @@ def logspace( Returns ------- - samples : dpnp.ndarray + out: dpnp.ndarray num samples, equally spaced on a log scale. See Also