Skip to content

Commit 18f0cb1

Browse files
Merge master into update_svd_cuda
2 parents 11e28de + e0c9cf1 commit 18f0cb1

File tree

13 files changed

+547
-146
lines changed

13 files changed

+547
-146
lines changed

doc/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def _can_document_member(member, *args, **kwargs):
220220
"python": ("https://docs.python.org/3/", None),
221221
"numpy": ("https://docs.scipy.org/doc/numpy/", None),
222222
"scipy": ("https://docs.scipy.org/doc/scipy/reference/", None),
223+
"dpctl": ("https://intelpython.github.io/dpctl/latest/", None),
223224
}
224225

225226
# If true, `todo` and `todoList` produce output, else they produce nothing.

dpnp/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
[os.getenv("PATH", ""), mypath, dpctlpath]
5050
)
5151

52+
# Borrowed from DPCTL
53+
from dpctl.tensor import DLDeviceType
54+
5255
from dpnp.dpnp_array import dpnp_array as ndarray
5356
from dpnp.dpnp_flatiter import flatiter as flatiter
5457
from dpnp.dpnp_iface_types import *

dpnp/dpnp_iface.py

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
"check_limitations",
6363
"check_supported_arrays_type",
6464
"default_float_type",
65-
"from_dlpack",
6665
"get_dpnp_descriptor",
6766
"get_include",
6867
"get_normalized_queue_device",
@@ -443,60 +442,6 @@ def default_float_type(device=None, sycl_queue=None):
443442
return map_dtype_to_device(float64, _sycl_queue.sycl_device)
444443

445444

