Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement dpnp.mgrid and dpnp.ogrid function #1633

Merged
merged 7 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions dpnp/dpnp_algo/dpnp_arraycreation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import math
import operator

import dpctl.utils as dpu
import numpy

import dpnp
Expand All @@ -10,6 +12,7 @@
"dpnp_geomspace",
"dpnp_linspace",
"dpnp_logspace",
"dpnp_nd_grid",
]


Expand Down Expand Up @@ -256,3 +259,134 @@ def dpnp_logspace(
if dtype is None:
return dpnp.power(base, res)
return dpnp.power(base, res).astype(dtype, copy=False)


class dpnp_nd_grid:
"""
Construct a multi-dimensional "meshgrid".

``grid = dpnp_nd_grid()`` creates an instance which will return a mesh-grid
when indexed. The dimension and number of the output arrays are equal
to the number of indexing dimensions. If the step length is not a
complex number, then the stop is not inclusive.

However, if the step length is a complex number (e.g. 5j), then the
integer part of its magnitude is interpreted as specifying the
number of points to create between the start and stop values, where
the stop value is inclusive.

If instantiated with an argument of ``sparse=True``, the mesh-grid is
open (or not fleshed out) so that only one-dimension of each returned
argument is greater than 1.

Parameters
----------
sparse : bool, optional
Whether the grid is sparse or not. Default is False.

"""

def __init__(
self, sparse=False, device=None, usm_type="device", sycl_queue=None
):
dpu.validate_usm_type(usm_type, allow_none=False)
self.sparse = sparse
self.usm_type = usm_type
self.sycl_queue_normalized = dpnp.get_normalized_queue_device(
sycl_queue=sycl_queue, device=device
)

def __getitem__(self, key):
if isinstance(key, slice):
step = key.step
stop = key.stop
start = key.start
if start is None:
start = 0
if isinstance(step, complex):
step = abs(step)
length = int(step)
if step != 1:
step = (stop - start) / float(step - 1)
stop = stop + step
return (
dpnp.arange(
0,
length,
1,
dtype=dpnp.default_float_type(),
usm_type=self.usm_type,
sycl_queue=self.sycl_queue_normalized,
)
* step
+ start
)
else:
return dpnp.arange(
start,
stop,
step,
usm_type=self.usm_type,
sycl_queue=self.sycl_queue_normalized,
)

size = []
dtype = int
for k in range(len(key)):
step = key[k].step
start = key[k].start
stop = key[k].stop
if start is None:
start = 0
if step is None:
step = 1
if isinstance(step, complex):
size.append(int(abs(step)))
dtype = dpnp.default_float_type()
else:
size.append(
int(math.ceil((key[k].stop - start) / (step * 1.0)))
)
if (
isinstance(step, float)
or isinstance(start, float)
or isinstance(stop, float)
):
dtype = dpnp.default_float_type()
if self.sparse:
nn = [
dpnp.arange(
_x,
dtype=_t,
usm_type=self.usm_type,
sycl_queue=self.sycl_queue_normalized,
)
for _x, _t in zip(size, (dtype,) * len(size))
]
else:
nn = dpnp.indices(
size,
dtype,
usm_type=self.usm_type,
sycl_queue=self.sycl_queue_normalized,
)
for k in range(len(size)):
step = key[k].step
start = key[k].start
stop = key[k].stop
if start is None:
start = 0
if step is None:
step = 1
if isinstance(step, complex):
step = int(abs(step))
if step != 1:
step = (stop - start) / float(step - 1)
nn[k] = nn[k] * step + start
if self.sparse:
slobj = [dpnp.newaxis] * len(size)
for k in range(len(size)):
slobj[k] = slice(None, None)
nn[k] = nn[k][tuple(slobj)]
slobj[k] = dpnp.newaxis
return nn
23 changes: 18 additions & 5 deletions dpnp/dpnp_iface_arraycreation.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
dpnp_geomspace,
dpnp_linspace,
dpnp_logspace,
dpnp_nd_grid,
)

