From 5e14449bdc9393ad20aa697d104da3060a77eb4c Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Fri, 27 Jan 2023 13:48:23 -0600 Subject: [PATCH 1/9] Use linspace() function from dpctl.tensor --- dpnp/dpnp_container.py | 27 +++++- dpnp/dpnp_iface.py | 34 ++++++- dpnp/dpnp_iface_arraycreation.py | 95 +++++++++++++++++-- tests/skipped_tests_gpu.tbl | 14 +-- .../cupy/creation_tests/test_ranges.py | 10 +- 5 files changed, 152 insertions(+), 28 deletions(-) diff --git a/dpnp/dpnp_container.py b/dpnp/dpnp_container.py index 93ab716eb59a..e93f085681e9 100644 --- a/dpnp/dpnp_container.py +++ b/dpnp/dpnp_container.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # ***************************************************************************** -# Copyright (c) 2016-2022, Intel Corporation +# Copyright (c) 2016-2023, Intel Corporation # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -150,6 +150,31 @@ def full(shape, return dpnp_array(array_obj.shape, buffer=array_obj, order=order) +def linspace(start, + stop, + /, + num, + *, + dtype=None, + device=None, + endpoint=True, + sycl_queue=None, + usm_type="device"): + """Validate input parameters before passing them into `dpctl.tensor` module""" + dpu.validate_usm_type(usm_type, allow_none=False) + sycl_queue_normalized = dpnp.get_normalized_queue_device(sycl_queue=sycl_queue, device=device) + + """Creates `dpnp_array` with evenly spaced numbers of specified interval.""" + array_obj = dpt.linspace(start, + stop, + num, + dtype=dtype, + endpoint=endpoint, + sycl_queue=sycl_queue, + usm_type=usm_type) + return dpnp_array(array_obj.shape, buffer=array_obj) + + def ones(shape, *, dtype=None, diff --git a/dpnp/dpnp_iface.py b/dpnp/dpnp_iface.py index 4e791ad0eaf9..aabfbc30d1ff 100644 --- a/dpnp/dpnp_iface.py +++ b/dpnp/dpnp_iface.py @@ -2,7 +2,7 @@ # distutils: language = c++ # -*- coding: utf-8 -*- # ***************************************************************************** -# Copyright (c) 2016-2022, Intel Corporation +# Copyright (c) 2016-2023, Intel Corporation # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -63,9 +63,12 @@ "convert_single_elem_array_to_scalar", "dpnp_queue_initialize", "dpnp_queue_is_cpu", + "get_coerced_usm_type", "get_dpnp_descriptor", + "get_execution_queue", "get_include", - "get_normalized_queue_device" + "get_normalized_queue_device", + "isarray" ] from dpnp import ( @@ -191,6 +194,16 @@ def convert_single_elem_array_to_scalar(obj, keepdims=False): return obj +def get_coerced_usm_type(usm_types): + """ + Given a list of strings denoting the types of USM allocations + for input arrays returns the type of USM allocation for the output + array(s) per compute follows data paradigm. + Returns `None` if the type can not be deduced. + """ + return dpctl.utils.get_coerced_usm_type(usm_types) + + def get_dpnp_descriptor(ext_obj, copy_when_strides=True, copy_when_nondefault_queue=True, @@ -252,6 +265,15 @@ def get_dpnp_descriptor(ext_obj, return False +def get_execution_queue(qs): + """ + Given a list of :class:`dpctl.SyclQueue` objects + returns the execution queue under compute follows data paradigm, + or returns `None` if queues are not equal. + """ + return dpctl.utils.get_execution_queue(qs) + + def get_include(): """ Return the directory that contains the DPNP C++ backend \\*.h header files. @@ -307,3 +329,11 @@ def get_normalized_queue_device(obj=None, if hasattr(dpt._device, 'normalize_queue_device'): return dpt._device.normalize_queue_device(sycl_queue=sycl_queue, device=device) return sycl_queue + + +def isarray(obj): + """ + Returns True if the type of `obj` is a usm_ndarray type. + + """ + return isinstance(obj, (dpnp_array, dpt.usm_ndarray)) diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 5fb4d8c7a4da..66c625226331 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -2,7 +2,7 @@ # distutils: language = c++ # -*- coding: utf-8 -*- # ***************************************************************************** -# Copyright (c) 2016-2022, Intel Corporation +# Copyright (c) 2016-2023, Intel Corporation # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -867,7 +867,18 @@ def identity(n, dtype=None, *, like=None): return call_origin(numpy.identity, n, dtype=dtype, like=like) -def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): +def linspace(start, + stop, + /, + num, + *, + dtype=None, + device=None, + endpoint=True, + sycl_queue=None, + usm_type=None, + retstep=False, + axis=0): """ Return evenly spaced numbers over a specified interval. @@ -876,6 +887,7 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis Limitations ----------- Parameter ``axis`` is supported only with default value ``0``. + Parameter ``retstep`` is supported only with default value ``False``. See Also -------- @@ -901,16 +913,79 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis """ - if not use_origin_backend(): - if axis != 0: - checker_throw_value_error("linspace", "axis", axis, 0) + if retstep is not False: + pass + elif axis != 0: + pass + elif dpnp.isscalar(start) and dpnp.isscalar(stop): + usm_type = usm_type if usm_type is not None else "device" + dt = None if numpy.issubdtype(dtype, dpnp.integer) else dtype + res = dpnp_container.linspace(start, + stop, + num, + dtype=dt, + device=device, + endpoint=endpoint, + sycl_queue=sycl_queue, + usm_type=usm_type) + if numpy.issubdtype(dtype, dpnp.integer): + dpnp.floor(res, out=res) + res = res.astype(dtype) + return res + else: + start_isarray = dpnp.isarray(start) + stop_isarray = dpnp.isarray(stop) + + if start_isarray and stop_isarray: + dt = numpy.result_type(start.dtype, stop.dtype) + if sycl_queue is None and device is None: + sycl_queue = dpnp.get_execution_queue([start.sycl_queue, stop.sycl_queue]) + if usm_type is None: + usm_type = dpnp.get_coerced_usm_type([start.usm_type, stop.usm_type]) + + elif start_isarray: + dt = start.dtype + if sycl_queue is None and device is None: + sycl_queue = start.sycl_queue + usm_type = start.usm_type if usm_type is None else usm_type + elif stop_isarray: + dt = stop.dtype + if sycl_queue is None and device is None: + sycl_queue = stop.sycl_queue + usm_type = stop.usm_type if usm_type is None else usm_type + else: + dt = numpy.result_type(None) - res = dpnp_linspace(start, stop, num, endpoint, retstep, dtype, axis) + if numpy.issubdtype(dt, dpnp.integer): + dt = numpy.result_type(float(num), dt) + usm_type = usm_type if usm_type is not None else "device" + sycl_queue_normalized = dpnp.get_normalized_queue_device(sycl_queue=sycl_queue, device=device) - if retstep: - return res - else: - return res[0] + _start = array([start] if dpnp.isscalar(start) else start, dtype=dt, + usm_type=usm_type, sycl_queue=sycl_queue_normalized) + _stop = array([stop] if dpnp.isscalar(stop) else stop, dtype=dt, + usm_type=usm_type, sycl_queue=sycl_queue_normalized) + + if dtype is None: + dtype = dt + + step = ((_stop - _start) * (1. / (num - 1) if endpoint else num)).astype(dt) + + 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) return call_origin(numpy.linspace, start, stop, num, endpoint, retstep, dtype, axis) diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 01a2bb21dc92..9d94b1595a3a 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -614,19 +614,13 @@ tests/third_party/cupy/creation_tests/test_ranges.py::TestMgrid::test_mgrid5 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 -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_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_float_underflow -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_mixed_start_stop -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_mixed_start_stop2 -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_start_stop_list - +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 tests/third_party/cupy/fft_tests/test_fft.py::TestFft2_param_7_{axes=(), norm=None, s=None, shape=(3, 4)}::test_ifft2 diff --git a/tests/third_party/cupy/creation_tests/test_ranges.py b/tests/third_party/cupy/creation_tests/test_ranges.py index 75960e492c17..0ffba79b3cba 100644 --- a/tests/third_party/cupy/creation_tests/test_ranges.py +++ b/tests/third_party/cupy/creation_tests/test_ranges.py @@ -121,13 +121,13 @@ def test_linspace_with_retstep(self, xp, dtype): @testing.numpy_cupy_allclose() def test_linspace_no_dtype_int(self, xp): - return xp.linspace(0, 10) + return xp.linspace(0, 10, 50) @testing.numpy_cupy_allclose() def test_linspace_no_dtype_float(self, xp): - return xp.linspace(0.0, 10.0) + return xp.linspace(0.0, 10.0, 50) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_array_equal() def test_linspace_float_args_with_int_dtype(self, xp): return xp.linspace(0.1, 9.1, 11, dtype=int) @@ -151,7 +151,7 @@ def test_linspace_float_underflow(self, xp): @testing.with_requires('numpy>=1.16') @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() def test_linspace_array_start_stop(self, xp, dtype_range, dtype_out): start = xp.array([0, 120], dtype=dtype_range) stop = xp.array([100, 0], dtype=dtype_range) @@ -172,7 +172,7 @@ def test_linspace_mixed_start_stop(self, xp, dtype_range, dtype_out): @testing.with_requires('numpy>=1.16') @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() def test_linspace_mixed_start_stop2(self, xp, dtype_range, dtype_out): if xp.dtype(dtype_range).kind in 'u': start = xp.array([160, 120], dtype=dtype_range) From 806e79d529fb448632289d321b1c46e0802f32cf Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Fri, 27 Jan 2023 13:50:21 -0600 Subject: [PATCH 2/9] Convert file cupy/creation_tests/test_ranges.py to unix --- .../cupy/creation_tests/test_ranges.py | 742 +++++++++--------- 1 file changed, 371 insertions(+), 371 deletions(-) diff --git a/tests/third_party/cupy/creation_tests/test_ranges.py b/tests/third_party/cupy/creation_tests/test_ranges.py index 0ffba79b3cba..137ec7c8e705 100644 --- a/tests/third_party/cupy/creation_tests/test_ranges.py +++ b/tests/third_party/cupy/creation_tests/test_ranges.py @@ -1,371 +1,371 @@ -import math -import sys -import unittest - -import numpy -import pytest - -import dpnp as cupy -from tests.third_party.cupy import testing - - -@testing.gpu -class TestRanges(unittest.TestCase): - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_arange(self, xp, dtype): - return xp.arange(10, dtype=dtype) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_arange2(self, xp, dtype): - return xp.arange(5, 10, dtype=dtype) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_arange3(self, xp, dtype): - return xp.arange(1, 11, 2, dtype=dtype) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_arange4(self, xp, dtype): - return xp.arange(20, 2, -3, dtype=dtype) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_arange5(self, xp, dtype): - return xp.arange(0, 100, None, dtype=dtype) - - @testing.for_all_dtypes() - @testing.numpy_cupy_array_equal() - def test_arange6(self, xp, dtype): - return xp.arange(0, 2, dtype=dtype) - - @testing.for_all_dtypes() - @testing.numpy_cupy_array_equal() - def test_arange7(self, xp, dtype): - return xp.arange(10, 11, dtype=dtype) - - @testing.for_all_dtypes() - @testing.numpy_cupy_array_equal() - def test_arange8(self, xp, dtype): - return xp.arange(10, 8, -1, dtype=dtype) - - def test_arange9(self): - for xp in (numpy, cupy): - with pytest.raises(ValueError): - xp.arange(10, dtype=xp.bool_) - - @testing.numpy_cupy_array_equal() - def test_arange_no_dtype_int(self, xp): - return xp.arange(1, 11, 2) - - @testing.numpy_cupy_array_equal() - def test_arange_no_dtype_float(self, xp): - return xp.arange(1.0, 11.0, 2.0) - - @testing.numpy_cupy_array_equal() - def test_arange_negative_size(self, xp): - return xp.arange(3, 1) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_linspace(self, xp, dtype): - return xp.linspace(0, 10, 5, dtype=dtype) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - 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() - def test_linspace_zero_num(self, xp, dtype): - return xp.linspace(0, 10, 0, dtype=dtype) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_linspace_zero_num_no_endopoint_with_retstep(self, xp, dtype): - x, step = xp.linspace(0, 10, 0, dtype=dtype, endpoint=False, - retstep=True) - self.assertTrue(math.isnan(step)) - return x - - @testing.with_requires('numpy>=1.18') - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_linspace_one_num_no_endopoint_with_retstep(self, xp, dtype): - start, stop = 3, 7 - x, step = xp.linspace(start, stop, 1, dtype=dtype, endpoint=False, - retstep=True) - self.assertEqual(step, stop - start) - return x - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_linspace_one_num(self, xp, dtype): - return xp.linspace(0, 2, 1, dtype=dtype) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_linspace_no_endpoint(self, xp, dtype): - return xp.linspace(0, 10, 5, dtype=dtype, endpoint=False) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_linspace_with_retstep(self, xp, dtype): - x, step = xp.linspace(0, 10, 5, dtype=dtype, retstep=True) - self.assertEqual(step, 2.5) - return x - - @testing.numpy_cupy_allclose() - def test_linspace_no_dtype_int(self, xp): - return xp.linspace(0, 10, 50) - - @testing.numpy_cupy_allclose() - def test_linspace_no_dtype_float(self, xp): - return xp.linspace(0.0, 10.0, 50) - - @testing.numpy_cupy_array_equal() - def test_linspace_float_args_with_int_dtype(self, xp): - return xp.linspace(0.1, 9.1, 11, dtype=int) - - def test_linspace_neg_num(self): - for xp in (numpy, cupy): - with pytest.raises(ValueError): - xp.linspace(0, 10, -1) - - @testing.numpy_cupy_allclose() - def test_linspace_float_overflow(self, xp): - return xp.linspace(0., sys.float_info.max / 5, 10, dtype=float) - - @testing.numpy_cupy_array_equal() - def test_linspace_float_underflow(self, xp): - # find minimum subnormal number - x = sys.float_info.min - while x / 2 > 0: - x /= 2 - return xp.linspace(0., x, 10, dtype=float) - - @testing.with_requires('numpy>=1.16') - @testing.for_all_dtypes_combination(names=('dtype_range', 'dtype_out'), - no_bool=True, no_complex=True) - @testing.numpy_cupy_allclose() - def test_linspace_array_start_stop(self, xp, dtype_range, dtype_out): - start = xp.array([0, 120], dtype=dtype_range) - stop = xp.array([100, 0], dtype=dtype_range) - return xp.linspace(start, stop, num=50, dtype=dtype_out) - - @testing.with_requires('numpy>=1.16') - @testing.for_all_dtypes_combination(names=('dtype_range', 'dtype_out'), - no_bool=True, no_complex=True) - @testing.numpy_cupy_array_equal() - def test_linspace_mixed_start_stop(self, xp, dtype_range, dtype_out): - start = 0.0 - if xp.dtype(dtype_range).kind in 'u': - stop = xp.array([100, 16], dtype=dtype_range) - else: - stop = xp.array([100, -100], dtype=dtype_range) - return xp.linspace(start, stop, num=50, dtype=dtype_out) - - @testing.with_requires('numpy>=1.16') - @testing.for_all_dtypes_combination(names=('dtype_range', 'dtype_out'), - no_bool=True, no_complex=True) - @testing.numpy_cupy_allclose() - def test_linspace_mixed_start_stop2(self, xp, dtype_range, dtype_out): - if xp.dtype(dtype_range).kind in 'u': - start = xp.array([160, 120], dtype=dtype_range) - else: - start = xp.array([-120, 120], dtype=dtype_range) - stop = 0 - return xp.linspace(start, stop, num=50, dtype=dtype_out) - - @testing.with_requires('numpy>=1.16') - @testing.for_all_dtypes_combination(names=('dtype_range', 'dtype_out'), - no_bool=True, no_complex=True) - @testing.numpy_cupy_array_equal() - 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) - return xp.linspace(start, stop, num=50, dtype=dtype_out, axis=1) - - @testing.with_requires('numpy>=1.16') - @testing.for_complex_dtypes() - @testing.numpy_cupy_array_equal() - def test_linspace_complex_start_stop(self, xp, dtype): - start = xp.array([0, 120], dtype=dtype) - stop = xp.array([100, 0], dtype=dtype) - return xp.linspace(start, stop, num=50, dtype=dtype) - - @testing.with_requires('numpy>=1.16') - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() - def test_linspace_start_stop_list(self, xp, dtype): - start = [0, 0] - 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): - return xp.logspace(2, 0, 5, dtype=dtype) - - @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() - 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() - 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() - 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) - - def test_logspace_neg_num(self): - for xp in (numpy, cupy): - 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() - def test_logspace_base(self, xp, dtype): - return xp.logspace(0, 2, 5, base=2.0, dtype=dtype) - - -@testing.parameterize( - *testing.product({ - 'indexing': ['xy', 'ij'], - 'sparse': [False, True], - 'copy': [False, True], - }) -) -@testing.gpu -class TestMeshgrid(unittest.TestCase): - - @testing.for_all_dtypes() - def test_meshgrid0(self, dtype): - out = cupy.meshgrid(indexing=self.indexing, sparse=self.sparse, - copy=self.copy) - assert(out == []) - - @testing.for_all_dtypes() - @testing.numpy_cupy_array_equal() - def test_meshgrid1(self, xp, dtype): - x = xp.arange(2).astype(dtype) - return xp.meshgrid(x, indexing=self.indexing, sparse=self.sparse, - copy=self.copy) - - @testing.for_all_dtypes() - @testing.numpy_cupy_array_equal() - def test_meshgrid2(self, xp, dtype): - x = xp.arange(2).astype(dtype) - y = xp.arange(3).astype(dtype) - return xp.meshgrid(x, y, indexing=self.indexing, sparse=self.sparse, - copy=self.copy) - - @testing.for_all_dtypes() - @testing.numpy_cupy_array_equal() - def test_meshgrid3(self, xp, dtype): - x = xp.arange(2).astype(dtype) - y = xp.arange(3).astype(dtype) - z = xp.arange(4).astype(dtype) - return xp.meshgrid(x, y, z, indexing=self.indexing, sparse=self.sparse, - copy=self.copy) - - -@testing.gpu -class TestMgrid(unittest.TestCase): - - @testing.numpy_cupy_array_equal() - def test_mgrid0(self, xp): - return xp.mgrid[0:] - - @testing.numpy_cupy_array_equal() - def test_mgrid1(self, xp): - return xp.mgrid[-10:10] - - @testing.numpy_cupy_array_equal() - def test_mgrid2(self, xp): - return xp.mgrid[-10:10:10j] - - @testing.numpy_cupy_array_equal() - def test_mgrid3(self, xp): - x = xp.zeros(10)[:, None] - y = xp.ones(10)[:, None] - return xp.mgrid[x:y:10j] - - @testing.numpy_cupy_array_equal() - def test_mgrid4(self, xp): - # check len(keys) > 1 - return xp.mgrid[-10:10:10j, -10:10:10j] - - @testing.numpy_cupy_array_equal() - def test_mgrid5(self, xp): - # check len(keys) > 1 - x = xp.zeros(10)[:, None] - y = xp.ones(10)[:, None] - return xp.mgrid[x:y:10j, x:y:10j] - - -@testing.gpu -class TestOgrid(unittest.TestCase): - - @testing.numpy_cupy_array_equal() - def test_ogrid0(self, xp): - return xp.ogrid[0:] - - @testing.numpy_cupy_array_equal() - def test_ogrid1(self, xp): - return xp.ogrid[-10:10] - - @testing.numpy_cupy_array_equal() - def test_ogrid2(self, xp): - return xp.ogrid[-10:10:10j] - - @testing.numpy_cupy_array_equal() - def test_ogrid3(self, xp): - x = xp.zeros(10)[:, None] - y = xp.ones(10)[:, None] - return xp.ogrid[x:y:10j] - - @testing.numpy_cupy_array_equal() - def test_ogrid4(self, xp): - # check len(keys) > 1 - return xp.ogrid[-10:10:10j, -10:10:10j] - - @testing.numpy_cupy_array_equal() - def test_ogrid5(self, xp): - # check len(keys) > 1 - x = xp.zeros(10)[:, None] - y = xp.ones(10)[:, None] - return xp.ogrid[x:y:10j, x:y:10j] +import math +import sys +import unittest + +import numpy +import pytest + +import dpnp as cupy +from tests.third_party.cupy import testing + + +@testing.gpu +class TestRanges(unittest.TestCase): + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_arange(self, xp, dtype): + return xp.arange(10, dtype=dtype) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_arange2(self, xp, dtype): + return xp.arange(5, 10, dtype=dtype) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_arange3(self, xp, dtype): + return xp.arange(1, 11, 2, dtype=dtype) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_arange4(self, xp, dtype): + return xp.arange(20, 2, -3, dtype=dtype) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_arange5(self, xp, dtype): + return xp.arange(0, 100, None, dtype=dtype) + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_arange6(self, xp, dtype): + return xp.arange(0, 2, dtype=dtype) + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_arange7(self, xp, dtype): + return xp.arange(10, 11, dtype=dtype) + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_arange8(self, xp, dtype): + return xp.arange(10, 8, -1, dtype=dtype) + + def test_arange9(self): + for xp in (numpy, cupy): + with pytest.raises(ValueError): + xp.arange(10, dtype=xp.bool_) + + @testing.numpy_cupy_array_equal() + def test_arange_no_dtype_int(self, xp): + return xp.arange(1, 11, 2) + + @testing.numpy_cupy_array_equal() + def test_arange_no_dtype_float(self, xp): + return xp.arange(1.0, 11.0, 2.0) + + @testing.numpy_cupy_array_equal() + def test_arange_negative_size(self, xp): + return xp.arange(3, 1) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_linspace(self, xp, dtype): + return xp.linspace(0, 10, 5, dtype=dtype) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + 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() + def test_linspace_zero_num(self, xp, dtype): + return xp.linspace(0, 10, 0, dtype=dtype) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_linspace_zero_num_no_endopoint_with_retstep(self, xp, dtype): + x, step = xp.linspace(0, 10, 0, dtype=dtype, endpoint=False, + retstep=True) + self.assertTrue(math.isnan(step)) + return x + + @testing.with_requires('numpy>=1.18') + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_linspace_one_num_no_endopoint_with_retstep(self, xp, dtype): + start, stop = 3, 7 + x, step = xp.linspace(start, stop, 1, dtype=dtype, endpoint=False, + retstep=True) + self.assertEqual(step, stop - start) + return x + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_linspace_one_num(self, xp, dtype): + return xp.linspace(0, 2, 1, dtype=dtype) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_linspace_no_endpoint(self, xp, dtype): + return xp.linspace(0, 10, 5, dtype=dtype, endpoint=False) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_linspace_with_retstep(self, xp, dtype): + x, step = xp.linspace(0, 10, 5, dtype=dtype, retstep=True) + self.assertEqual(step, 2.5) + return x + + @testing.numpy_cupy_allclose() + def test_linspace_no_dtype_int(self, xp): + return xp.linspace(0, 10, 50) + + @testing.numpy_cupy_allclose() + def test_linspace_no_dtype_float(self, xp): + return xp.linspace(0.0, 10.0, 50) + + @testing.numpy_cupy_array_equal() + def test_linspace_float_args_with_int_dtype(self, xp): + return xp.linspace(0.1, 9.1, 11, dtype=int) + + def test_linspace_neg_num(self): + for xp in (numpy, cupy): + with pytest.raises(ValueError): + xp.linspace(0, 10, -1) + + @testing.numpy_cupy_allclose() + def test_linspace_float_overflow(self, xp): + return xp.linspace(0., sys.float_info.max / 5, 10, dtype=float) + + @testing.numpy_cupy_array_equal() + def test_linspace_float_underflow(self, xp): + # find minimum subnormal number + x = sys.float_info.min + while x / 2 > 0: + x /= 2 + return xp.linspace(0., x, 10, dtype=float) + + @testing.with_requires('numpy>=1.16') + @testing.for_all_dtypes_combination(names=('dtype_range', 'dtype_out'), + no_bool=True, no_complex=True) + @testing.numpy_cupy_allclose() + def test_linspace_array_start_stop(self, xp, dtype_range, dtype_out): + start = xp.array([0, 120], dtype=dtype_range) + stop = xp.array([100, 0], dtype=dtype_range) + return xp.linspace(start, stop, num=50, dtype=dtype_out) + + @testing.with_requires('numpy>=1.16') + @testing.for_all_dtypes_combination(names=('dtype_range', 'dtype_out'), + no_bool=True, no_complex=True) + @testing.numpy_cupy_array_equal() + def test_linspace_mixed_start_stop(self, xp, dtype_range, dtype_out): + start = 0.0 + if xp.dtype(dtype_range).kind in 'u': + stop = xp.array([100, 16], dtype=dtype_range) + else: + stop = xp.array([100, -100], dtype=dtype_range) + return xp.linspace(start, stop, num=50, dtype=dtype_out) + + @testing.with_requires('numpy>=1.16') + @testing.for_all_dtypes_combination(names=('dtype_range', 'dtype_out'), + no_bool=True, no_complex=True) + @testing.numpy_cupy_allclose() + def test_linspace_mixed_start_stop2(self, xp, dtype_range, dtype_out): + if xp.dtype(dtype_range).kind in 'u': + start = xp.array([160, 120], dtype=dtype_range) + else: + start = xp.array([-120, 120], dtype=dtype_range) + stop = 0 + return xp.linspace(start, stop, num=50, dtype=dtype_out) + + @testing.with_requires('numpy>=1.16') + @testing.for_all_dtypes_combination(names=('dtype_range', 'dtype_out'), + no_bool=True, no_complex=True) + @testing.numpy_cupy_array_equal() + 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) + return xp.linspace(start, stop, num=50, dtype=dtype_out, axis=1) + + @testing.with_requires('numpy>=1.16') + @testing.for_complex_dtypes() + @testing.numpy_cupy_array_equal() + def test_linspace_complex_start_stop(self, xp, dtype): + start = xp.array([0, 120], dtype=dtype) + stop = xp.array([100, 0], dtype=dtype) + return xp.linspace(start, stop, num=50, dtype=dtype) + + @testing.with_requires('numpy>=1.16') + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_array_equal() + def test_linspace_start_stop_list(self, xp, dtype): + start = [0, 0] + 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): + return xp.logspace(2, 0, 5, dtype=dtype) + + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_allclose() + 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() + 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() + 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) + + def test_logspace_neg_num(self): + for xp in (numpy, cupy): + 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() + def test_logspace_base(self, xp, dtype): + return xp.logspace(0, 2, 5, base=2.0, dtype=dtype) + + +@testing.parameterize( + *testing.product({ + 'indexing': ['xy', 'ij'], + 'sparse': [False, True], + 'copy': [False, True], + }) +) +@testing.gpu +class TestMeshgrid(unittest.TestCase): + + @testing.for_all_dtypes() + def test_meshgrid0(self, dtype): + out = cupy.meshgrid(indexing=self.indexing, sparse=self.sparse, + copy=self.copy) + assert(out == []) + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_meshgrid1(self, xp, dtype): + x = xp.arange(2).astype(dtype) + return xp.meshgrid(x, indexing=self.indexing, sparse=self.sparse, + copy=self.copy) + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_meshgrid2(self, xp, dtype): + x = xp.arange(2).astype(dtype) + y = xp.arange(3).astype(dtype) + return xp.meshgrid(x, y, indexing=self.indexing, sparse=self.sparse, + copy=self.copy) + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_meshgrid3(self, xp, dtype): + x = xp.arange(2).astype(dtype) + y = xp.arange(3).astype(dtype) + z = xp.arange(4).astype(dtype) + return xp.meshgrid(x, y, z, indexing=self.indexing, sparse=self.sparse, + copy=self.copy) + + +@testing.gpu +class TestMgrid(unittest.TestCase): + + @testing.numpy_cupy_array_equal() + def test_mgrid0(self, xp): + return xp.mgrid[0:] + + @testing.numpy_cupy_array_equal() + def test_mgrid1(self, xp): + return xp.mgrid[-10:10] + + @testing.numpy_cupy_array_equal() + def test_mgrid2(self, xp): + return xp.mgrid[-10:10:10j] + + @testing.numpy_cupy_array_equal() + def test_mgrid3(self, xp): + x = xp.zeros(10)[:, None] + y = xp.ones(10)[:, None] + return xp.mgrid[x:y:10j] + + @testing.numpy_cupy_array_equal() + def test_mgrid4(self, xp): + # check len(keys) > 1 + return xp.mgrid[-10:10:10j, -10:10:10j] + + @testing.numpy_cupy_array_equal() + def test_mgrid5(self, xp): + # check len(keys) > 1 + x = xp.zeros(10)[:, None] + y = xp.ones(10)[:, None] + return xp.mgrid[x:y:10j, x:y:10j] + + +@testing.gpu +class TestOgrid(unittest.TestCase): + + @testing.numpy_cupy_array_equal() + def test_ogrid0(self, xp): + return xp.ogrid[0:] + + @testing.numpy_cupy_array_equal() + def test_ogrid1(self, xp): + return xp.ogrid[-10:10] + + @testing.numpy_cupy_array_equal() + def test_ogrid2(self, xp): + return xp.ogrid[-10:10:10j] + + @testing.numpy_cupy_array_equal() + def test_ogrid3(self, xp): + x = xp.zeros(10)[:, None] + y = xp.ones(10)[:, None] + return xp.ogrid[x:y:10j] + + @testing.numpy_cupy_array_equal() + def test_ogrid4(self, xp): + # check len(keys) > 1 + return xp.ogrid[-10:10:10j, -10:10:10j] + + @testing.numpy_cupy_array_equal() + def test_ogrid5(self, xp): + # check len(keys) > 1 + x = xp.zeros(10)[:, None] + y = xp.ones(10)[:, None] + return xp.ogrid[x:y:10j, x:y:10j] From 22d68bc29a7319ee28ddca871cc52c5adb9f2ee5 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Wed, 15 Feb 2023 15:13:38 -0600 Subject: [PATCH 3/9] Added support for array input arguments to linspace() function. --- dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx | 112 ++++++++++++++---- dpnp/dpnp_container.py | 10 +- dpnp/dpnp_iface.py | 32 +---- dpnp/dpnp_iface_arraycreation.py | 82 ++----------- dpnp/dpnp_utils/dpnp_algo_utils.pyx | 2 +- tests/skipped_tests.tbl | 8 +- tests/test_arraycreation.py | 45 +++++++ tests/test_sycl_queue.py | 32 +++-- tests/test_usm_type.py | 13 ++ .../cupy/creation_tests/test_ranges.py | 2 +- 10 files changed, 195 insertions(+), 143 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx index 6986bf0ec702..26f4fc80afcb 100644 --- a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx +++ b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx @@ -192,31 +192,101 @@ cpdef utils.dpnp_descriptor dpnp_identity(n, result_dtype): return result -# TODO this function should work through dpnp_arange_c -cpdef tuple dpnp_linspace(start, stop, num, endpoint, retstep, 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) +cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=None, usm_type=None, sycl_queue=None, endpoint=True, retstep=False, axis=0): + start_isarray = isinstance(start, (dpnp.ndarray, dpctl.tensor.usm_ndarray)) + stop_isarray = isinstance(stop, (dpnp.ndarray, dpctl.tensor.usm_ndarray)) + + if sycl_queue is None and device is None: + sycl_queue = utils_py.get_common_allocation_queue([start, stop]) + sycl_queue_normalized = dpnp.get_normalized_queue_device(sycl_queue=sycl_queue, device=device) + + if usm_type is None: + if start_isarray and stop_isarray: + usm_type = dpctl.utils.get_coerced_usm_type([start.usm_type, stop.usm_type]) + elif start_isarray: + usm_type = start.usm_type + elif stop_isarray: + usm_type = stop.usm_type + else: + usm_type = "device" - if endpoint: - steps_count = num - 1 - else: - steps_count = num + start_isarray = start_isarray or isinstance(start, numpy.ndarray) + stop_isarray = stop_isarray or isinstance(stop, numpy.ndarray) - # if there are steps, then fill values - if steps_count > 0: - step = (dpnp.float64(stop) - start) / steps_count - for i in range(1, result.size): - result.get_pyobj()[i] = start + step * i - else: - step = dpnp.nan + dt = None + if start_isarray and stop_isarray: + dt = numpy.result_type(start.dtype, stop.dtype) + elif start_isarray: + dt = start.dtype + elif stop_isarray: + dt = stop.dtype - # 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 + if dt == None or numpy.issubdtype(dt, dpnp.integer): + dt = numpy.result_type(float(num), dt) + + dt = utils_py.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) - return (result.get_pyobj(), step) + if dtype is None: + dtype = dt + + if dpnp.isscalar(start) and dpnp.isscalar(stop): + res = dpnp_container.linspace(start, + stop, + num, + dtype=dt, + device=device, + 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") + + #FIXME: When subtraction with scalar will be implemented + start_isscalar = dpnp.isscalar(start) + if start_isscalar: + start = [start] + elif start_isarray: + if start.ndim == 0: + start = start.reshape((1)) + start_isscalar = True + stop_isscalar = dpnp.isscalar(stop) + if stop_isscalar: + stop = [stop] + elif stop_isarray: + if stop.ndim == 0: + stop = stop.reshape((1)) + stop_isscalar = True + + _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) + + _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 stop_isscalar and start_isscalar: + res = res.reshape(-1) + + if numpy.issubdtype(dtype, dpnp.integer): + res = res + dpnp.asarray([0.000000001], dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue_normalized) + dpnp.floor(res, out=res) + return dpnp.get_dpnp_descriptor(res.astype(dtype), copy_when_nondefault_queue=False) cpdef utils.dpnp_descriptor dpnp_logspace(start, stop, num, endpoint, base, dtype, axis): diff --git a/dpnp/dpnp_container.py b/dpnp/dpnp_container.py index 19413f33a288..fac73bf680c0 100644 --- a/dpnp/dpnp_container.py +++ b/dpnp/dpnp_container.py @@ -186,9 +186,9 @@ def linspace(start, *, dtype=None, device=None, - endpoint=True, + usm_type="device", sycl_queue=None, - usm_type="device"): + endpoint=True): """Validate input parameters before passing them into `dpctl.tensor` module""" dpu.validate_usm_type(usm_type, allow_none=False) sycl_queue_normalized = dpnp.get_normalized_queue_device(sycl_queue=sycl_queue, device=device) @@ -198,9 +198,9 @@ def linspace(start, stop, num, dtype=dtype, - endpoint=endpoint, - sycl_queue=sycl_queue, - usm_type=usm_type) + usm_type=usm_type, + sycl_queue=sycl_queue_normalized, + endpoint=endpoint) return dpnp_array(array_obj.shape, buffer=array_obj) diff --git a/dpnp/dpnp_iface.py b/dpnp/dpnp_iface.py index 1fe2ba9c59b5..4806b511aff4 100644 --- a/dpnp/dpnp_iface.py +++ b/dpnp/dpnp_iface.py @@ -64,12 +64,9 @@ "default_float_type", "dpnp_queue_initialize", "dpnp_queue_is_cpu", - "get_coerced_usm_type", "get_dpnp_descriptor", - "get_execution_queue", "get_include", - "get_normalized_queue_device", - "isarray" + "get_normalized_queue_device" ] from dpnp import ( @@ -196,16 +193,6 @@ def convert_single_elem_array_to_scalar(obj, keepdims=False): return obj -def get_coerced_usm_type(usm_types): - """ - Given a list of strings denoting the types of USM allocations - for input arrays returns the type of USM allocation for the output - array(s) per compute follows data paradigm. - Returns `None` if the type can not be deduced. - """ - return dpctl.utils.get_coerced_usm_type(usm_types) - - def default_float_type(device=None, sycl_queue=None): """ Return a floating type used by default in DPNP depending on device capabilities. @@ -296,15 +283,6 @@ def get_dpnp_descriptor(ext_obj, return False -def get_execution_queue(qs): - """ - Given a list of :class:`dpctl.SyclQueue` objects - returns the execution queue under compute follows data paradigm, - or returns `None` if queues are not equal. - """ - return dpctl.utils.get_execution_queue(qs) - - def get_include(): """ Return the directory that contains the DPNP C++ backend \\*.h header files. @@ -360,11 +338,3 @@ def get_normalized_queue_device(obj=None, if hasattr(dpt._device, 'normalize_queue_device'): return dpt._device.normalize_queue_device(sycl_queue=sycl_queue, device=device) return sycl_queue - - -def isarray(obj): - """ - Returns True if the type of `obj` is a usm_ndarray type. - - """ - return isinstance(obj, (dpnp_array, dpt.usm_ndarray)) diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index d4ae518b3546..95f964957c42 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -49,6 +49,7 @@ import dpnp.dpnp_container as dpnp_container import dpctl.tensor as dpt +import dpctl __all__ = [ @@ -885,9 +886,9 @@ def linspace(start, *, dtype=None, device=None, - endpoint=True, - sycl_queue=None, usm_type=None, + sycl_queue=None, + endpoint=True, retstep=False, axis=0): """ @@ -899,6 +900,7 @@ def linspace(start, ----------- 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. See Also -------- @@ -928,75 +930,15 @@ def linspace(start, pass elif axis != 0: pass - elif dpnp.isscalar(start) and dpnp.isscalar(stop): - usm_type = usm_type if usm_type is not None else "device" - dt = None if numpy.issubdtype(dtype, dpnp.integer) else dtype - res = dpnp_container.linspace(start, - stop, - num, - dtype=dt, - device=device, - endpoint=endpoint, - sycl_queue=sycl_queue, - usm_type=usm_type) - if numpy.issubdtype(dtype, dpnp.integer): - dpnp.floor(res, out=res) - res = res.astype(dtype) - return res else: - start_isarray = dpnp.isarray(start) - stop_isarray = dpnp.isarray(stop) - - if start_isarray and stop_isarray: - dt = numpy.result_type(start.dtype, stop.dtype) - if sycl_queue is None and device is None: - sycl_queue = dpnp.get_execution_queue([start.sycl_queue, stop.sycl_queue]) - if usm_type is None: - usm_type = dpnp.get_coerced_usm_type([start.usm_type, stop.usm_type]) - - elif start_isarray: - dt = start.dtype - if sycl_queue is None and device is None: - sycl_queue = start.sycl_queue - usm_type = start.usm_type if usm_type is None else usm_type - elif stop_isarray: - dt = stop.dtype - if sycl_queue is None and device is None: - sycl_queue = stop.sycl_queue - usm_type = stop.usm_type if usm_type is None else usm_type - else: - dt = numpy.result_type(None) - - if numpy.issubdtype(dt, dpnp.integer): - dt = numpy.result_type(float(num), dt) - usm_type = usm_type if usm_type is not None else "device" - sycl_queue_normalized = dpnp.get_normalized_queue_device(sycl_queue=sycl_queue, device=device) - - _start = array([start] if dpnp.isscalar(start) else start, dtype=dt, - usm_type=usm_type, sycl_queue=sycl_queue_normalized) - _stop = array([stop] if dpnp.isscalar(stop) else stop, dtype=dt, - usm_type=usm_type, sycl_queue=sycl_queue_normalized) - - if dtype is None: - dtype = dt - - step = ((_stop - _start) * (1. / (num - 1) if endpoint else num)).astype(dt) - - 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) + return dpnp_linspace(start, + stop, + num, + dtype=dtype, + device=device, + usm_type=usm_type, + sycl_queue=sycl_queue, + endpoint=endpoint).get_pyobj() return call_origin(numpy.linspace, start, stop, num, endpoint, retstep, dtype, axis) diff --git a/dpnp/dpnp_utils/dpnp_algo_utils.pyx b/dpnp/dpnp_utils/dpnp_algo_utils.pyx index 4913d5854918..f3d200faddc3 100644 --- a/dpnp/dpnp_utils/dpnp_algo_utils.pyx +++ b/dpnp/dpnp_utils/dpnp_algo_utils.pyx @@ -238,7 +238,7 @@ def get_common_allocation_queue(objects): elif len(queues_in_use) == 1: return queues_in_use[0] - common_queue = dpt.get_execution_queue(queues_in_use) + common_queue = dpctl.utils.get_execution_queue(queues_in_use) if common_queue is None: raise ValueError("Input arrays must be allocated on the same SYCL queue") return common_queue diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index 63c6cbd0d133..636c4b3befee 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -424,12 +424,10 @@ 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 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_float_underflow -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_mixed_start_stop -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_mixed_start_stop2 -tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_start_stop_list +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/test_arraycreation.py b/tests/test_arraycreation.py index 833ea6109c3c..59077c02aef6 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -508,3 +508,48 @@ def test_dpctl_tensor_input(func, args): assert X.shape == Y.shape else: assert_array_equal(X, Y) + + +@pytest.mark.parametrize("start", + [0, -5, 10, -2.5, 9.7], + ids=['0', '-5', '10', '-2.5', '9.7']) +@pytest.mark.parametrize("stop", + [0, 10, -2, 20.5, 1000], + ids=['0', '10', '-2', '20.5', '1000']) +@pytest.mark.parametrize("num", + [5, 10, 17, 100], + ids=['5', '10', '17', '100']) +# @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)']) +@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) + + if numpy.issubdtype(dtype, numpy.floating) or numpy.issubdtype(dtype, numpy.complexfloating): + assert_allclose(func(numpy), func(dpnp), atol=numpy.finfo(dtype).eps) + else: + assert_array_equal(func(numpy), func(dpnp)) + + +@pytest.mark.parametrize("start_dtype", + [numpy.float64, numpy.float32, numpy.int64, numpy.int32], + ids=['float64', 'float32', 'int64', 'int32']) +@pytest.mark.parametrize("stop_dtype", + [numpy.float64, numpy.float32, numpy.int64, numpy.int32], + ids=['float64', 'float32', 'int64', 'int32']) +def test_linspace_dtype(start_dtype, stop_dtype): + start = dpnp.asarray([1, 2, 3], dtype=start_dtype) + stop = dpnp.asarray([11, 7, -2], dtype=stop_dtype) + dpnp.linspace(start, stop, 10) + + +@pytest.mark.parametrize("start", + [dpnp.array(1), dpnp.array([2.6]), numpy.array([[-6.7, 3]]), [1, -4], (3, 5)]) +@pytest.mark.parametrize("stop", + [dpnp.array([-4]), dpnp.array([[2.6], [- 4]]), numpy.array(2), [[-4.6]], (3,)]) +def test_linspace_arrays(start, stop): + func = lambda xp: xp.linspace(start, stop, 10) + func(dpnp) + #assert func(numpy).shape == func(dpnp).shape + #assert_array_equal(func(numpy), func(dpnp)) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 413596e2cc76..d9fb12b552e8 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -84,6 +84,9 @@ def vvsort(val, vec, size, xp): pytest.param("eye", [4, 2], {}), + pytest.param("linspace", + [0, 4, 8], + {}), pytest.param("ones", [(2,2)], {}), @@ -128,13 +131,22 @@ def test_empty_like(device_x, device_y): @pytest.mark.parametrize( - "func, kwargs", + "func, args, kwargs", [ pytest.param("full_like", + ['x0'], {'fill_value': 5}), pytest.param("ones_like", + ['x0'], {}), pytest.param("zeros_like", + ['x0'], + {}), + pytest.param("linspace", + ['x0', '4', '4'], + {}), + pytest.param("linspace", + ['1', 'x0', '4'], {}) ]) @pytest.mark.parametrize("device_x", @@ -143,21 +155,23 @@ def test_empty_like(device_x, device_y): @pytest.mark.parametrize("device_y", valid_devices, ids=[device.filter_string for device in valid_devices]) -def test_array_creation_like(func, kwargs, device_x, device_y): - x_orig = numpy.ndarray([1, 2, 3]) - y_orig = getattr(numpy, func)(x_orig, **kwargs) +def test_array_creation_like(func, args, kwargs, device_x, device_y): + x_orig = numpy.array([1, 2, 3]) + numpy_args = [eval(val, {'x0' : x_orig}) for val in args] + y_orig = getattr(numpy, func)(*numpy_args, **kwargs) - x = dpnp.ndarray([1, 2, 3], device=device_x) + x = dpnp.array([1, 2, 3], device=device_x) + dpnp_args = [eval(val, {'x0' : x}) for val in args] - y = getattr(dpnp, func)(x, **kwargs) - numpy.testing.assert_array_equal(y_orig, y) + y = getattr(dpnp, func)(*dpnp_args, **kwargs) + numpy.testing.assert_allclose(y_orig, y) assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) dpnp_kwargs = dict(kwargs) dpnp_kwargs['device'] = device_y - y = getattr(dpnp, func)(x, **dpnp_kwargs) - numpy.testing.assert_array_equal(y_orig, y) + y = getattr(dpnp, func)(*dpnp_args, **dpnp_kwargs) + numpy.testing.assert_allclose(y_orig, y) assert_sycl_queue_equal(y.sycl_queue, x.to_device(device_y).sycl_queue) diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 094fe419c263..b535d8b144c6 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -49,6 +49,10 @@ def test_coerced_usm_types_mul(usm_type_x, usm_type_y): ['x0']), pytest.param("empty_like", ['x0']), + pytest.param("linspace", + ['x0[0:2]', '4', '4']), + pytest.param("linspace", + ['0', 'x0[3:5]', '4']), ]) @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) @@ -61,3 +65,12 @@ def test_array_creation(func, args, usm_type_x, usm_type_y): assert x.usm_type == usm_type_x assert y.usm_type == usm_type_y + + +@pytest.mark.parametrize("usm_type_start", list_of_usm_types, ids=list_of_usm_types) +@pytest.mark.parametrize("usm_type_stop", list_of_usm_types, ids=list_of_usm_types) +def test_linspace_arrays(usm_type_start, usm_type_stop): + start = dp.asarray([0, 0], usm_type=usm_type_start) + stop = dp.asarray([2, 4], usm_type=usm_type_stop) + res = dp.linspace(start, stop, 4) + assert res.usm_type == du.get_coerced_usm_type([usm_type_start, usm_type_stop]) diff --git a/tests/third_party/cupy/creation_tests/test_ranges.py b/tests/third_party/cupy/creation_tests/test_ranges.py index fec425762304..ac94297354f0 100644 --- a/tests/third_party/cupy/creation_tests/test_ranges.py +++ b/tests/third_party/cupy/creation_tests/test_ranges.py @@ -108,7 +108,7 @@ def test_linspace_one_num(self, xp, dtype): return xp.linspace(0, 2, 1, dtype=dtype) @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_array_equal() + @testing.numpy_cupy_allclose() def test_linspace_no_endpoint(self, xp, dtype): return xp.linspace(0, 10, 5, dtype=dtype, endpoint=False) From a7d9f2f74ec2047ba722a738fcafde68fd0ed73a Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Thu, 16 Feb 2023 19:33:16 -0600 Subject: [PATCH 4/9] Updated linspace implementation for arrays as input argument. --- dpnp/dpnp_algo/dpnp_algo.pyx | 2 + dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx | 44 ++++------------------ tests/test_arraycreation.py | 21 ++++------- tests/test_sycl_queue.py | 2 - 4 files changed, 17 insertions(+), 52 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_algo.pyx b/dpnp/dpnp_algo/dpnp_algo.pyx index f12707ccc761..4737bcfd3c76 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pyx +++ b/dpnp/dpnp_algo/dpnp_algo.pyx @@ -48,6 +48,8 @@ cimport dpnp.dpnp_utils as utils cimport numpy import numpy +import operator + __all__ = [ "dpnp_astype", diff --git a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx index 218e134ae289..80198262f3ae 100644 --- a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx +++ b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx @@ -191,25 +191,17 @@ cpdef utils.dpnp_descriptor dpnp_identity(n, result_dtype): cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=None, usm_type=None, sycl_queue=None, endpoint=True, retstep=False, axis=0): - start_isarray = isinstance(start, (dpnp.ndarray, dpctl.tensor.usm_ndarray)) - stop_isarray = isinstance(stop, (dpnp.ndarray, dpctl.tensor.usm_ndarray)) + usm_type_alloc, sycl_queue_alloc = utils_py.get_usm_allocations([start, stop]) if sycl_queue is None and device is None: - sycl_queue = utils_py.get_common_allocation_queue([start, stop]) + sycl_queue = sycl_queue_alloc sycl_queue_normalized = dpnp.get_normalized_queue_device(sycl_queue=sycl_queue, device=device) if usm_type is None: - if start_isarray and stop_isarray: - usm_type = dpctl.utils.get_coerced_usm_type([start.usm_type, stop.usm_type]) - elif start_isarray: - usm_type = start.usm_type - elif stop_isarray: - usm_type = stop.usm_type - else: - usm_type = "device" + usm_type = "device" if usm_type_alloc is None else usm_type_alloc - start_isarray = start_isarray or isinstance(start, numpy.ndarray) - stop_isarray = stop_isarray or isinstance(stop, numpy.ndarray) + start_isarray = isinstance(start, (dpnp.ndarray, dpctl.tensor.usm_ndarray, numpy.ndarray)) + stop_isarray = isinstance(stop, (dpnp.ndarray, dpctl.tensor.usm_ndarray, numpy.ndarray)) dt = None if start_isarray and stop_isarray: @@ -237,32 +229,14 @@ cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=N sycl_queue=sycl_queue_normalized, endpoint=endpoint) else: - #num = operator.index(num) + num = operator.index(num) if num < 0: raise ValueError("Number of points must be non-negative") - #FIXME: When subtraction with scalar will be implemented - start_isscalar = dpnp.isscalar(start) - if start_isscalar: - start = [start] - elif start_isarray: - if start.ndim == 0: - start = start.reshape((1)) - start_isscalar = True - stop_isscalar = dpnp.isscalar(stop) - if stop_isscalar: - stop = [stop] - elif stop_isarray: - if stop.ndim == 0: - stop = stop.reshape((1)) - stop_isscalar = True - _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) - _num = dpnp.asarray([(num - 1) if endpoint else num], dtype=dt, - usm_type=usm_type, sycl_queue=sycl_queue_normalized) - + _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, @@ -278,11 +252,7 @@ cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=N if endpoint and num > 1: res[-1] = dpnp_container.full(step.shape, _stop) - if stop_isscalar and start_isscalar: - res = res.reshape(-1) - if numpy.issubdtype(dtype, dpnp.integer): - res = res + dpnp.asarray([0.000000001], dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue_normalized) dpnp.floor(res, out=res) return dpnp.get_dpnp_descriptor(res.astype(dtype), copy_when_nondefault_queue=False) diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index e4d736621a28..d9185cff6241 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -520,19 +520,16 @@ def test_dpctl_tensor_input(func, args): [0, 10, -2, 20.5, 1000], ids=['0', '10', '-2', '20.5', '1000']) @pytest.mark.parametrize("num", - [5, 10, 17, 100], - ids=['5', '10', '17', '100']) -# @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)']) + [5, numpy.array(10), dpnp.array(17), dpt.asarray(100)], + ids=['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) - if numpy.issubdtype(dtype, numpy.floating) or numpy.issubdtype(dtype, numpy.complexfloating): - assert_allclose(func(numpy), func(dpnp), atol=numpy.finfo(dtype).eps) + if numpy.issubdtype(dtype, dpnp.integer): + assert_allclose(func(numpy), func(dpnp), rtol=1) else: - assert_array_equal(func(numpy), func(dpnp)) + assert_allclose(func(numpy), func(dpnp), atol=numpy.finfo(dtype).eps) @pytest.mark.parametrize("start_dtype", @@ -542,8 +539,8 @@ def test_linspace(start, stop, num, dtype): [numpy.float64, numpy.float32, numpy.int64, numpy.int32], ids=['float64', 'float32', 'int64', 'int32']) def test_linspace_dtype(start_dtype, stop_dtype): - start = dpnp.asarray([1, 2, 3], dtype=start_dtype) - stop = dpnp.asarray([11, 7, -2], 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) @@ -553,6 +550,4 @@ def test_linspace_dtype(start_dtype, stop_dtype): [dpnp.array([-4]), dpnp.array([[2.6], [- 4]]), numpy.array(2), [[-4.6]], (3,)]) def test_linspace_arrays(start, stop): func = lambda xp: xp.linspace(start, stop, 10) - func(dpnp) - #assert func(numpy).shape == func(dpnp).shape - #assert_array_equal(func(numpy), func(dpnp)) + assert func(numpy).shape == func(dpnp).shape diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 60527d68b2f4..22d911f17898 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -178,8 +178,6 @@ def test_array_creation_like(func, args, kwargs, device_x, device_y): y = getattr(dpnp, func)(*dpnp_args, **dpnp_kwargs) numpy.testing.assert_allclose(y_orig, y) - y = getattr(dpnp, func)(x, **dpnp_kwargs) - numpy.testing.assert_array_equal(y_orig, y) assert_sycl_queue_equal(y.sycl_queue, x.to_device(device_y).sycl_queue) From 0ae14c5b1d3b6708e3ec311fa9e0d853427e0aad Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Fri, 17 Feb 2023 14:41:50 -0600 Subject: [PATCH 5/9] Fixed linspace() function for complex dtype. --- dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx | 20 +++++++------------- tests/test_arraycreation.py | 5 +++++ tests/test_special.py | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx index 80198262f3ae..d432be42efde 100644 --- a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx +++ b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx @@ -200,19 +200,13 @@ cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=N if usm_type is None: usm_type = "device" if usm_type_alloc is None else usm_type_alloc - start_isarray = isinstance(start, (dpnp.ndarray, dpctl.tensor.usm_ndarray, numpy.ndarray)) - stop_isarray = isinstance(stop, (dpnp.ndarray, dpctl.tensor.usm_ndarray, numpy.ndarray)) - - dt = None - if start_isarray and stop_isarray: - dt = numpy.result_type(start.dtype, stop.dtype) - elif start_isarray: - dt = start.dtype - elif stop_isarray: - dt = stop.dtype - - if dt == None or numpy.issubdtype(dt, dpnp.integer): - dt = numpy.result_type(float(num), dt) + if isinstance(start, (list, tuple)): + start = dpnp.asarray(start, usm_type=usm_type, sycl_queue=sycl_queue_normalized) + + if isinstance(stop, (list, tuple)): + 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) diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index d9185cff6241..753328ce4177 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -551,3 +551,8 @@ def test_linspace_dtype(start_dtype, stop_dtype): def test_linspace_arrays(start, stop): func = lambda xp: xp.linspace(start, stop, 10) assert func(numpy).shape == func(dpnp).shape + + +def test_linspace_complex(): + func = lambda xp: xp.linspace(0, 3 + 2j, num=1000) + assert_allclose(func(numpy), func(dpnp)) diff --git a/tests/test_special.py b/tests/test_special.py index da9938d75e9c..21810661687a 100644 --- a/tests/test_special.py +++ b/tests/test_special.py @@ -7,7 +7,7 @@ def test_erf(): a = numpy.linspace(2.0, 3.0, num=10) ia = dpnp.linspace(2.0, 3.0, num=10) - numpy.testing.assert_array_equal(a, ia) + numpy.testing.assert_allclose(a, ia) expected = numpy.empty_like(a) for idx, val in enumerate(a): From 101ed23bd0b6dedbe4a1ea95ff6179c92de3b0db Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Thu, 23 Feb 2023 10:48:34 -0600 Subject: [PATCH 6/9] Removed extra copy in linspace() function. --- dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx | 36 ++++++++++++---------- dpnp/dpnp_iface_arraycreation.py | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx index d432be42efde..3bc60c431631 100644 --- a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx +++ b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx @@ -190,26 +190,31 @@ cpdef utils.dpnp_descriptor dpnp_identity(n, result_dtype): return result -cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=None, usm_type=None, sycl_queue=None, endpoint=True, retstep=False, axis=0): +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]) 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) - if usm_type is None: + if dpnp.isscalar(start) and dpnp.isscalar(stop): + pass + if usm_type is not None: + _start = dpnp.asarray(start, usm_type=usm_type, sycl_queue=sycl_queue_normalized) + _stop = dpnp.asarray(stop, usm_type=usm_type, sycl_queue=sycl_queue_normalized) + else: usm_type = "device" if usm_type_alloc is None else usm_type_alloc + if not hasattr(start, "usm_type"): + _start = dpnp.asarray(start, usm_type=usm_type, sycl_queue=sycl_queue_normalized) + else: + _start = start + if not hasattr(stop, "usm_type"): + _stop = dpnp.asarray(stop, usm_type=usm_type, sycl_queue=sycl_queue_normalized) + else: + _stop = stop - if isinstance(start, (list, tuple)): - start = dpnp.asarray(start, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - - if isinstance(stop, (list, tuple)): - stop = dpnp.asarray(stop, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - - dt = numpy.result_type(start, stop, float(num)) - + dt = numpy.result_type(start if dpnp.isscalar(start) else _start, stop if dpnp.isscalar(stop) else _stop, float(num)) dt = utils_py.map_dtype_to_device(dt, sycl_queue_normalized.sycl_device) - if dtype is None: dtype = dt @@ -218,7 +223,6 @@ cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=N stop, num, dtype=dt, - device=device, usm_type=usm_type, sycl_queue=sycl_queue_normalized, endpoint=endpoint) @@ -226,10 +230,8 @@ cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=N num = operator.index(num) if num < 0: raise ValueError("Number of points must be non-negative") - - _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) - + _start = dpnp.asarray(_start, dtype=dt, sycl_queue=sycl_queue_normalized) + _stop = dpnp.asarray(_stop, dtype=dt, sycl_queue=sycl_queue_normalized) _num = dpnp.asarray((num - 1) if endpoint else num, dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue_normalized) step = (_stop - _start) / _num @@ -248,7 +250,7 @@ cpdef utils.dpnp_descriptor dpnp_linspace(start, stop, num, dtype=None, device=N if numpy.issubdtype(dtype, dpnp.integer): dpnp.floor(res, out=res) - return dpnp.get_dpnp_descriptor(res.astype(dtype), copy_when_nondefault_queue=False) + return res.astype(dtype) cpdef utils.dpnp_descriptor dpnp_logspace(start, stop, num, endpoint, base, dtype, axis): diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 49765aa7d63e..d2a27439cbd8 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -939,7 +939,7 @@ def linspace(start, device=device, usm_type=usm_type, sycl_queue=sycl_queue, - endpoint=endpoint).get_pyobj() + endpoint=endpoint) return call_origin(numpy.linspace, start, stop, num, endpoint, retstep, dtype, axis) From 73c2c3cdbad433c7ec9c9b25736bae80dae647c5 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Thu, 23 Feb 2023 20:43:03 -0600 Subject: [PATCH 7/9] Added comments for linspace() function. --- dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx | 52 ++++++++++++++-------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx index 3bc60c431631..f746af329fb3 100644 --- a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx +++ b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pyx @@ -193,46 +193,60 @@ cpdef utils.dpnp_descriptor dpnp_identity(n, result_dtype): 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) - if dpnp.isscalar(start) and dpnp.isscalar(stop): - pass - if usm_type is not None: - _start = dpnp.asarray(start, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - _stop = dpnp.asarray(stop, usm_type=usm_type, sycl_queue=sycl_queue_normalized) + # 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 = "device" if usm_type_alloc is None else usm_type_alloc - if not hasattr(start, "usm_type"): - _start = dpnp.asarray(start, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - else: - _start = start - if not hasattr(stop, "usm_type"): - _stop = dpnp.asarray(stop, usm_type=usm_type, sycl_queue=sycl_queue_normalized) - else: - _stop = stop - - dt = numpy.result_type(start if dpnp.isscalar(start) else _start, stop if dpnp.isscalar(stop) else _stop, float(num)) + _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, + 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 = dpnp.asarray(_start, dtype=dt, sycl_queue=sycl_queue_normalized) - _stop = dpnp.asarray(_stop, dtype=dt, sycl_queue=sycl_queue_normalized) + + # 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, From f079554d8903cd78adf6d94cb52a1608d9e00e80 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Mon, 27 Feb 2023 16:16:35 -0600 Subject: [PATCH 8/9] Added skipping cross device tests for linspace() function on Windows. --- tests/test_sycl_queue.py | 65 +++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index bd6c8ee853f0..23c202e660df 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -1,5 +1,6 @@ import pytest from .helper import get_all_dtypes +import sys import dpnp import dpctl @@ -148,6 +149,12 @@ def test_empty_like(device_x, device_y): 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'], {}), @@ -155,24 +162,58 @@ def test_empty_like(device_x, device_y): ['1', 'x0', '4'], {}) ]) -@pytest.mark.parametrize("device_x", - valid_devices, - ids=[device.filter_string for device in valid_devices]) -@pytest.mark.parametrize("device_y", +@pytest.mark.parametrize("device", valid_devices, ids=[device.filter_string for device in valid_devices]) -def test_array_creation_like(func, args, kwargs, device_x, device_y): - x_orig = numpy.array([1, 2, 3]) +def test_array_creation_follow_device(func, args, kwargs, device): + x_orig = numpy.array([1, 2, 3, 4]) numpy_args = [eval(val, {'x0' : x_orig}) for val in args] y_orig = getattr(numpy, func)(*numpy_args, **kwargs) - x = dpnp.array([1, 2, 3], device=device_x) + x = dpnp.array([1, 2, 3, 4], device=device) dpnp_args = [eval(val, {'x0' : x}) for val in args] y = getattr(dpnp, func)(*dpnp_args, **kwargs) numpy.testing.assert_allclose(y_orig, y) assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) + +@pytest.mark.parametrize( + "func, args, kwargs", + [ + pytest.param("full_like", + ['x0'], + {'fill_value': 5}), + pytest.param("ones_like", + ['x0'], + {}), + pytest.param("zeros_like", + ['x0'], + {}), + pytest.param("linspace", + ['x0', '4', '4'], + {}), + pytest.param("linspace", + ['1', 'x0', '4'], + {}) + ]) +@pytest.mark.parametrize("device_x", + valid_devices, + ids=[device.filter_string for device in valid_devices]) +@pytest.mark.parametrize("device_y", + valid_devices, + ids=[device.filter_string for device in valid_devices]) +def test_array_creation_cross_device(func, args, kwargs, device_x, device_y): + if func is 'linspace' and sys.platform.startswith('win'): + pytest.skip() + + x_orig = numpy.array([1, 2, 3, 4]) + numpy_args = [eval(val, {'x0' : x_orig}) for val in args] + y_orig = getattr(numpy, func)(*numpy_args, **kwargs) + + x = dpnp.array([1, 2, 3, 4], device=device_x) + dpnp_args = [eval(val, {'x0' : x}) for val in args] + dpnp_kwargs = dict(kwargs) dpnp_kwargs['device'] = device_y @@ -182,16 +223,6 @@ def test_array_creation_like(func, args, kwargs, device_x, device_y): assert_sycl_queue_equal(y.sycl_queue, x.to_device(device_y).sycl_queue) -@pytest.mark.parametrize("func", ["tril", "triu"], ids=["tril", "triu"]) -@pytest.mark.parametrize("device", - valid_devices, - ids=[device.filter_string for device in valid_devices]) -def test_tril_triu(func, device): - x0 = dpnp.ones((3,3), device=device) - x = getattr(dpnp, func)(x0) - assert_sycl_queue_equal(x.sycl_queue, x0.sycl_queue) - - @pytest.mark.parametrize("device_x", valid_devices, ids=[device.filter_string for device in valid_devices]) From 67eeeb73cf5959ac57260d651e27629cde6d53be Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Mon, 27 Feb 2023 14:58:46 -0800 Subject: [PATCH 9/9] Added reason for skipping tests for linspace() function. Co-authored-by: Oleksandr Pavlyk --- tests/test_sycl_queue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 23c202e660df..2197dbe5414c 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -205,7 +205,7 @@ def test_array_creation_follow_device(func, args, kwargs, device): ids=[device.filter_string for device in valid_devices]) def test_array_creation_cross_device(func, args, kwargs, device_x, device_y): if func is 'linspace' and sys.platform.startswith('win'): - pytest.skip() + pytest.skip("CPU driver experiences an instability on Windows.") x_orig = numpy.array([1, 2, 3, 4]) numpy_args = [eval(val, {'x0' : x_orig}) for val in args]