446-
def from_dlpack(obj, /, *, device=None, copy=None):
447-
"""
448-
Create a dpnp array from a Python object implementing the ``__dlpack__``
449-
protocol.
450-
451-
See https://dmlc.github.io/dlpack/latest/ for more details.
452-
453-
Parameters
454-
----------
455-
obj : object
456-
A Python object representing an array that implements the ``__dlpack__``
457-
and ``__dlpack_device__`` methods.
458-
device : {:class:`dpctl.SyclDevice`, :class:`dpctl.SyclQueue`,
459-
:class:`dpctl.tensor.Device`, tuple, None}, optional
460-
Array API concept of a device where the output array is to be placed.
461-
``device`` can be ``None``, an oneAPI filter selector string,
462-
an instance of :class:`dpctl.SyclDevice` corresponding to
463-
a non-partitioned SYCL device, an instance of :class:`dpctl.SyclQueue`,
464-
a :class:`dpctl.tensor.Device` object returned by
465-
:attr:`dpctl.tensor.usm_ndarray.device`, or a 2-tuple matching
466-
the format of the output of the ``__dlpack_device__`` method,
467-
an integer enumerator representing the device type followed by
468-
an integer representing the index of the device.
469-
Default: ``None``.
470-
copy {bool, None}, optional
471-
Boolean indicating whether or not to copy the input.
472-
473-
* If `copy``is ``True``, the input will always be copied.
474-
* If ``False``, a ``BufferError`` will be raised if a copy is deemed
475-
necessary.
476-
* If ``None``, a copy will be made only if deemed necessary, otherwise,
477-
the existing memory buffer will be reused.
478-
479-
Default: ``None``.
480-
481-
Returns
482-
-------
483-
out : dpnp_array
484-
Returns a new dpnp array containing the data from another array
485-
(obj) with the ``__dlpack__`` method on the same device as object.
486-
487-
Raises
488-
------
489-
TypeError:
490-
if `obj` does not implement ``__dlpack__`` method
491-
ValueError:
492-
if the input array resides on an unsupported device
493-
494-
"""
495-
496-
usm_res = dpt.from_dlpack(obj, device=device, copy=copy)
497-
return dpnp_array._create_from_usm_ndarray(usm_res)
498-
499-
500445
def get_dpnp_descriptor(
501446
ext_obj,
502447
copy_when_strides=True,

dpnp/dpnp_iface_arraycreation.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
"fromfunction",
7676
"fromiter",
7777
"fromstring",
78+
"from_dlpack",
7879
"full",
7980
"full_like",
8081
"geomspace",
@@ -2047,6 +2048,93 @@ def fromstring(
20472048
)
20482049

20492050

2051+
def from_dlpack(x, /, *, device=None, copy=None):
2052+
"""
2053+
Constructs :class:`dpnp.ndarray` or :class:`numpy.ndarray` instance from
2054+
a Python object `x` that implements ``__dlpack__`` protocol.
2055+
2056+
For full documentation refer to :obj:`numpy.from_dlpack`.
2057+
2058+
Parameters
2059+
----------
2060+
x : object
2061+
A Python object representing an array that implements the ``__dlpack__``
2062+
and ``__dlpack_device__`` methods.
2063+
device : {None, string, tuple, device}, optional
2064+
Device where the output array is to be placed. `device` keyword values
2065+
can be:
2066+
2067+
* ``None`` : The data remains on the same device.
2068+
* oneAPI filter selector string : SYCL device selected by filter
2069+
selector string.
2070+
* :class:`dpctl.SyclDevice` : Explicit SYCL device that must correspond
2071+
to a non-partitioned SYCL device.
2072+
* :class:`dpctl.SyclQueue` : Implies SYCL device targeted by the SYCL
2073+
queue.
2074+
* :class:`dpctl.tensor.Device` : Implies SYCL device
2075+
``device.sycl_queue``. The `device` object is obtained via
2076+
:attr:`dpctl.tensor.usm_ndarray.device`.
2077+
* ``(device_type, device_id)`` : 2-tuple matching the format of the
2078+
output of the ``__dlpack_device__`` method: an integer enumerator
2079+
representing the device type followed by an integer representing
2080+
the index of the device. The only supported :class:`dpnp.DLDeviceType`
2081+
device types are ``"kDLCPU"`` and ``"kDLOneAPI"``.
2082+
2083+
Default: ``None``.
2084+
copy : {bool, None}, optional
2085+
Boolean indicating whether or not to copy the input.
2086+
2087+
* If `copy` is ``True``, the input will always be copied.
2088+
* If ``False``, a ``BufferError`` will be raised if a copy is deemed
2089+
necessary.
2090+
* If ``None``, a copy will be made only if deemed necessary, otherwise,
2091+
the existing memory buffer will be reused.
2092+
2093+
Default: ``None``.
2094+
2095+
Returns
2096+
-------
2097+
out : {dpnp.ndarray, numpy.ndarray}
2098+
An array containing the data in `x`. When `copy` is ``None`` or
2099+
``False``, this may be a view into the original memory.
2100+
The type of the returned object depends on where the data backing up
2101+
input object `x` resides. If it resides in a USM allocation on a SYCL
2102+
device, the type :class:`dpnp.ndarray` is returned, otherwise if it
2103+
resides on ``"kDLCPU"`` device the type is :class:`numpy.ndarray`, and
2104+
otherwise an exception is raised.
2105+
2106+
Raises
2107+
------
2108+
TypeError
2109+
if `obj` does not implement ``__dlpack__`` method
2110+
ValueError
2111+
if data of the input object resides on an unsupported device
2112+
2113+
Notes
2114+
-----
2115+
If the return type is :class:`dpnp.ndarray`, the associated SYCL queue is
2116+
derived from the `device` keyword. When `device` keyword value has type
2117+
:class:`dpctl.SyclQueue`, the explicit queue instance is used, when `device`
2118+
keyword value has type :class:`dpctl.tensor.Device`, the
2119+
``device.sycl_queue`` is used. In all other cases, the cached SYCL queue
2120+
corresponding to the implied SYCL device is used.
2121+
2122+
Examples
2123+
--------
2124+
>>> import dpnp as np
2125+
>>> import numpy
2126+
>>> x = numpy.arange(10)
2127+
>>> # create a view of the numpy array "x" in dpnp:
2128+
>>> y = np.from_dlpack(x)
2129+
2130+
"""
2131+
2132+
result = dpt.from_dlpack(x, device=device, copy=copy)
2133+
if isinstance(result, dpt.usm_ndarray):
2134+
return dpnp_array._create_from_usm_ndarray(result)
2135+
return result
2136+
2137+
20502138
def full(
20512139
shape,
20522140
fill_value,

dpnp/dpnp_iface_nanfunctions.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import warnings
4141

4242
import dpnp
43+
from dpnp.dpnp_utils.dpnp_utils_statistics import dpnp_median
4344

4445
__all__ = [
4546
"nanargmax",
@@ -48,6 +49,7 @@
4849
"nancumsum",
4950
"nanmax",
5051
"nanmean",
52+
"nanmedian",
5153
"nanmin",
5254
"nanprod",
5355
"nanstd",
@@ -568,6 +570,107 @@ def nanmean(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
568570
return avg
569571

570572

573+
def nanmedian(a, axis=None, out=None, overwrite_input=False, keepdims=False):
574+
"""
575+
Compute the median along the specified axis, while ignoring NaNs.
576+
577+
For full documentation refer to :obj:`numpy.nanmedian`.
578+
579+
Parameters
580+
----------
581+
a : {dpnp.ndarray, usm_ndarray}
582+
Input array.
583+
axis : {None, int, tuple or list of ints}, optional
584+
Axis or axes along which the medians are computed. The default,
585+
``axis=None``, will compute the median along a flattened version of
586+
the array. If a sequence of axes, the array is first flattened along
587+
the given axes, then the median is computed along the resulting
588+
flattened axis.
589+
Default: ``None``.
590+
out : {None, dpnp.ndarray, usm_ndarray}, optional
591+
Alternative output array in which to place the result. It must have
592+
the same shape as the expected output but the type (of the calculated
593+
values) will be cast if necessary.
594+
Default: ``None``.
595+
overwrite_input : bool, optional
596+
If ``True``, then allow use of memory of input array `a` for
597+
calculations. The input array will be modified by the call to
598+
:obj:`dpnp.nanmedian`. This will save memory when you do not need to
599+
preserve the contents of the input array. Treat the input as undefined,
600+
but it will probably be fully or partially sorted.
601+
Default: ``False``.
602+
keepdims : bool, optional
603+
If ``True``, the reduced axes (dimensions) are included in the result
604+
as singleton dimensions, so that the returned array remains
605+
compatible with the input array according to Array Broadcasting
606+
rules. Otherwise, if ``False``, the reduced axes are not included in
607+
the returned array.
608+
Default: ``False``.
609+
610+
Returns
611+
-------
612+
out : dpnp.ndarray
613+
A new array holding the result. If `a` has a floating-point data type,
614+
the returned array will have the same data type as `a`. If `a` has a
615+
boolean or integral data type, the returned array will have the
616+
default floating point data type for the device where input array `a`
617+
is allocated.
618+
619+
See Also
620+
--------
621+
:obj:`dpnp.mean` : Compute the arithmetic mean along the specified axis.
622+
:obj:`dpnp.median` : Compute the median along the specified axis.
623+
:obj:`dpnp.percentile` : Compute the q-th percentile of the data
624+
along the specified axis.
625+
626+
Notes
627+
-----
628+
Given a vector ``V`` of length ``N``, the median of ``V`` is the
629+
middle value of a sorted copy of ``V``, ``V_sorted`` - i.e.,
630+
``V_sorted[(N-1)/2]``, when ``N`` is odd, and the average of the
631+
two middle values of ``V_sorted`` when ``N`` is even.
632+
633+
Examples
634+
--------
635+
>>> import dpnp as np
636+
>>> a = np.array([[10.0, 7, 4], [3, 2, 1]])
637+
>>> a[0, 1] = np.nan
638+
>>> a
639+
array([[10., nan, 4.],
640+
[ 3., 2., 1.]])
641+
>>> np.median(a)
642+
array(nan)
643+
>>> np.nanmedian(a)
644+
array(3.)
645+
646+
>>> np.nanmedian(a, axis=0)
647+
array([6.5, 2., 2.5])
648+
>>> np.nanmedian(a, axis=1)
649+
array([7., 2.])
650+
651+
>>> b = a.copy()
652+
>>> np.nanmedian(b, axis=1, overwrite_input=True)
653+
array([7., 2.])
654+
>>> assert not np.all(a==b)
655+
>>> b = a.copy()
656+
>>> np.nanmedian(b, axis=None, overwrite_input=True)
657+
array(3.)
658+
>>> assert not np.all(a==b)
659+
660+
"""
661+
662+
dpnp.check_supported_arrays_type(a)
663+
ignore_nan = False
664+
if dpnp.issubdtype(a.dtype, dpnp.inexact):
665+
mask = dpnp.isnan(a)
666+
if dpnp.any(mask):
667+
ignore_nan = True
668+
669+
return dpnp_median(
670+
a, axis, out, overwrite_input, keepdims, ignore_nan=ignore_nan
671+
)
672+
673+
571674
def nanmin(a, axis=None, out=None, keepdims=False, initial=None, where=True):
572675
"""
573676
Return the minimum of an array or minimum along an axis, ignoring any NaNs.

0 commit comments

Comments
 (0)