__all__ = [
Expand Down Expand Up @@ -1472,7 +1473,15 @@ class MGridClass:
"""

def __getitem__(self, key):
return dpnp.array(numpy.mgrid[key])
return dpnp_nd_grid(sparse=False)[key]

def __call__(self, device=None, usm_type="device", sycl_queue=None):
return dpnp_nd_grid(
sparse=False,
device=device,
usm_type=usm_type,
sycl_queue=sycl_queue,
)


mgrid = MGridClass()
Expand All @@ -1487,10 +1496,9 @@ class OGridClass:
Examples
--------
>>> import dpnp as np
>>> from numpy import ogrid
>>> ogrid[-1:1:5j]
>>> np.ogrid[-1:1:5j]
array([-1. , -0.5, 0. , 0.5, 1. ])
>>> ogrid[0:5,0:5]
>>> np.ogrid[0:5,0:5]
npolina4 marked this conversation as resolved.
Show resolved Hide resolved
[array([[0],
[1],
[2],
Expand All @@ -1500,7 +1508,12 @@ class OGridClass:
"""

def __getitem__(self, key):
return dpnp.array(numpy.ogrid[key])
return dpnp_nd_grid(sparse=True)[key]

def __call__(self, device=None, usm_type="device", sycl_queue=None):
return dpnp_nd_grid(
sparse=True, device=device, usm_type=usm_type, sycl_queue=sycl_queue
)


ogrid = OGridClass()
Expand Down
4 changes: 0 additions & 4 deletions tests/skipped_tests.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,6 @@ tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_7_{copy
tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_7_{copy=True, indexing='ij', sparse=True}::test_meshgrid1
tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_7_{copy=True, indexing='ij', sparse=True}::test_meshgrid2
tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_7_{copy=True, indexing='ij', sparse=True}::test_meshgrid3
tests/third_party/cupy/creation_tests/test_ranges.py::TestMgrid::test_mgrid3
npolina4 marked this conversation as resolved.
Show resolved Hide resolved
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/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
Expand Down
5 changes: 0 additions & 5 deletions tests/skipped_tests_gpu.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,6 @@ tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_7_{copy
tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_7_{copy=True, indexing='ij', sparse=True}::test_meshgrid1
tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_7_{copy=True, indexing='ij', sparse=True}::test_meshgrid2
tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_7_{copy=True, indexing='ij', sparse=True}::test_meshgrid3
tests/third_party/cupy/creation_tests/test_ranges.py::TestMgrid::test_mgrid3
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_arange_negative_size
tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_arange_no_dtype_int

Expand Down
12 changes: 12 additions & 0 deletions tests/test_sycl_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,18 @@ def test_indices(device, sparse):
assert i.sycl_device == device


@pytest.mark.parametrize(
"device",
valid_devices,
ids=[device.filter_string for device in valid_devices],
)
@pytest.mark.parametrize("func", ["mgrid", "ogrid"])
def test_grid(device, func):
sycl_queue = dpctl.SyclQueue(device)
x = getattr(dpnp, func)(sycl_queue=sycl_queue)[0:4]
assert_sycl_queue_equal(x.sycl_queue, sycl_queue)


@pytest.mark.parametrize(
"device",
valid_devices,
Expand Down
12 changes: 12 additions & 0 deletions tests/test_usm_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,18 @@ def test_take(func, usm_type_x, usm_type_ind):
assert z.usm_type == du.get_coerced_usm_type([usm_type_x, usm_type_ind])


@pytest.mark.parametrize("usm_type", list_of_usm_types, ids=list_of_usm_types)
def test_indices(usm_type):
x = dp.indices((2,), usm_type=usm_type)
assert x.usm_type == usm_type


@pytest.mark.parametrize("usm_type", list_of_usm_types, ids=list_of_usm_types)
@pytest.mark.parametrize("func", ["mgrid", "ogrid"])
def test_grid(usm_type, func):
assert getattr(dp, func)(usm_type=usm_type)[0:4].usm_type == usm_type


@pytest.mark.parametrize("usm_type", list_of_usm_types, ids=list_of_usm_types)
@pytest.mark.parametrize("sparse", [True, False], ids=["True", "False"])
def test_indices(usm_type, sparse):
Expand Down
10 changes: 5 additions & 5 deletions tests/third_party/cupy/creation_tests/test_ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ def test_mgrid1(self, xp):
def test_mgrid2(self, xp):
return xp.mgrid[-10:10:10j]

@testing.numpy_cupy_array_equal()
@testing.numpy_cupy_allclose(rtol=1e-4, type_check=has_support_aspect64())
def test_mgrid3(self, xp):
x = xp.zeros(10)[:, None]
y = xp.ones(10)[:, None]
Expand All @@ -374,7 +374,7 @@ def test_mgrid4(self, xp):
# check len(keys) > 1
return xp.mgrid[-10:10:10j, -10:10:10j]

@testing.numpy_cupy_array_equal()
@testing.numpy_cupy_allclose(rtol=1e-4, type_check=has_support_aspect64())
def test_mgrid5(self, xp):
# check len(keys) > 1
x = xp.zeros(10)[:, None]
Expand All @@ -396,18 +396,18 @@ def test_ogrid1(self, xp):
def test_ogrid2(self, xp):
return xp.ogrid[-10:10:10j]

@testing.numpy_cupy_array_equal()
@testing.numpy_cupy_allclose(rtol=1e-4, type_check=has_support_aspect64())
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()
@testing.numpy_cupy_allclose(rtol=1e-4, type_check=has_support_aspect64())
def test_ogrid4(self, xp):
# check len(keys) > 1
return xp.ogrid[-10:10:10j, -10:10:10j]

@testing.numpy_cupy_array_equal()
@testing.numpy_cupy_allclose(rtol=1e-4, type_check=has_support_aspect64())
def test_ogrid5(self, xp):
# check len(keys) > 1
x = xp.zeros(10)[:, None]
Expand Down
Loading