# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2016-2025, Intel Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
# *****************************************************************************
"""
Interface of the array manipulation routines part of the DPNP
Notes
-----
This module is a face or public interface file for the library
it contains:
- Interface functions
- documentation for the functions
- The functions parameters check
"""
import math
import operator
import warnings
from typing import NamedTuple
import dpctl
import dpctl.tensor as dpt
import numpy
from dpctl.tensor._numpy_helper import AxisError, normalize_axis_index
import dpnp
from .dpnp_array import dpnp_array
# pylint: disable=no-name-in-module
from .dpnp_utils import get_usm_allocations
from .dpnp_utils.dpnp_utils_pad import dpnp_pad
class InsertDeleteParams(NamedTuple):
"""Parameters used for ``dpnp.delete`` and ``dpnp.insert``."""
a: dpnp_array
a_ndim: int
order: str
axis: int
slobj: list
n: int
a_shape: list
exec_q: dpctl.SyclQueue
usm_type: str
__all__ = [
"append",
"array_split",
"asarray_chkfinite",
"asfarray",
"atleast_1d",
"atleast_2d",
"atleast_3d",
"broadcast_arrays",
"broadcast_shapes",
"broadcast_to",
"can_cast",
"column_stack",
"concat",
"concatenate",
"copyto",
"delete",
"dsplit",
"dstack",
"expand_dims",
"flip",
"fliplr",
"flipud",
"hsplit",
"hstack",
"insert",
"matrix_transpose",
"moveaxis",
"ndim",
"pad",
"permute_dims",
"ravel",
"repeat",
"require",
"reshape",
"resize",
"result_type",
"roll",
"rollaxis",
"rot90",
"row_stack",
"shape",
"size",
"split",
"squeeze",
"stack",
"swapaxes",
"tile",
"transpose",
"trim_zeros",
"unique",
"unstack",
"vsplit",
"vstack",
]
def _check_stack_arrays(arrays):
"""Validate a sequence type of arrays to stack."""
if not hasattr(arrays, "__getitem__"):
raise TypeError(
'arrays to stack must be passed as a "sequence" type '
"such as list or tuple."
)
def _delete_with_slice(params, obj, axis):
"""Utility function for ``dpnp.delete`` when obj is slice."""
a, a_ndim, order, axis, slobj, n, newshape, exec_q, usm_type = params
start, stop, step = obj.indices(n)
xr = range(start, stop, step)
num_del = len(xr)
if num_del <= 0:
return a.copy(order=order)
# Invert if step is negative:
if step < 0:
step = -step
start = xr[-1]
stop = xr[0] + 1
newshape[axis] -= num_del
new = dpnp.empty(
newshape,
order=order,
dtype=a.dtype,
sycl_queue=exec_q,
usm_type=usm_type,
)
# copy initial chunk
if start == 0:
pass
else:
slobj[axis] = slice(None, start)
new[tuple(slobj)] = a[tuple(slobj)]
# copy end chunk
if stop == n:
pass
else:
slobj[axis] = slice(stop - num_del, None)
slobj2 = [slice(None)] * a_ndim
slobj2[axis] = slice(stop, None)
new[tuple(slobj)] = a[tuple(slobj2)]
# copy middle pieces
if step == 1:
pass
else: # use array indexing.
keep = dpnp.ones(
stop - start,
dtype=dpnp.bool,
sycl_queue=exec_q,
usm_type=usm_type,
)
keep[: stop - start : step] = False
slobj[axis] = slice(start, stop - num_del)
slobj2 = [slice(None)] * a_ndim
slobj2[axis] = slice(start, stop)
a = a[tuple(slobj2)]
slobj2[axis] = keep
new[tuple(slobj)] = a[tuple(slobj2)]
return new
def _delete_without_slice(params, obj, axis, single_value):
"""Utility function for ``dpnp.delete`` when obj is int or array of int."""
a, a_ndim, order, axis, slobj, n, newshape, exec_q, usm_type = params
if single_value:
# optimization for a single value
if obj < -n or obj >= n:
raise IndexError(
f"index {obj} is out of bounds for axis {axis} with "
f"size {n}"
)
if obj < 0:
obj += n
newshape[axis] -= 1
new = dpnp.empty(
newshape,
order=order,
dtype=a.dtype,
sycl_queue=exec_q,
usm_type=usm_type,
)
slobj[axis] = slice(None, obj)
new[tuple(slobj)] = a[tuple(slobj)]
slobj[axis] = slice(obj, None)
slobj2 = [slice(None)] * a_ndim
slobj2[axis] = slice(obj + 1, None)
new[tuple(slobj)] = a[tuple(slobj2)]
else:
if obj.dtype == dpnp.bool:
if obj.shape != (n,):
raise ValueError(
"boolean array argument `obj` to delete must be "
f"one-dimensional and match the axis length of {n}"
)
# optimization, the other branch is slower
keep = ~obj
else:
keep = dpnp.ones(
n, dtype=dpnp.bool, sycl_queue=exec_q, usm_type=usm_type
)
keep[obj,] = False
slobj[axis] = keep
new = a[tuple(slobj)]
return new
def _calc_parameters(a, axis, obj, values=None):
"""Utility function for ``dpnp.delete`` and ``dpnp.insert``."""
a_ndim = a.ndim
order = "F" if a.flags.fnc else "C"
if axis is None:
if a_ndim != 1:
a = dpnp.ravel(a)
a_ndim = 1
axis = 0
else:
axis = normalize_axis_index(axis, a_ndim)
slobj = [slice(None)] * a_ndim
n = a.shape[axis]
a_shape = list(a.shape)
usm_type, exec_q = get_usm_allocations([a, obj, values])
return InsertDeleteParams(
a, a_ndim, order, axis, slobj, n, a_shape, exec_q, usm_type
)
def _insert_array_indices(parameters, indices, values, obj):
"""
Utility function for ``dpnp.insert`` when indices is an array with
multiple elements.
"""
a, a_ndim, order, axis, slobj, n, newshape, exec_q, usm_type = parameters
is_array = isinstance(obj, (dpnp_array, numpy.ndarray, dpt.usm_ndarray))
if indices.size == 0 and not is_array:
# Can safely cast the empty list to intp
indices = indices.astype(dpnp.intp)
indices[indices < 0] += n
numnew = len(indices)
ind_sort = indices.argsort(kind="stable")
indices[ind_sort] += dpnp.arange(
numnew, dtype=indices.dtype, sycl_queue=exec_q, usm_type=usm_type
)
newshape[axis] += numnew
old_mask = dpnp.ones(
newshape[axis], dtype=dpnp.bool, sycl_queue=exec_q, usm_type=usm_type
)
old_mask[indices] = False
new = dpnp.empty(
newshape,
order=order,
dtype=a.dtype,
sycl_queue=exec_q,
usm_type=usm_type,
)
slobj2 = [slice(None)] * a_ndim
slobj[axis] = indices
slobj2[axis] = old_mask
new[tuple(slobj)] = values
new[tuple(slobj2)] = a
return new
def _insert_singleton_index(parameters, indices, values, obj):
"""
Utility function for ``dpnp.insert`` when indices is an array with
one element.
"""
a, a_ndim, order, axis, slobj, n, newshape, exec_q, usm_type = parameters
# In dpnp, `.item()` calls `.wait()`, so it is preferred to avoid it
# When possible (i.e. for numpy arrays, lists, etc), it is preferred
# to use `.item()` on a NumPy array
if dpnp.is_supported_array_type(obj):
index = indices.item()
else:
if isinstance(obj, slice):
obj = numpy.arange(*obj.indices(n), dtype=dpnp.intp)
index = numpy.asarray(obj).item()
if index < -n or index > n:
raise IndexError(
f"index {index} is out of bounds for axis {axis} with size {n}"
)
if index < 0:
index += n
# Need to change the dtype of values to input array dtype and update
# its shape to make ``input_arr[..., index, ...] = values`` legal
values = dpnp.array(
values,
copy=None,
ndmin=a_ndim,
dtype=a.dtype,
sycl_queue=exec_q,
usm_type=usm_type,
)
if indices.ndim == 0:
# numpy.insert behave differently if obj is an scalar or an array
# with one element, so, this change is needed to align with NumPy
values = dpnp.moveaxis(values, 0, axis)
numnew = values.shape[axis]
newshape[axis] += numnew
new = dpnp.empty(
newshape,
order=order,
dtype=a.dtype,
sycl_queue=exec_q,
usm_type=usm_type,
)
slobj[axis] = slice(None, index)
new[tuple(slobj)] = a[tuple(slobj)]
slobj[axis] = slice(index, index + numnew)
new[tuple(slobj)] = values
slobj[axis] = slice(index + numnew, None)
slobj2 = [slice(None)] * a_ndim
slobj2[axis] = slice(index, None)
new[tuple(slobj)] = a[tuple(slobj2)]
return new
def _unique_1d(
ar,
return_index=False,
return_inverse=False,
return_counts=False,
equal_nan=True,
):
"""Find the unique elements of a 1D array."""
def _get_first_nan_index(usm_a):
"""
Find the first index of NaN in the input array with at least two NaNs.
Assume the input array sorted where the NaNs are always at the end.
Return None if the input array does not have at least two NaN values or
data type of the array is not inexact.
"""
if (
usm_a.size > 2
and dpnp.issubdtype(usm_a.dtype, dpnp.inexact)
and dpnp.isnan(usm_a[-2])
):
if dpnp.issubdtype(usm_a.dtype, dpnp.complexfloating):
# for complex all NaNs are considered equivalent
true_val = dpt.asarray(
True, sycl_queue=usm_a.sycl_queue, usm_type=usm_a.usm_type
)
return dpt.searchsorted(dpt.isnan(usm_a), true_val, side="left")
return dpt.searchsorted(usm_a, usm_a[-1], side="left")
return None
usm_ar = dpnp.get_usm_ndarray(ar)
num_of_flags = (return_index, return_inverse, return_counts).count(True)
if num_of_flags == 0:
usm_res = dpt.unique_values(usm_ar)
usm_res = (usm_res,) # cast to a tuple to align with other cases
elif num_of_flags == 1 and return_inverse:
usm_res = dpt.unique_inverse(usm_ar)
elif num_of_flags == 1 and return_counts:
usm_res = dpt.unique_counts(usm_ar)
else:
usm_res = dpt.unique_all(usm_ar)
first_nan = None
if equal_nan:
first_nan = _get_first_nan_index(usm_res[0])
# collapse multiple NaN values in an array into one NaN value if applicable
result = (
usm_res[0][: first_nan + 1] if first_nan is not None else usm_res[0],
)
if return_index:
result += (
(
usm_res.indices[: first_nan + 1]
if first_nan is not None
else usm_res.indices
),
)
if return_inverse:
if first_nan is not None:
# all NaNs are collapsed, so need to replace the indices with
# the index of the first NaN value in result array of unique values
dpt.place(
usm_res.inverse_indices,
usm_res.inverse_indices > first_nan,
dpt.reshape(first_nan, 1),
)
result += (usm_res.inverse_indices,)
if return_counts:
if first_nan is not None:
# all NaNs are collapsed, so need to put a count of all NaNs
# at the last index
dpt.sum(usm_res.counts[first_nan:], out=usm_res.counts[first_nan])
result += (usm_res.counts[: first_nan + 1],)
else:
result += (usm_res.counts,)
result = tuple(dpnp_array._create_from_usm_ndarray(x) for x in result)
return _unpack_tuple(result)
def _unique_build_sort_indices(a, index_sh):
"""
Build the indices of an input array (when axis is provided) which result
in the unique array.
"""
is_inexact = dpnp.issubdtype(a, dpnp.inexact)
if dpnp.issubdtype(a.dtype, numpy.unsignedinteger):
ar_cmp = a.astype(dpnp.intp)
elif dpnp.issubdtype(a.dtype, dpnp.bool):
ar_cmp = a.astype(numpy.int8)
else:
ar_cmp = a
def compare_axis_elems(idx1, idx2):
comp = dpnp.trim_zeros(ar_cmp[idx1] - ar_cmp[idx2], "f")
if comp.shape[0] > 0:
diff = comp[0]
if is_inexact and dpnp.isnan(diff):
isnan1 = dpnp.isnan(ar_cmp[idx1])
if not isnan1.any(): # no NaN in ar_cmp[idx1]
return True # ar_cmp[idx1] goes to left
isnan2 = dpnp.isnan(ar_cmp[idx2])
if not isnan2.any(): # no NaN in ar_cmp[idx2]
return False # ar_cmp[idx1] goes to right
# for complex all NaNs are considered equivalent
if (isnan1 & isnan2).all(): # NaNs at the same places
return False # ar_cmp[idx1] goes to right
xor_nan_idx = dpnp.where(isnan1 ^ isnan2)[0]
if xor_nan_idx.size == 0:
return False
if dpnp.isnan(ar_cmp[idx2][xor_nan_idx[0]]):
# first NaN in XOR mask is from ar_cmp[idx2]
return True # ar_cmp[idx1] goes to left
return False
return diff < 0
return False
# sort the array `a` lexicographically using the first item
# of each element on the axis
sorted_indices = dpnp.empty_like(a, shape=index_sh, dtype=dpnp.intp)
queue = [(numpy.arange(0, index_sh, dtype=numpy.intp).tolist(), 0)]
while len(queue) != 0:
current, off = queue.pop(0)
if len(current) == 0:
continue
mid_elem = current[0]
left = []
right = []
for i in range(1, len(current)):
if compare_axis_elems(current[i], mid_elem):
left.append(current[i])
else:
right.append(current[i])
elem_pos = off + len(left)
queue.append((left, off))
queue.append((right, elem_pos + 1))
sorted_indices[elem_pos] = mid_elem
return sorted_indices
def _unpack_tuple(a):
"""Unpacks one-element tuples for use as return values."""
if len(a) == 1:
return a[0]
return a
[docs]
def append(arr, values, axis=None):
"""
Append values to the end of an array.
For full documentation refer to :obj:`numpy.append`.
Parameters
----------
arr : {dpnp.ndarray, usm_ndarray}
Values are appended to a copy of this array.
values : {scalar, array_like}
These values are appended to a copy of `arr`. It must be of the
correct shape (the same shape as `arr`, excluding `axis`). If
`axis` is not specified, `values` can be any shape and will be
flattened before use.
These values can be in any form that can be converted to an array.
This includes scalars, lists, lists of tuples, tuples,
tuples of tuples, tuples of lists, and ndarrays.
axis : {None, int}, optional
The axis along which `values` are appended. If `axis` is not
given, both `arr` and `values` are flattened before use.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
A copy of `arr` with `values` appended to `axis`. Note that
`append` does not occur in-place: a new array is allocated and
filled. If `axis` is ``None``, `out` is a flattened array.
See Also
--------
:obj:`dpnp.insert` : Insert elements into an array.
:obj:`dpnp.delete` : Delete elements from an array.
Examples
--------
>>> import dpnp as np
>>> a = np.array([1, 2, 3])
>>> np.append(a, [[4, 5, 6], [7, 8, 9]])
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
When `axis` is specified, `values` must have the correct shape.
>>> b = np.array([[1, 2, 3], [4, 5, 6]])
>>> np.append(b, [[7, 8, 9]], axis=0)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> np.append(b, [7, 8, 9], axis=0)
Traceback (most recent call last):
...
ValueError: all the input arrays must have same number of dimensions, but
the array at index 0 has 2 dimension(s) and the array at index 1 has 1
dimension(s)
"""
dpnp.check_supported_arrays_type(arr)
if not dpnp.is_supported_array_type(values):
values = dpnp.array(
values, usm_type=arr.usm_type, sycl_queue=arr.sycl_queue
)
if axis is None:
if arr.ndim != 1:
arr = dpnp.ravel(arr)
if values.ndim != 1:
values = dpnp.ravel(values)
axis = 0
return dpnp.concatenate((arr, values), axis=axis)
[docs]
def array_split(ary, indices_or_sections, axis=0):
"""
Split an array into multiple sub-arrays.
Please refer to the :obj:`dpnp.split` documentation. The only difference
between these functions is that ``dpnp.array_split`` allows
`indices_or_sections` to be an integer that does *not* equally divide the
axis. For an array of length l that should be split into n sections, it
returns ``l % n`` sub-arrays of size ``l//n + 1`` and the rest of size
``l//n``.
For full documentation refer to :obj:`numpy.array_split`.
Parameters
----------
ary : {dpnp.ndarray, usm_ndarray}
Array to be divided into sub-arrays.
indices_or_sections : {int, sequence of ints}
If `indices_or_sections` is an integer, N, and array length is l, it
returns ``l % n`` sub-arrays of size ``l//n + 1`` and the rest of size
``l//n``.
If `indices_or_sections` is a sequence of sorted integers, the entries
indicate where along `axis` the array is split.
axis : int, optional
The axis along which to split.
Default: ``0``.
Returns
-------
sub-arrays : list of dpnp.ndarray
A list of sub arrays. Each array is a view of the corresponding input
array.
See Also
--------
:obj:`dpnp.split` : Split array into multiple sub-arrays of equal size.
Examples
--------
>>> import dpnp as np
>>> x = np.arange(8.0)
>>> np.array_split(x, 3)
[array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7.])]
>>> x = np.arange(9)
>>> np.array_split(x, 4)
[array([0, 1, 2]), array([3, 4]), array([5, 6]), array([7, 8])]
"""
dpnp.check_supported_arrays_type(ary)
n_tot = ary.shape[axis]
try:
# handle array case.
n_sec = len(indices_or_sections) + 1
div_points = [0] + list(indices_or_sections) + [n_tot]
except TypeError:
# indices_or_sections is a scalar, not an array.
n_sec = int(indices_or_sections)
if n_sec <= 0:
raise ValueError("number sections must be larger than 0.") from None
n_each_sec, extras = numpy.divmod(n_tot, n_sec)
section_sizes = (
[0] + extras * [n_each_sec + 1] + (n_sec - extras) * [n_each_sec]
)
div_points = dpnp.array(
section_sizes,
dtype=dpnp.intp,
usm_type=ary.usm_type,
sycl_queue=ary.sycl_queue,
).cumsum()
sub_arys = []
sary = dpnp.swapaxes(ary, axis, 0)
for i in range(n_sec):
st = div_points[i]
end = div_points[i + 1]
sub_arys.append(dpnp.swapaxes(sary[st:end], axis, 0))
return sub_arys
[docs]
def asarray_chkfinite(
a, dtype=None, order=None, *, device=None, usm_type=None, sycl_queue=None
):
"""
Convert the input to an array, checking for NaNs or Infs.
For full documentation refer to :obj:`numpy.asarray_chkfinite`.
Parameters
----------
arr : array_like
Input data, in any form that can be converted to an array. This
includes lists, lists of tuples, tuples, tuples of tuples, tuples
of lists and ndarrays. Success requires no NaNs or Infs.
dtype : {None, str, dtype object}, optional
By default, the data-type is inferred from the input data.
Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Memory layout of the newly output array.
Default: ``"K"``.
device : {None, string, SyclDevice, SyclQueue}, optional
An array API concept of device where the output array is created.
The `device` can be ``None`` (the default), an OneAPI filter selector
string, an instance of :class:`dpctl.SyclDevice` corresponding to
a non-partitioned SYCL device, an instance of :class:`dpctl.SyclQueue`,
or a `Device` object returned by
:obj:`dpnp.dpnp_array.dpnp_array.device` property.
Default: ``None``.
usm_type : {None, "device", "shared", "host"}, optional
The type of SYCL USM allocation for the output array.
Default: ``None``.
sycl_queue : {None, SyclQueue}, optional
A SYCL queue to use for output array allocation and copying. The
`sycl_queue` can be passed as ``None`` (the default), which means
to get the SYCL queue from `device` keyword if present or to use
a default queue.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
Array interpretation of `a`. No copy is performed if the input is
already an ndarray.
Raises
-------
ValueError
Raises ``ValueError`` if `a` contains NaN (Not a Number) or
Inf (Infinity).
See Also
--------
:obj:`dpnp.asarray` : Create an array.
:obj:`dpnp.asanyarray` : Converts an input object into array.
:obj:`dpnp.ascontiguousarray` : Convert input to a c-contiguous array.
:obj:`dpnp.asfortranarray` : Convert input to an array with column-major
memory order.
:obj:`dpnp.fromiter` : Create an array from an iterator.
:obj:`dpnp.fromfunction` : Construct an array by executing a function
on grid positions.
Examples
--------
>>> import dpnp as np
Convert a list into an array. If all elements are finite,
``asarray_chkfinite`` is identical to ``asarray``.
>>> a = [1, 2]
>>> np.asarray_chkfinite(a, dtype=np.float32)
array([1., 2.])
Raises ``ValueError`` if array_like contains NaNs or Infs.
>>> a = [1, 2, np.inf]
>>> try:
... np.asarray_chkfinite(a)
... except ValueError:
... print('ValueError')
ValueError
Creating an array on a different device or with a specified usm_type
>>> x = np.asarray_chkfinite([1, 2, 3]) # default case
>>> x, x.device, x.usm_type
(array([1, 2, 3]), Device(level_zero:gpu:0), 'device')
>>> y = np.asarray_chkfinite([1, 2, 3], device="cpu")
>>> y, y.device, y.usm_type
(array([1, 2, 3]), Device(opencl:cpu:0), 'device')
>>> z = np.asarray_chkfinite([1, 2, 3], usm_type="host")
>>> z, z.device, z.usm_type
(array([1, 2, 3]), Device(level_zero:gpu:0), 'host')
"""
a = dpnp.asarray(
a,
dtype=dtype,
order=order,
device=device,
usm_type=usm_type,
sycl_queue=sycl_queue,
)
if dpnp.issubdtype(a.dtype, dpnp.inexact) and not dpnp.isfinite(a).all():
raise ValueError("array must not contain infs or NaNs")
return a
[docs]
def asfarray(a, dtype=None, *, device=None, usm_type=None, sycl_queue=None):
"""
Return an array converted to a float type.
For full documentation refer to :obj:`numpy.asfarray`.
Parameters
----------
a : array_like
Input data, in any form that can be converted to an array.
This includes an instance of :class:`dpnp.ndarray` or
:class:`dpctl.tensor.usm_ndarray`, an object representing
SYCL USM allocation and implementing `__sycl_usm_array_interface__`
protocol, an instance of :class:`numpy.ndarray`, an object supporting
Python buffer protocol, a Python scalar, or a (possibly nested)
sequence of Python scalars.
dtype : str or dtype object, optional
Float type code to coerce input array `a`. If `dtype` is ``None``,
:obj:`dpnp.bool` or one of the `int` dtypes, it is replaced with
the default floating type (:obj:`dpnp.float64` if a device supports it,
or :obj:`dpnp.float32` type otherwise).
device : {None, string, SyclDevice, SyclQueue}, optional
An array API concept of device where the output array is created.
The `device` can be ``None`` (the default), an OneAPI filter selector
string, an instance of :class:`dpctl.SyclDevice` corresponding to
a non-partitioned SYCL device, an instance of :class:`dpctl.SyclQueue`,
or a `Device` object returned by :obj:`dpnp.ndarray.device` property.
usm_type : {None, "device", "shared", "host"}, optional
The type of SYCL USM allocation for the output array.
sycl_queue : {None, SyclQueue}, optional
A SYCL queue to use for output array allocation and copying. The
`sycl_queue` can be passed as ``None`` (the default), which means
to get the SYCL queue from `device` keyword if present or to use
a default queue.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
The input `a` as a float ndarray.
Examples
--------
>>> import dpnp as np
>>> np.asfarray([2, 3])
array([2., 3.])
>>> np.asfarray([2, 3], dtype=dpnp.float32)
array([2., 3.], dtype=float32)
>>> np.asfarray([2, 3], dtype=dpnp.int32)
array([2., 3.])
"""
_sycl_queue = dpnp.get_normalized_queue_device(
a, sycl_queue=sycl_queue, device=device
)
if dtype is None or not dpnp.issubdtype(dtype, dpnp.inexact):
dtype = dpnp.default_float_type(sycl_queue=_sycl_queue)
return dpnp.asarray(
a, dtype=dtype, usm_type=usm_type, sycl_queue=_sycl_queue
)
[docs]
def atleast_1d(*arys):
"""
Convert inputs to arrays with at least one dimension.
For full documentation refer to :obj:`numpy.atleast_1d`.
Parameters
----------
arys : {dpnp.ndarray, usm_ndarray}
One or more array-like sequences. Arrays that already have one or more
dimensions are preserved.
Returns
-------
out : dpnp.ndarray
An array, or list of arrays, each with ``a.ndim >= 1``.
Copies are made only if necessary.
See Also
--------
:obj:`dpnp.atleast_2d` : View inputs as arrays with at least two dimensions.
:obj:`dpnp.atleast_3d` : View inputs as arrays with at least three
dimensions.
Examples
--------
>>> import dpnp as np
>>> x = np.array(1.0)
>>> np.atleast_1d(x)
array([1.])
>>> y = np.array([3, 4])
>>> np.atleast_1d(x, y)
[array([1.]), array([3, 4])]
>>> x = np.arange(9.0).reshape(3,3)
>>> np.atleast_1d(x)
array([[0., 1., 2.],
[3., 4., 5.],
[6., 7., 8.]])
>>> np.atleast_1d(x) is x
True
"""
res = []
dpnp.check_supported_arrays_type(*arys)
for ary in arys:
if ary.ndim == 0:
result = ary.reshape(1)
else:
result = ary
if isinstance(result, dpt.usm_ndarray):
result = dpnp_array._create_from_usm_ndarray(result)
res.append(result)
if len(res) == 1:
return res[0]
return res
[docs]
def atleast_2d(*arys):
"""
View inputs as arrays with at least two dimensions.
For full documentation refer to :obj:`numpy.atleast_2d`.
Parameters
----------
arys : {dpnp.ndarray, usm_ndarray}
One or more array-like sequences. Arrays that already have two or more
dimensions are preserved.
Returns
-------
out : dpnp.ndarray
An array, or list of arrays, each with ``a.ndim >= 2``.
Copies are avoided where possible, and views with two or more
dimensions are returned.
See Also
--------
:obj:`dpnp.atleast_1d` : Convert inputs to arrays with at least one
dimension.
:obj:`dpnp.atleast_3d` : View inputs as arrays with at least three
dimensions.
Examples
--------
>>> import dpnp as np
>>> x = np.array(3.0)
>>> np.atleast_2d(x)
array([[3.]])
>>> x = np.arange(3.0)
>>> np.atleast_2d(x)
array([[0., 1., 2.]])
"""
res = []
dpnp.check_supported_arrays_type(*arys)
for ary in arys:
if ary.ndim == 0:
result = ary.reshape(1, 1)
elif ary.ndim == 1:
result = ary[dpnp.newaxis, :]
else:
result = ary
if isinstance(result, dpt.usm_ndarray):
result = dpnp_array._create_from_usm_ndarray(result)
res.append(result)
if len(res) == 1:
return res[0]
return res
[docs]
def atleast_3d(*arys):
"""
View inputs as arrays with at least three dimensions.
For full documentation refer to :obj:`numpy.atleast_3d`.
Parameters
----------
arys : {dpnp.ndarray, usm_ndarray}
One or more array-like sequences. Arrays that already have three or more
dimensions are preserved.
Returns
-------
out : dpnp.ndarray
An array, or list of arrays, each with ``a.ndim >= 3``. Copies are
avoided where possible, and views with three or more dimensions are
returned.
See Also
--------
:obj:`dpnp.atleast_1d` : Convert inputs to arrays with at least one
dimension.
:obj:`dpnp.atleast_2d` : View inputs as arrays with at least three
dimensions.
Examples
--------
>>> import dpnp as np
>>> x = np.array(3.0)
>>> np.atleast_3d(x)
array([[[3.]]])
>>> x = np.arange(3.0)
>>> np.atleast_3d(x).shape
(1, 3, 1)
>>> x = np.arange(12.0).reshape(4, 3)
>>> np.atleast_3d(x).shape
(4, 3, 1)
"""
res = []
dpnp.check_supported_arrays_type(*arys)
for ary in arys:
if ary.ndim == 0:
result = ary.reshape(1, 1, 1)
elif ary.ndim == 1:
result = ary[dpnp.newaxis, :, dpnp.newaxis]
elif ary.ndim == 2:
result = ary[:, :, dpnp.newaxis]
else:
result = ary
if isinstance(result, dpt.usm_ndarray):
result = dpnp_array._create_from_usm_ndarray(result)
res.append(result)
if len(res) == 1:
return res[0]
return res
[docs]
def broadcast_arrays(*args, subok=False):
"""
Broadcast any number of arrays against each other.
For full documentation refer to :obj:`numpy.broadcast_arrays`.
Parameters
----------
args : {dpnp.ndarray, usm_ndarray}
A list of arrays to broadcast.
Returns
-------
out : list of dpnp.ndarray
A list of arrays which are views on the original arrays from `args`.
Limitations
-----------
Parameter `subok` is supported with default value.
Otherwise ``NotImplementedError`` exception will be raised.
See Also
--------
:obj:`dpnp.broadcast_to` : Broadcast an array to a new shape.
Examples
--------
>>> import dpnp as np
>>> x = np.array([[1, 2, 3]])
>>> y = np.array([[4], [5]])
>>> np.broadcast_arrays(x, y)
[array([[1, 2, 3],
[1, 2, 3]]), array([[4, 4, 4],
[5, 5, 5]])]
"""
if subok is not False:
raise NotImplementedError(f"subok={subok} is currently not supported")
if len(args) == 0:
return []
usm_arrays = dpt.broadcast_arrays(*[dpnp.get_usm_ndarray(a) for a in args])
return [dpnp_array._create_from_usm_ndarray(a) for a in usm_arrays]
[docs]
def broadcast_shapes(*args):
"""
Broadcast the input shapes into a single shape.
For full documentation refer to :obj:`numpy.broadcast_shapes`.
Parameters
----------
*args : tuples of ints, or ints
The shapes to be broadcast against each other.
Returns
-------
tuple
Broadcasted shape.
See Also
--------
:obj:`dpnp.broadcast_arrays` : Broadcast any number of arrays against
each other.
:obj:`dpnp.broadcast_to` : Broadcast an array to a new shape.
Examples
--------
>>> import dpnp as np
>>> np.broadcast_shapes((1, 2), (3, 1), (3, 2))
(3, 2)
>>> np.broadcast_shapes((6, 7), (5, 6, 1), (7,), (5, 1, 7))
(5, 6, 7)
"""
return numpy.broadcast_shapes(*args)
# pylint: disable=redefined-outer-name
[docs]
def broadcast_to(array, /, shape, subok=False):
"""
Broadcast an array to a new shape.
For full documentation refer to :obj:`numpy.broadcast_to`.
Parameters
----------
array : {dpnp.ndarray, usm_ndarray}
The array to broadcast.
shape : tuple or int
The shape of the desired array. A single integer ``i`` is interpreted
as ``(i,)``.
Returns
-------
out : dpnp.ndarray
An array having a specified shape.
Must have the same data type as `array`.
Limitations
-----------
Parameter `subok` is supported with default value.
Otherwise ``NotImplementedError`` exception will be raised.
See Also
--------
:obj:`dpnp.broadcast_arrays` : Broadcast any number of arrays against
each other.
Examples
--------
>>> import dpnp as np
>>> x = np.array([1, 2, 3])
>>> np.broadcast_to(x, (3, 3))
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
"""
if subok is not False:
raise NotImplementedError(f"subok={subok} is currently not supported")
usm_array = dpnp.get_usm_ndarray(array)
new_array = dpt.broadcast_to(usm_array, shape)
return dpnp_array._create_from_usm_ndarray(new_array)
[docs]
def can_cast(from_, to, casting="safe"):
"""
Returns ``True`` if cast between data types can occur according
to the casting rule.
For full documentation refer to :obj:`numpy.can_cast`.
Parameters
----------
from_ : {dpnp.ndarray, usm_ndarray, dtype, dtype specifier}
Source data type.
to : dtype
Target data type.
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
Controls what kind of data casting may occur.
Returns
-------
out: bool
``True`` if cast can occur according to the casting rule,
``False`` otherwise.
See Also
--------
:obj:`dpnp.result_type` : Returns the type that results from applying
the NumPy type promotion rules to the arguments.
Examples
--------
Basic examples
>>> import dpnp as np
>>> np.can_cast(np.int32, np.int64)
True
>>> np.can_cast(np.float64, complex)
True
>>> np.can_cast(complex, float)
False
>>> np.can_cast('i8', 'f8')
True
>>> np.can_cast('i8', 'f4')
False
Array scalar checks the value, array does not
>>> np.can_cast(np.array(1000.0), np.float32)
True
>>> np.can_cast(np.array([1000.0]), np.float32)
False
Using the casting rules
>>> np.can_cast('i8', 'i8', 'no')
True
>>> np.can_cast('<i8', '>i8', 'no')
False
>>> np.can_cast('<i8', '>i8', 'equiv')
True
>>> np.can_cast('<i4', '>i8', 'equiv')
False
>>> np.can_cast('<i4', '>i8', 'safe')
True
>>> np.can_cast('<i8', '>i4', 'safe')
False
>>> np.can_cast('<i8', '>i4', 'same_kind')
True
>>> np.can_cast('<i8', '>u4', 'same_kind')
False
>>> np.can_cast('<i8', '>u4', 'unsafe')
True
"""
if dpnp.is_supported_array_type(to):
raise TypeError("Cannot construct a dtype from an array")
dtype_from = (
from_.dtype
if dpnp.is_supported_array_type(from_)
else dpnp.dtype(from_)
)
return dpt.can_cast(dtype_from, to, casting=casting)
[docs]
def column_stack(tup):
"""
Stacks 1-D and 2-D arrays as columns into a 2-D array.
Take a sequence of 1-D arrays and stack them as columns to make a single
2-D array. 2-D arrays are stacked as-is, just like with :obj:`dpnp.hstack`.
1-D arrays are turned into 2-D columns first.
For full documentation refer to :obj:`numpy.column_stack`.
Parameters
----------
tup : {dpnp.ndarray, usm_ndarray}
A sequence of 1-D or 2-D arrays to stack. All of them must have
the same first dimension.
Returns
-------
out : dpnp.ndarray
The array formed by stacking the given arrays.
See Also
--------
:obj:`dpnp.stack` : Join a sequence of arrays along a new axis.
:obj:`dpnp.dstack` : Stack arrays in sequence depth wise (along third axis).
:obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise).
:obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise).
:obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis.
Examples
--------
>>> import dpnp as np
>>> a = np.array((1, 2, 3))
>>> b = np.array((2, 3, 4))
>>> np.column_stack((a, b))
array([[1, 2],
[2, 3],
[3, 4]])
"""
_check_stack_arrays(tup)
arrays = []
for v in tup:
dpnp.check_supported_arrays_type(v)
if v.ndim == 1:
v = v[:, dpnp.newaxis]
elif v.ndim != 2:
raise ValueError(
"Only 1 or 2 dimensional arrays can be column stacked"
)
arrays.append(v)
return dpnp.concatenate(arrays, axis=1)
[docs]
def concatenate(
arrays, /, *, axis=0, out=None, dtype=None, casting="same_kind"
):
"""
Join a sequence of arrays along an existing axis.
Note that :obj:`dpnp.concat` is an alias of :obj:`dpnp.concatenate`.
For full documentation refer to :obj:`numpy.concatenate`.
Parameters
----------
arrays : {Sequence of dpnp.ndarray or usm_ndarray}
The arrays must have the same shape, except in the dimension
corresponding to axis (the first, by default).
axis : int, optional
The axis along which the arrays will be joined. If axis is ``None``,
arrays are flattened before use.
Default: ``0``.
out : dpnp.ndarray, optional
If provided, the destination to place the result. The shape must be
correct, matching that of what concatenate would have returned
if no out argument were specified.
dtype : str or dtype
If provided, the destination array will have this dtype. Cannot be
provided together with `out`.
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
Controls what kind of data casting may occur. Defaults to 'same_kind'.
Returns
-------
out : dpnp.ndarray
The concatenated array.
See Also
--------
:obj:`dpnp.array_split` : Split an array into multiple sub-arrays of equal
or near-equal size.
:obj:`dpnp.split` : Split array into a list of multiple sub-arrays of equal
size.
:obj:`dpnp.hsplit` : Split array into multiple sub-arrays horizontally
(column wise).
:obj:`dpnp.vsplit` : Split array into multiple sub-arrays vertically
(row wise).
:obj:`dpnp.dsplit` : Split array into multiple sub-arrays along
the 3rd axis (depth).
:obj:`dpnp.stack` : Stack a sequence of arrays along a new axis.
:obj:`dpnp.block` : Assemble arrays from blocks.
:obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise).
:obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise).
:obj:`dpnp.dstack` : Stack arrays in sequence depth wise
(along third dimension).
:obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array.
Examples
--------
>>> import dpnp as np
>>> a = np.array([[1, 2], [3, 4]])
>>> b = np.array([[5, 6]])
>>> np.concatenate((a, b), axis=0)
array([[1, 2],
[3, 4],
[5, 6]])
>>> np.concatenate((a, b.T), axis=1)
array([[1, 2, 5],
[3, 4, 6]])
>>> np.concatenate((a, b), axis=None)
array([1, 2, 3, 4, 5, 6])
"""
if dtype is not None and out is not None:
raise TypeError(
"concatenate() only takes `out` or `dtype` as an argument, "
"but both were provided."
)
usm_arrays = [dpnp.get_usm_ndarray(x) for x in arrays]
usm_res = dpt.concat(usm_arrays, axis=axis)
res = dpnp_array._create_from_usm_ndarray(usm_res)
if dtype is not None:
res = res.astype(dtype, casting=casting, copy=False)
elif out is not None:
dpnp.copyto(out, res, casting=casting)
return out
return res
concat = concatenate # concat is an alias of concatenate
[docs]
def copyto(dst, src, casting="same_kind", where=True):
"""
Copies values from one array to another, broadcasting as necessary.
Raises a ``TypeError`` if the `casting` rule is violated, and if
`where` is provided, it selects which elements to copy.
For full documentation refer to :obj:`numpy.copyto`.
Parameters
----------
dst : {dpnp.ndarray, usm_ndarray}
The array into which values are copied.
src : array_like
The array from which values are copied.
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
Controls what kind of data casting may occur when copying.
where : {dpnp.ndarray, usm_ndarray, scalar} of bool, optional
A boolean array or a scalar which is broadcasted to match
the dimensions of `dst`, and selects elements to copy
from `src` to `dst` wherever it contains the value ``True``.
Examples
--------
>>> import dpnp as np
>>> A = np.array([4, 5, 6])
>>> B = [1, 2, 3]
>>> np.copyto(A, B)
>>> A
array([1, 2, 3])
>>> A = np.array([[1, 2, 3], [4, 5, 6]])
>>> B = [[4, 5, 6], [7, 8, 9]]
>>> np.copyto(A, B)
>>> A
array([[4, 5, 6],
[7, 8, 9]])
"""
if not dpnp.is_supported_array_type(dst):
raise TypeError(
"Destination array must be any of supported type, "
f"but got {type(dst)}"
)
if not dpnp.is_supported_array_type(src):
src = dpnp.array(src, sycl_queue=dst.sycl_queue)
if not dpnp.can_cast(src.dtype, dst.dtype, casting=casting):
raise TypeError(
f"Cannot cast from {src.dtype} to {dst.dtype} "
f"according to the rule {casting}."
)
if where is True:
dst[...] = src
elif where is False:
# nothing to copy
pass
else:
if dpnp.isscalar(where):
where = dpnp.array(
where, dtype=dpnp.bool, sycl_queue=dst.sycl_queue
)
elif not dpnp.is_supported_array_type(where):
raise TypeError(
"`where` array must be any of supported type, "
f"but got {type(where)}"
)
elif where.dtype != dpnp.bool:
raise TypeError(
"`where` keyword argument must be of boolean type, "
f"but got {where.dtype}"
)
dst_usm, src_usm, mask_usm = dpt.broadcast_arrays(
dpnp.get_usm_ndarray(dst),
dpnp.get_usm_ndarray(src),
dpnp.get_usm_ndarray(where),
)
dst_usm[mask_usm] = src_usm[mask_usm]
[docs]
def delete(arr, obj, axis=None):
"""
Return a new array with sub-arrays along an axis deleted. For a one
dimensional array, this returns those entries not returned by
``arr[obj]``.
For full documentation refer to :obj:`numpy.delete`.
Parameters
----------
arr : {dpnp.ndarray, usm_ndarray}
Input array.
obj : {slice, int, array-like of ints or boolean}
Indicate indices of sub-arrays to remove along the specified axis.
Boolean indices are treated as a mask of elements to remove.
axis : {None, int}, optional
The axis along which to delete the subarray defined by `obj`.
If `axis` is ``None``, `obj` is applied to the flattened array.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
A copy of `arr` with the elements specified by `obj` removed. Note
that `delete` does not occur in-place. If `axis` is ``None``, `out` is
a flattened array.
See Also
--------
:obj:`dpnp.insert` : Insert elements into an array.
:obj:`dpnp.append` : Append elements at the end of an array.
Notes
-----
Often it is preferable to use a boolean mask. For example:
>>> import dpnp as np
>>> arr = np.arange(12) + 1
>>> mask = np.ones(len(arr), dtype=np.bool)
>>> mask[0] = mask[2] = mask[4] = False
>>> result = arr[mask,...]
is equivalent to ``np.delete(arr, [0, 2, 4], axis=0)``, but allows further
use of `mask`.
Examples
--------
>>> import dpnp as np
>>> arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
>>> arr
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
>>> np.delete(arr, 1, 0)
array([[ 1, 2, 3, 4],
[ 9, 10, 11, 12]])
>>> np.delete(arr, slice(None, None, 2), 1)
array([[ 2, 4],
[ 6, 8],
[10, 12]])
>>> np.delete(arr, [1, 3, 5], None)
array([ 1, 3, 5, 7, 8, 9, 10, 11, 12])
"""
dpnp.check_supported_arrays_type(arr)
params = _calc_parameters(arr, axis, obj)
if isinstance(obj, slice):
return _delete_with_slice(params, obj, axis)
if isinstance(obj, (int, dpnp.integer)) and not isinstance(obj, bool):
single_value = True
indices = obj
else:
single_value = False
is_array = isinstance(obj, (dpnp_array, numpy.ndarray, dpt.usm_ndarray))
indices = dpnp.asarray(
obj, sycl_queue=params.exec_q, usm_type=params.usm_type
)
# if `obj` is originally an empty list, after converting it into
# an array, it will have float dtype, so we need to change its dtype
# to integer. However, if `obj` is originally an empty array with
# float dtype, it is a mistake by user and it will raise an error later
if indices.size == 0 and not is_array:
indices = indices.astype(dpnp.intp)
elif indices.size == 1 and indices.dtype.kind in "ui":
# For a size 1 integer array we can use the single-value path
# (most dtypes, except boolean, should just fail later).
single_value = True
# In dpnp, `.item()` calls `.wait()`, so it is preferred to avoid it
# When possible (i.e. for numpy arrays, lists, etc), it is
# preferred to use `.item()` on a NumPy array
if dpnp.is_supported_array_type(obj):
indices = indices.item()
else:
indices = numpy.asarray(obj).item()
return _delete_without_slice(params, indices, axis, single_value)
[docs]
def dsplit(ary, indices_or_sections):
"""
Split array into multiple sub-arrays along the 3rd axis (depth).
Please refer to the :obj:`dpnp.split` documentation. ``dsplit``
is equivalent to ``split`` with ``axis=2``, the array is always
split along the third axis provided the array dimension is greater than
or equal to 3.
For full documentation refer to :obj:`numpy.dsplit`.
Parameters
----------
ary : {dpnp.ndarray, usm_ndarray}
Array to be divided into sub-arrays.
indices_or_sections : {int, sequence of ints}
If `indices_or_sections` is an integer, N, the array will be divided
into N equal arrays along the third axis. If such a split is not
possible, an error is raised.
If `indices_or_sections` is a sequence of sorted integers, the entries
indicate where along the third axis the array is split.
Returns
-------
sub-arrays : list of dpnp.ndarray
A list of sub arrays. Each array is a view of the corresponding input
array.
See Also
--------
:obj:`dpnp.split` : Split array into multiple sub-arrays of equal size.
Examples
--------
>>> import dpnp as np
>>> x = np.arange(16.0).reshape(2, 2, 4)
>>> x
array([[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.]],
[[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]])
>>> np.dsplit(x, 2)
[array([[[ 0., 1.],
[ 4., 5.]],
[[ 8., 9.],
[12., 13.]]]),
array([[[ 2., 3.],
[ 6., 7.]],
[[10., 11.],
[14., 15.]]])]
>>> np.dsplit(x, np.array([3, 6]))
[array([[[ 0., 1., 2.],
[ 4., 5., 6.]],
[[ 8., 9., 10.],
[12., 13., 14.]]]),
array([[[ 3.],
[ 7.]],
[[11.],
[15.]]]),
array([])]
"""
dpnp.check_supported_arrays_type(ary)
if ary.ndim < 3:
raise ValueError("dsplit only works on arrays of 3 or more dimensions")
return split(ary, indices_or_sections, 2)
[docs]
def dstack(tup):
"""
Stack arrays in sequence depth wise (along third axis).
This is equivalent to concatenation along the third axis after 2-D arrays
of shape `(M, N)` have been reshaped to `(M, N, 1)` and 1-D arrays of shape
`(N,)` have been reshaped to `(1, N, 1)`. Rebuilds arrays divided by
:obj:`dpnp.dsplit`.
For full documentation refer to :obj:`numpy.dstack`.
Parameters
----------
tup : {dpnp.ndarray, usm_ndarray}
One or more array-like sequences. The arrays must have the same shape
along all but the third axis. 1-D or 2-D arrays must have the same
shape.
Returns
-------
out : dpnp.ndarray
The array formed by stacking the given arrays, will be at least 3-D.
See Also
--------
:obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis.
:obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise).
:obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise).
:obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array.
:obj:`dpnp.stack` : Join a sequence of arrays along a new axis.
:obj:`dpnp.block` : Assemble an ndarray from nested lists of blocks.
:obj:`dpnp.dsplit` : Split array along third axis.
Examples
--------
>>> import dpnp as np
>>> a = np.array((1, 2, 3))
>>> b = np.array((2, 3, 4))
>>> np.dstack((a, b))
array([[[1, 2],
[2, 3],
[3, 4]]])
>>> a = np.array([[1], [2], [3]])
>>> b = np.array([[2], [3], [4]])
>>> np.dstack((a, b))
array([[[1, 2]],
[[2, 3]],
[[3, 4]]])
"""
_check_stack_arrays(tup)
arrs = atleast_3d(*tup)
if not isinstance(arrs, list):
arrs = [arrs]
return dpnp.concatenate(arrs, axis=2)
[docs]
def expand_dims(a, axis):
"""
Expand the shape of an array.
Insert a new axis that will appear at the `axis` position in the expanded
array shape.
For full documentation refer to :obj:`numpy.expand_dims`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input array.
axis : int or tuple of ints
Position in the expanded axes where the new axis (or axes) is placed.
Returns
-------
out : dpnp.ndarray
An array with the number of dimensions increased.
A view is returned whenever possible.
Notes
-----
If `a` has rank (i.e, number of dimensions) `N`, a valid `axis` must reside
in the closed-interval `[-N-1, N]`.
If provided a negative `axis`, the `axis` position at which to insert a
singleton dimension is computed as `N + axis + 1`.
Hence, if provided `-1`, the resolved axis position is `N` (i.e.,
a singleton dimension must be appended to the input array `a`).
If provided `-N-1`, the resolved axis position is `0` (i.e., a
singleton dimension is added to the input array `a`).
See Also
--------
:obj:`dpnp.squeeze` : The inverse operation, removing singleton dimensions
:obj:`dpnp.reshape` : Insert, remove, and combine dimensions, and resize
existing ones
:obj:`dpnp.atleast_1d` : Convert inputs to arrays with at least one
dimension.
:obj:`dpnp.atleast_2d` : View inputs as arrays with at least two dimensions.
:obj:`dpnp.atleast_3d` : View inputs as arrays with at least three
dimensions.
Examples
--------
>>> import dpnp as np
>>> x = np.array([1, 2])
>>> x.shape
(2,)
The following is equivalent to ``x[np.newaxis, :]`` or ``x[np.newaxis]``:
>>> y = np.expand_dims(x, axis=0)
>>> y
array([[1, 2]])
>>> y.shape
(1, 2)
The following is equivalent to ``x[:, np.newaxis]``:
>>> y = np.expand_dims(x, axis=1)
>>> y
array([[1],
[2]])
>>> y.shape
(2, 1)
``axis`` may also be a tuple:
>>> y = np.expand_dims(x, axis=(0, 1))
>>> y
array([[[1, 2]]])
>>> y = np.expand_dims(x, axis=(2, 0))
>>> y
array([[[1],
[2]]])
Note that some examples may use ``None`` instead of ``np.newaxis``. These
are the same objects:
>>> np.newaxis is None
True
"""
usm_a = dpnp.get_usm_ndarray(a)
usm_res = dpt.expand_dims(usm_a, axis=axis)
return dpnp_array._create_from_usm_ndarray(usm_res)
[docs]
def flip(m, axis=None):
"""
Reverse the order of elements in an array along the given axis.
The shape of the array is preserved, but the elements are reordered.
For full documentation refer to :obj:`numpy.flip`.
Parameters
----------
m : {dpnp.ndarray, usm_ndarray}
Input array.
axis : None or int or tuple of ints, optional
Axis or axes along which to flip over. The default,
``axis=None``, will flip over all of the axes of the input array.
If `axis` is negative it counts from the last to the first axis.
If `axis` is a tuple of integers, flipping is performed on all of
the axes specified in the tuple.
Returns
-------
out : dpnp.ndarray
A view of `m` with the entries of axis reversed.
See Also
--------
:obj:`dpnp.flipud` : Flip an array vertically (axis=0).
:obj:`dpnp.fliplr` : Flip an array horizontally (axis=1).
Examples
--------
>>> import dpnp as np
>>> A = np.arange(8).reshape((2, 2, 2))
>>> A
array([[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]])
>>> np.flip(A, 0)
array([[[4, 5],
[6, 7]],
[[0, 1],
[2, 3]]])
>>> np.flip(A, 1)
array([[[2, 3],
[0, 1]],
[[6, 7],
[4, 5]]])
>>> np.flip(A)
array([[[7, 6],
[5, 4]],
[[3, 2],
[1, 0]]])
>>> np.flip(A, (0, 2))
array([[[5, 4],
[7, 6]],
[[1, 0],
[3, 2]]])
>>> A = np.random.randn(3, 4, 5)
>>> np.all(np.flip(A, 2) == A[:, :, ::-1, ...])
array(True)
"""
m_usm = dpnp.get_usm_ndarray(m)
return dpnp_array._create_from_usm_ndarray(dpt.flip(m_usm, axis=axis))
[docs]
def fliplr(m):
"""
Reverse the order of elements along axis 1 (left/right).
For a 2-D array, this flips the entries in each row in the left/right
direction. Columns are preserved, but appear in a different order than
before.
For full documentation refer to :obj:`numpy.fliplr`.
Parameters
----------
m : {dpnp.ndarray, usm_ndarray}
Input array, must be at least 2-D.
Returns
-------
out : dpnp.ndarray
A view of `m` with the columns reversed.
See Also
--------
:obj:`dpnp.flipud` : Flip an array vertically (axis=0).
:obj:`dpnp.flip` : Flip array in one or more dimensions.
:obj:`dpnp.rot90` : Rotate array counterclockwise.
Examples
--------
>>> import dpnp as np
>>> A = np.diag(np.array([1., 2., 3.]))
>>> A
array([[1., 0., 0.],
[0., 2., 0.],
[0., 0., 3.]])
>>> np.fliplr(A)
array([[0., 0., 1.],
[0., 2., 0.],
[3., 0., 0.]])
>>> A = np.random.randn(2, 3, 5)
>>> np.all(np.fliplr(A) == A[:, ::-1, ...])
array(True)
"""
dpnp.check_supported_arrays_type(m)
if m.ndim < 2:
raise ValueError(f"Input must be >= 2-d, but got {m.ndim}")
return m[:, ::-1]
[docs]
def flipud(m):
"""
Reverse the order of elements along axis 0 (up/down).
For a 2-D array, this flips the entries in each column in the up/down
direction. Rows are preserved, but appear in a different order than before.
For full documentation refer to :obj:`numpy.flipud`.
Parameters
----------
m : {dpnp.ndarray, usm_ndarray}
Input array.
Returns
-------
out : dpnp.ndarray
A view of `m` with the rows reversed.
See Also
--------
:obj:`dpnp.fliplr` : Flip array in the left/right direction.
:obj:`dpnp.flip` : Flip array in one or more dimensions.
:obj:`dpnp.rot90` : Rotate array counterclockwise.
Examples
--------
>>> import dpnp as np
>>> A = np.diag(np.array([1., 2., 3.]))
>>> A
array([[1., 0., 0.],
[0., 2., 0.],
[0., 0., 3.]])
>>> np.flipud(A)
array([[0., 0., 3.],
[0., 2., 0.],
[1., 0., 0.]])
>>> A = np.random.randn(2, 3, 5)
>>> np.all(np.flipud(A) == A[::-1, ...])
array(True)
>>> np.flipud(np.array([1, 2]))
array([2, 1])
"""
dpnp.check_supported_arrays_type(m)
if m.ndim < 1:
raise ValueError(f"Input must be >= 1-d, but got {m.ndim}")
return m[::-1, ...]
[docs]
def hsplit(ary, indices_or_sections):
"""
Split an array into multiple sub-arrays horizontally (column-wise).
Please refer to the :obj:`dpnp.split` documentation. ``hsplit``
is equivalent to ``dpnp.split`` with ``axis=1``, the array is always
split along the second axis except for 1-D arrays, where it is split at
``axis=0``.
For full documentation refer to :obj:`numpy.hsplit`.
Parameters
----------
ary : {dpnp.ndarray, usm_ndarray}
Array to be divided into sub-arrays.
indices_or_sections : {int, sequence of ints}
If `indices_or_sections` is an integer, N, the array will be divided
into N equal arrays along the second axis except for 1-D arrays, where
it is split at the first axis. If such a split is not possible,
an error is raised.
If `indices_or_sections` is a sequence of sorted integers, the entries
indicate where along the second axis the array is split. For 1-D arrays,
the entries indicate where along the first axis the array is split.
Returns
-------
sub-arrays : list of dpnp.ndarray
A list of sub arrays. Each array is a view of the corresponding input
array.
See Also
--------
:obj:`dpnp.split` : Split array into multiple sub-arrays of equal size.
Examples
--------
>>> import dpnp as np
>>> x = np.arange(16.0).reshape(4, 4)
>>> x
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]])
>>> np.hsplit(x, 2)
[array([[ 0., 1.],
[ 4., 5.],
[ 8., 9.],
[12., 13.]]),
array([[ 2., 3.],
[ 6., 7.],
[10., 11.],
[14., 15.]])]
>>> np.hsplit(x, np.array([3, 6]))
[array([[ 0., 1., 2.],
[ 4., 5., 6.],
[ 8., 9., 10.],
[12., 13., 14.]]),
array([[ 3.],
[ 7.],
[11.],
[15.]]),
array([])]
With a higher dimensional array the split is still along the second axis.
>>> x = np.arange(8.0).reshape(2, 2, 2)
>>> x
array([[[0., 1.],
[2., 3.]],
[[4., 5.],
[6., 7.]]])
>>> np.hsplit(x, 2)
[array([[[0., 1.]],
[[4., 5.]]]),
array([[[2., 3.]],
[[6., 7.]]])]
With a 1-D array, the split is along axis 0.
>>> x = np.array([0, 1, 2, 3, 4, 5])
>>> np.hsplit(x, 2)
[array([0, 1, 2]), array([3, 4, 5])]
"""
dpnp.check_supported_arrays_type(ary)
if ary.ndim == 0:
raise ValueError("hsplit only works on arrays of 1 or more dimensions")
if ary.ndim > 1:
return split(ary, indices_or_sections, 1)
return split(ary, indices_or_sections, 0)
[docs]
def hstack(tup, *, dtype=None, casting="same_kind"):
"""
Stack arrays in sequence horizontally (column wise).
For full documentation refer to :obj:`numpy.hstack`.
Parameters
----------
tup : {dpnp.ndarray, usm_ndarray}
The arrays must have the same shape along all but the second axis,
except 1-D arrays which can be any length.
dtype : str or dtype
If provided, the destination array will have this dtype.
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
Controls what kind of data casting may occur. Defaults to 'same_kind'.
Returns
-------
out : dpnp.ndarray
The stacked array which has one more dimension than the input arrays.
See Also
--------
:obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis.
:obj:`dpnp.stack` : Join a sequence of arrays along a new axis.
:obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise).
:obj:`dpnp.dstack` : Stack arrays in sequence depth wise
(along third dimension).
:obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array.
:obj:`dpnp.block` : Assemble an ndarray from nested lists of blocks.
:obj:`dpnp.split` : Split array into a list of multiple sub-arrays of equal
size.
:obj:`dpnp.unstack` : Split an array into a tuple of sub-arrays along
an axis.
Examples
--------
>>> import dpnp as np
>>> a = np.array((1, 2, 3))
>>> b = np.array((4, 5, 6))
>>> np.hstack((a, b))
array([1, 2, 3, 4, 5, 6])
>>> a = np.array([[1], [2], [3]])
>>> b = np.array([[4], [5], [6]])
>>> np.hstack((a, b))
array([[1, 4],
[2, 5],
[3, 6]])
"""
_check_stack_arrays(tup)
arrs = dpnp.atleast_1d(*tup)
if not isinstance(arrs, list):
arrs = [arrs]
# As a special case, dimension 0 of 1-dimensional arrays is "horizontal"
if arrs and arrs[0].ndim == 1:
return dpnp.concatenate(arrs, axis=0, dtype=dtype, casting=casting)
return dpnp.concatenate(arrs, axis=1, dtype=dtype, casting=casting)
[docs]
def insert(arr, obj, values, axis=None):
"""
Insert values along the given axis before the given indices.
For full documentation refer to :obj:`numpy.insert`.
Parameters
----------
arr : array_like
Input array.
obj : {slice, int, array-like of ints or bools}
Object that defines the index or indices before which `values` is
inserted. It supports multiple insertions when `obj` is a single
scalar or a sequence with one element (similar to calling insert
multiple times).
Boolean indices are treated as a mask of elements to insert.
values : array_like
Values to insert into `arr`. If the type of `values` is different
from that of `arr`, `values` is converted to the type of `arr`.
`values` should be shaped so that ``arr[..., obj, ...] = values``
is legal.
axis : {None, int}, optional
Axis along which to insert `values`. If `axis` is ``None`` then `arr`
is flattened first.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
A copy of `arr` with `values` inserted. Note that :obj:`dpnp.insert`
does not occur in-place: a new array is returned. If
`axis` is ``None``, `out` is a flattened array.
See Also
--------
:obj:`dpnp.append` : Append elements at the end of an array.
:obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis.
:obj:`dpnp.delete` : Delete elements from an array.
Notes
-----
Note that for higher dimensional inserts ``obj=0`` behaves very different
from ``obj=[0]`` just like ``arr[:, 0, :] = values`` is different from
``arr[:, [0], :] = values``.
Examples
--------
>>> import dpnp as np
>>> a = np.array([[1, 1], [2, 2], [3, 3]])
>>> a
array([[1, 1],
[2, 2],
[3, 3]])
>>> np.insert(a, 1, 5)
array([1, 5, 1, 2, 2, 3, 3])
>>> np.insert(a, 1, 5, axis=1)
array([[1, 5, 1],
[2, 5, 2],
[3, 5, 3]])
Difference between sequence and scalars:
>>> np.insert(a, [1], [[1],[2],[3]], axis=1)
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
>>> np.array_equal(np.insert(a, 1, [1, 2, 3], axis=1),
... np.insert(a, [1], [[1],[2],[3]], axis=1))
array(True)
>>> b = a.flatten()
>>> b
array([1, 1, 2, 2, 3, 3])
>>> np.insert(b, [2, 2], [5, 6])
array([1, 1, 5, 6, 2, 2, 3, 3])
>>> np.insert(b, slice(2, 4), [5, 6])
array([1, 1, 5, 2, 6, 2, 3, 3])
>>> np.insert(b, [2, 2], [7.13, False]) # dtype casting
array([1, 1, 7, 0, 2, 2, 3, 3])
>>> x = np.arange(8).reshape(2, 4)
>>> idx = (1, 3)
>>> np.insert(x, idx, 999, axis=1)
array([[ 0, 999, 1, 2, 999, 3],
[ 4, 999, 5, 6, 999, 7]])
"""
dpnp.check_supported_arrays_type(arr)
params = _calc_parameters(arr, axis, obj, values)
if isinstance(obj, slice):
# turn it into a range object
indices = dpnp.arange(
*obj.indices(params.n),
dtype=dpnp.intp,
sycl_queue=params.exec_q,
usm_type=params.usm_type,
)
else:
# need to copy obj, because indices will be changed in-place
indices = dpnp.copy(
obj, sycl_queue=params.exec_q, usm_type=params.usm_type
)
if indices.dtype == dpnp.bool:
if indices.ndim != 1:
raise ValueError(
"boolean array argument obj to insert "
"must be one dimensional"
)
indices = dpnp.flatnonzero(indices)
elif indices.ndim > 1:
raise ValueError(
"index array argument `obj` to insert must be one-dimensional "
"or scalar"
)
if indices.size == 1:
return _insert_singleton_index(params, indices, values, obj)
return _insert_array_indices(params, indices, values, obj)
[docs]
def matrix_transpose(x, /):
"""
Transposes a matrix (or a stack of matrices) `x`.
For full documentation refer to :obj:`numpy.matrix_transpose`.
Parameters
----------
x : (..., M, N) {dpnp.ndarray, usm_ndarray}
Input array with ``x.ndim >= 2`` and whose two innermost
dimensions form ``MxN`` matrices.
Returns
-------
out : dpnp.ndarray
An array containing the transpose for each matrix and having shape
(..., N, M).
See Also
--------
:obj:`dpnp.transpose` : Returns an array with axes transposed.
:obj:`dpnp.linalg.matrix_transpose` : Equivalent function.
:obj:`dpnp.ndarray.mT` : Equivalent method.
Examples
--------
>>> import dpnp as np
>>> a = np.array([[1, 2], [3, 4]])
>>> np.matrix_transpose(a)
array([[1, 3],
[2, 4]])
>>> b = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
>>> np.matrix_transpose(b)
array([[[1, 3],
[2, 4]],
[[5, 7],
[6, 8]]])
"""
usm_x = dpnp.get_usm_ndarray(x)
if usm_x.ndim < 2:
raise ValueError(
"Input array must be at least 2-dimensional, "
f"but it is {usm_x.ndim}"
)
usm_res = dpt.matrix_transpose(usm_x)
return dpnp_array._create_from_usm_ndarray(usm_res)
[docs]
def moveaxis(a, source, destination):
"""
Move axes of an array to new positions. Other axes remain in their original
order.
For full documentation refer to :obj:`numpy.moveaxis`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
The array whose axes should be reordered.
source : int or sequence of int
Original positions of the axes to move. These must be unique.
destination : int or sequence of int
Destination positions for each of the original axes. These must also be
unique.
Returns
-------
out : dpnp.ndarray
Array with moved axes. This array is a view of the input array.
See Also
--------
:obj:`dpnp.transpose` : Permute the dimensions of an array.
:obj:`dpnp.swapaxes` : Interchange two axes of an array.
Examples
--------
>>> import dpnp as np
>>> x = np.zeros((3, 4, 5))
>>> np.moveaxis(x, 0, -1).shape
(4, 5, 3)
>>> np.moveaxis(x, -1, 0).shape
(5, 3, 4)
"""
usm_array = dpnp.get_usm_ndarray(a)
return dpnp_array._create_from_usm_ndarray(
dpt.moveaxis(usm_array, source, destination)
)
[docs]
def ndim(a):
"""
Return the number of dimensions of array-like input.
For full documentation refer to :obj:`numpy.ndim`.
Parameters
----------
a : array_like
Input data.
Returns
-------
number_of_dimensions : int
The number of dimensions in `a`. Scalars are zero-dimensional.
See Also
--------
:obj:`dpnp.ndarray.ndim` : Equivalent method for `dpnp.ndarray`
or `usm_ndarray` input.
:obj:`dpnp.shape` : Return the shape of an array.
:obj:`dpnp.ndarray.shape` : Return the shape of an array.
Examples
--------
>>> import dpnp as np
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> np.ndim(a)
2
>>> a = np.asarray(a)
>>> np.ndim(a)
2
>>> np.ndim(1)
0
"""
if dpnp.is_supported_array_type(a):
return a.ndim
return numpy.ndim(a)
[docs]
def pad(array, pad_width, mode="constant", **kwargs):
"""
Pad an array.
For full documentation refer to :obj:`numpy.pad`.
Parameters
----------
array : {dpnp.ndarray, usm_ndarray}
The array of rank ``N`` to pad.
pad_width : {sequence, array_like, int}
Number of values padded to the edges of each axis.
``((before_1, after_1), ... (before_N, after_N))`` unique pad widths
for each axis.
``(before, after)`` or ``((before, after),)`` yields same before
and after pad for each axis.
``(pad,)`` or ``int`` is a shortcut for ``before = after = pad`` width
for all axes.
mode : {str, function}, optional
One of the following string values or a user supplied function.
"constant"
Pads with a constant value.
"edge"
Pads with the edge values of array.
"linear_ramp"
Pads with the linear ramp between `end_value` and the
array edge value.
"maximum"
Pads with the maximum value of all or part of the
vector along each axis.
"mean"
Pads with the mean value of all or part of the
vector along each axis.
"median"
Pads with the median value of all or part of the
vector along each axis.
"minimum"
Pads with the minimum value of all or part of the
vector along each axis.
"reflect"
Pads with the reflection of the vector mirrored on
the first and last values of the vector along each
axis.
"symmetric"
Pads with the reflection of the vector mirrored
along the edge of the array.
"wrap"
Pads with the wrap of the vector along the axis.
The first values are used to pad the end and the
end values are used to pad the beginning.
"empty"
Pads with undefined values.
<function>
Padding function, see Notes.
Default: ``"constant"``.
stat_length : {None, int, sequence of ints}, optional
Used in ``"maximum"``, ``"mean"``, ``"median"``, and ``"minimum"``.
Number of values at edge of each axis used to calculate the statistic
value. ``((before_1, after_1), ... (before_N, after_N))`` unique
statistic lengths for each axis.
``(before, after)`` or ``((before, after),)`` yields same before
and after statistic lengths for each axis.
``(stat_length,)`` or ``int`` is a shortcut for
``before = after = statistic`` length for all axes.
Default: ``None``, to use the entire axis.
constant_values : {sequence, scalar}, optional
Used in ``"constant"``. The values to set the padded values for each
axis.
``((before_1, after_1), ... (before_N, after_N))`` unique pad constants
for each axis.
``(before, after)`` or ``((before, after),)`` yields same before
and after constants for each axis.
``(constant,)`` or ``constant`` is a shortcut for
``before = after = constant`` for all axes.
Default: ``0``.
end_values : {sequence, scalar}, optional
Used in ``"linear_ramp"``. The values used for the ending value of the
linear_ramp and that will form the edge of the padded array.
``((before_1, after_1), ... (before_N, after_N))`` unique end values
for each axis.
``(before, after)`` or ``((before, after),)`` yields same before
and after end values for each axis.
``(constant,)`` or ``constant`` is a shortcut for
``before = after = constant`` for all axes.
Default: ``0``.
reflect_type : {"even", "odd"}, optional
Used in ``"reflect"``, and ``"symmetric"``. The ``"even"`` style is the
default with an unaltered reflection around the edge value. For
the ``"odd"`` style, the extended part of the array is created by
subtracting the reflected values from two times the edge value.
Default: ``"even"``.
Returns
-------
padded array : dpnp.ndarray
Padded array of rank equal to `array` with shape increased
according to `pad_width`.
Notes
-----
For an array with rank greater than 1, some of the padding of later
axes is calculated from padding of previous axes. This is easiest to
think about with a rank 2 array where the corners of the padded array
are calculated by using padded values from the first axis.
The padding function, if used, should modify a rank 1 array in-place. It
has the following signature::
padding_func(vector, iaxis_pad_width, iaxis, kwargs)
where
vector : dpnp.ndarray
A rank 1 array already padded with zeros. Padded values are
vector[:iaxis_pad_width[0]] and vector[-iaxis_pad_width[1]:].
iaxis_pad_width : tuple
A 2-tuple of ints, iaxis_pad_width[0] represents the number of
values padded at the beginning of vector where
iaxis_pad_width[1] represents the number of values padded at
the end of vector.
iaxis : int
The axis currently being calculated.
kwargs : dict
Any keyword arguments the function requires.
Examples
--------
>>> import dpnp as np
>>> a = np.array([1, 2, 3, 4, 5])
>>> np.pad(a, (2, 3), 'constant', constant_values=(4, 6))
array([4, 4, 1, 2, 3, 4, 5, 6, 6, 6])
>>> np.pad(a, (2, 3), 'edge')
array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5])
>>> np.pad(a, (2, 3), 'linear_ramp', end_values=(5, -4))
array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4])
>>> np.pad(a, (2,), 'maximum')
array([5, 5, 1, 2, 3, 4, 5, 5, 5])
>>> np.pad(a, (2,), 'mean')
array([3, 3, 1, 2, 3, 4, 5, 3, 3])
>>> np.pad(a, (2,), 'median')
array([3, 3, 1, 2, 3, 4, 5, 3, 3])
>>> a = np.array([[1, 2], [3, 4]])
>>> np.pad(a, ((3, 2), (2, 3)), 'minimum')
array([[1, 1, 1, 2, 1, 1, 1],
[1, 1, 1, 2, 1, 1, 1],
[1, 1, 1, 2, 1, 1, 1],
[1, 1, 1, 2, 1, 1, 1],
[3, 3, 3, 4, 3, 3, 3],
[1, 1, 1, 2, 1, 1, 1],
[1, 1, 1, 2, 1, 1, 1]])
>>> a = np.array([1, 2, 3, 4, 5])
>>> np.pad(a, (2, 3), 'reflect')
array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2])
>>> np.pad(a, (2, 3), 'reflect', reflect_type='odd')
array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> np.pad(a, (2, 3), 'symmetric')
array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3])
>>> np.pad(a, (2, 3), 'symmetric', reflect_type='odd')
array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7])
>>> np.pad(a, (2, 3), 'wrap')
array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3])
>>> def pad_width(vector, pad_width, iaxis, kwargs):
... pad_value = kwargs.get('padder', 10)
... vector[:pad_width[0]] = pad_value
... vector[-pad_width[1]:] = pad_value
>>> a = np.arange(6)
>>> a = a.reshape((2, 3))
>>> np.pad(a, 2, pad_width)
array([[10, 10, 10, 10, 10, 10, 10],
[10, 10, 10, 10, 10, 10, 10],
[10, 10, 0, 1, 2, 10, 10],
[10, 10, 3, 4, 5, 10, 10],
[10, 10, 10, 10, 10, 10, 10],
[10, 10, 10, 10, 10, 10, 10]])
>>> np.pad(a, 2, pad_width, padder=100)
array([[100, 100, 100, 100, 100, 100, 100],
[100, 100, 100, 100, 100, 100, 100],
[100, 100, 0, 1, 2, 100, 100],
[100, 100, 3, 4, 5, 100, 100],
[100, 100, 100, 100, 100, 100, 100],
[100, 100, 100, 100, 100, 100, 100]])
"""
dpnp.check_supported_arrays_type(array)
return dpnp_pad(array, pad_width, mode=mode, **kwargs)
[docs]
def ravel(a, order="C"):
"""
Return a contiguous flattened array.
For full documentation refer to :obj:`numpy.ravel`.
Parameters
----------
x : {dpnp.ndarray, usm_ndarray}
Input array. The elements in `a` are read in the order specified by
order, and packed as a 1-D array.
order : {None, "C", "F", "A"}, optional
The elements of `a` are read using this index order. ``"C"`` means to
index the elements in row-major, C-style order, with the last axis
index changing fastest, back to the first axis index changing slowest.
``"F"`` means to index the elements in column-major, Fortran-style
order, with the first index changing fastest, and the last index
changing slowest. Note that the "C" and "F" options take no account of
the memory layout of the underlying array, and only refer to
the order of axis indexing. "A" means to read the elements in
Fortran-like index order if `a` is Fortran *contiguous* in
memory, C-like order otherwise. ``order=None`` is an alias for
``order="C"``.
Default: ``"C"``.
Returns
-------
out : dpnp.ndarray
A contiguous 1-D array of the same subtype as `a`, with shape (a.size,).
Limitations
-----------
`order="K"` is not supported and the function raises `NotImplementedError`
exception.
See Also
--------
:obj:`dpnp.ndarray.flat` : 1-D iterator over an array.
:obj:`dpnp.ndarray.flatten` : 1-D array copy of the elements of an array
in row-major order.
:obj:`dpnp.ndarray.reshape` : Change the shape of an array without
changing its data.
:obj:`dpnp.reshape` : The same as :obj:`dpnp.ndarray.reshape`.
Notes
-----
In row-major, C-style order, in two dimensions, the row index
varies the slowest, and the column index the quickest. This can
be generalized to multiple dimensions, where row-major order
implies that the index along the first axis varies slowest, and
the index along the last quickest. The opposite holds for
column-major, Fortran-style index ordering.
When a view is desired in as many cases as possible, ``arr.reshape(-1)``
may be preferable.
Examples
--------
>>> import dpnp as np
>>> x = np.array([[1, 2, 3], [4, 5, 6]])
>>> np.ravel(x)
array([1, 2, 3, 4, 5, 6])
>>> x.reshape(-1)
array([1, 2, 3, 4, 5, 6])
>>> np.ravel(x, order='F')
array([1, 4, 2, 5, 3, 6])
When `order` is ``"A"``, it will preserve the array's
``"C"`` or ``"F"`` ordering:
>>> np.ravel(x.T)
array([1, 4, 2, 5, 3, 6])
>>> np.ravel(x.T, order='A')
array([1, 2, 3, 4, 5, 6])
"""
if order in "kK":
raise NotImplementedError(
"Keyword argument `order` is supported only with "
f"values None, 'C', 'F', and 'A', but got '{order}'"
)
result = dpnp.reshape(a, -1, order=order)
if result.flags.c_contiguous:
return result
return dpnp.ascontiguousarray(result)
[docs]
def repeat(a, repeats, axis=None):
"""
Repeat elements of an array.
For full documentation refer to :obj:`numpy.repeat`.
Parameters
----------
x : {dpnp.ndarray, usm_ndarray}
Input array.
repeats : {int, tuple, list, range, dpnp.ndarray, usm_ndarray}
The number of repetitions for each element. `repeats` is broadcasted to
fit the shape of the given axis.
If `repeats` is an array, it must have an integer data type.
Otherwise, `repeats` must be a Python integer or sequence of Python
integers (i.e., a tuple, list, or range).
axis : {None, int}, optional
The axis along which to repeat values. By default, use the flattened
input array, and return a flat output array.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
Output array which has the same shape as `a`, except along the given
axis.
See Also
--------
:obj:`dpnp.tile` : Tile an array.
:obj:`dpnp.unique` : Find the unique elements of an array.
Examples
--------
>>> import dpnp as np
>>> x = np.array([3])
>>> np.repeat(x, 4)
array([3, 3, 3, 3])
>>> x = np.array([[1, 2], [3, 4]])
>>> np.repeat(x, 2)
array([1, 1, 2, 2, 3, 3, 4, 4])
>>> np.repeat(x, 3, axis=1)
array([[1, 1, 1, 2, 2, 2],
[3, 3, 3, 4, 4, 4]])
>>> np.repeat(x, [1, 2], axis=0)
array([[1, 2],
[3, 4],
[3, 4]])
"""
dpnp.check_supported_arrays_type(a)
if not isinstance(repeats, (int, tuple, list, range)):
repeats = dpnp.get_usm_ndarray(repeats)
if axis is None and a.ndim > 1:
a = dpnp.ravel(a)
usm_arr = dpnp.get_usm_ndarray(a)
usm_res = dpt.repeat(usm_arr, repeats, axis=axis)
return dpnp_array._create_from_usm_ndarray(usm_res)
[docs]
def require(a, dtype=None, requirements=None, *, like=None):
"""
Return a :class:`dpnp.ndarray` of the provided type that satisfies
requirements.
This function is useful to be sure that an array with the correct flags
is returned for passing to compiled code (perhaps through ctypes).
For full documentation refer to :obj:`numpy.require`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
The input array to be converted to a type-and-requirement-satisfying
array.
dtype : {None, data-type}, optional
The required data-type. If ``None`` preserve the current dtype.
requirements : {None, str, sequence of str}, optional
The requirements list can be any of the following:
* 'F_CONTIGUOUS' ('F') - ensure a Fortran-contiguous array
* 'C_CONTIGUOUS' ('C') - ensure a C-contiguous array
* 'WRITABLE' ('W') - ensure a writable array
Returns
-------
out : dpnp.ndarray
Array with specified requirements and type if given.
Limitations
-----------
Parameter `like` is supported only with default value ``None``.
Otherwise, the function raises `NotImplementedError` exception.
See Also
--------
:obj:`dpnp.asarray` : Convert input to an ndarray.
:obj:`dpnp.asanyarray` : Convert to an ndarray, but pass through
ndarray subclasses.
:obj:`dpnp.ascontiguousarray` : Convert input to a contiguous array.
:obj:`dpnp.asfortranarray` : Convert input to an ndarray with
column-major memory order.
:obj:`dpnp.ndarray.flags` : Information about the memory layout
of the array.
Notes
-----
The returned array will be guaranteed to have the listed requirements
by making a copy if needed.
Examples
--------
>>> import dpnp as np
>>> x = np.arange(6).reshape(2, 3)
>>> x.flags
C_CONTIGUOUS : True
F_CONTIGUOUS : False
WRITEABLE : True
>>> y = np.require(x, dtype=np.float32, requirements=['W', 'F'])
>>> y.flags
C_CONTIGUOUS : False
F_CONTIGUOUS : True
WRITEABLE : True
"""
dpnp.check_limitations(like=like)
dpnp.check_supported_arrays_type(a)
possible_flags = {
"C": "C",
"C_CONTIGUOUS": "C",
"F": "F",
"F_CONTIGUOUS": "F",
"W": "W",
"WRITEABLE": "W",
}
if not requirements:
return dpnp.asanyarray(a, dtype=dtype)
try:
requirements = {possible_flags[x.upper()] for x in requirements}
except KeyError as exc:
incorrect_flag = (set(requirements) - set(possible_flags.keys())).pop()
raise ValueError(
f"Incorrect flag {incorrect_flag} in requirements"
) from exc
order = "A"
if requirements.issuperset({"C", "F"}):
raise ValueError("Cannot specify both 'C' and 'F' order")
if "F" in requirements:
order = "F"
requirements.remove("F")
elif "C" in requirements:
order = "C"
requirements.remove("C")
arr = dpnp.array(a, dtype=dtype, order=order, copy=None)
if not arr.flags["W"]:
return arr.copy(order)
return arr
[docs]
def reshape(a, /, shape=None, order="C", *, newshape=None, copy=None):
"""
Gives a new shape to an array without changing its data.
For full documentation refer to :obj:`numpy.reshape`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Array to be reshaped.
shape : int or tuple of ints
The new shape should be compatible with the original shape. If
an integer, then the result will be a 1-D array of that length.
One shape dimension can be -1. In this case, the value is
inferred from the length of the array and remaining dimensions.
order : {None, "C", "F", "A"}, optional
Read the elements of `a` using this index order, and place the
elements into the reshaped array using this index order. ``"C"``
means to read / write the elements using C-like index order,
with the last axis index changing fastest, back to the first
axis index changing slowest. ``"F"`` means to read / write the
elements using Fortran-like index order, with the first index
changing fastest, and the last index changing slowest. Note that
the ``"C"`` and ``"F"`` options take no account of the memory layout of
the underlying array, and only refer to the order of indexing.
``order=None`` is an alias for ``order="C"``. ``"A"`` means to
read / write the elements in Fortran-like index order if ``a`` is
Fortran *contiguous* in memory, C-like order otherwise.
Default: ``"C"``.
newshape : int or tuple of ints
Replaced by `shape` argument. Retained for backward compatibility.
copy : {None, bool}, optional
If ``True``, then the array data is copied. If ``None``, a copy will
only be made if it's required by ``order``. For ``False`` it raises
a ``ValueError`` if a copy cannot be avoided.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
This will be a new view object if possible; otherwise, it will
be a copy. Note there is no guarantee of the *memory layout* (C- or
Fortran- contiguous) of the returned array.
See Also
--------
:obj:`dpnp.ndarray.reshape` : Equivalent method.
Notes
-----
It is not always possible to change the shape of an array without copying
the data.
The `order` keyword gives the index ordering both for *fetching*
the values from ``a``, and then *placing* the values into the output
array. For example, let's say you have an array:
>>> import dpnp as np
>>> a = np.arange(6).reshape((3, 2))
>>> a
array([[0, 1],
[2, 3],
[4, 5]])
You can think of reshaping as first raveling the array (using the given
index order), then inserting the elements from the raveled array into the
new array using the same kind of index ordering as was used for the
raveling.
>>> np.reshape(a, (2, 3)) # C-like index ordering
array([[0, 1, 2],
[3, 4, 5]])
>>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape
array([[0, 1, 2],
[3, 4, 5]])
>>> np.reshape(a, (2, 3), order='F') # Fortran-like index ordering
array([[0, 4, 3],
[2, 1, 5]])
>>> np.reshape(np.ravel(a, order='F'), (2, 3), order='F')
array([[0, 4, 3],
[2, 1, 5]])
Examples
--------
>>> import dpnp as np
>>> a = np.array([[1, 2, 3], [4, 5, 6]])
>>> np.reshape(a, 6)
array([1, 2, 3, 4, 5, 6])
>>> np.reshape(a, 6, order='F')
array([1, 4, 2, 5, 3, 6])
>>> np.reshape(a, (3, -1)) # the unspecified value is inferred to be 2
array([[1, 2],
[3, 4],
[5, 6]])
"""
if newshape is None and shape is None:
raise TypeError(
"reshape() missing 1 required positional argument: 'shape'"
)
if newshape is not None:
if shape is not None:
raise TypeError(
"You cannot specify 'newshape' and 'shape' arguments "
"at the same time."
)
# Deprecated in dpnp 0.17.0
warnings.warn(
"`newshape` keyword argument is deprecated, "
"use `shape=...` or pass shape positionally instead. "
"(deprecated in dpnp 0.17.0)",
DeprecationWarning,
stacklevel=2,
)
shape = newshape
if order is None:
order = "C"
elif order in "aA":
order = "F" if a.flags.fnc else "C"
elif order not in "cfCF":
raise ValueError(
f"order must be None, 'C', 'F', or 'A' (got '{order}')"
)
usm_a = dpnp.get_usm_ndarray(a)
usm_res = dpt.reshape(usm_a, shape=shape, order=order, copy=copy)
return dpnp_array._create_from_usm_ndarray(usm_res)
[docs]
def resize(a, new_shape):
"""
Return a new array with the specified shape.
If the new array is larger than the original array, then the new array is
filled with repeated copies of `a`. Note that this behavior is different
from ``a.resize(new_shape)`` which fills with zeros instead of repeated
copies of `a`.
For full documentation refer to :obj:`numpy.resize`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Array to be resized.
new_shape : {int, tuple or list of ints}
Shape of resized array.
Returns
-------
out : dpnp.ndarray
The new array is formed from the data in the old array, repeated
if necessary to fill out the required number of elements. The
data are repeated iterating over the array in C-order.
See Also
--------
:obj:`dpnp.ndarray.resize` : Resize an array in-place.
:obj:`dpnp.reshape` : Reshape an array without changing the total size.
:obj:`dpnp.pad` : Enlarge and pad an array.
:obj:`dpnp.repeat` : Repeat elements of an array.
Notes
-----
When the total size of the array does not change :obj:`dpnp.reshape` should
be used. In most other cases either indexing (to reduce the size) or
padding (to increase the size) may be a more appropriate solution.
Warning: This functionality does **not** consider axes separately,
i.e. it does not apply interpolation/extrapolation.
It fills the return array with the required number of elements, iterating
over `a` in C-order, disregarding axes (and cycling back from the start if
the new shape is larger). This functionality is therefore not suitable to
resize images, or data where each axis represents a separate and distinct
entity.
Examples
--------
>>> import dpnp as np
>>> a = np.array([[0, 1], [2, 3]])
>>> np.resize(a, (2, 3))
array([[0, 1, 2],
[3, 0, 1]])
>>> np.resize(a, (1, 4))
array([[0, 1, 2, 3]])
>>> np.resize(a, (2, 4))
array([[0, 1, 2, 3],
[0, 1, 2, 3]])
"""
dpnp.check_supported_arrays_type(a)
if a.ndim == 0:
return dpnp.full_like(a, a, shape=new_shape)
if isinstance(new_shape, (int, numpy.integer)):
new_shape = (new_shape,)
new_size = 1
for dim_length in new_shape:
if dim_length < 0:
raise ValueError("all elements of `new_shape` must be non-negative")
new_size *= dim_length
a_size = a.size
if a_size == 0 or new_size == 0:
# First case must zero fill. The second would have repeats == 0.
return dpnp.zeros_like(a, shape=new_shape)
repeats = -(-new_size // a_size) # ceil division
a = dpnp.concatenate((dpnp.ravel(a),) * repeats)[:new_size]
return a.reshape(new_shape)
[docs]
def result_type(*arrays_and_dtypes):
"""
result_type(*arrays_and_dtypes)
Returns the type that results from applying the NumPy
type promotion rules to the arguments.
For full documentation refer to :obj:`numpy.result_type`.
Parameters
----------
arrays_and_dtypes : list of {dpnp.ndarray, usm_ndarray, dtype}
An arbitrary length sequence of arrays or dtypes.
Returns
-------
out : dtype
The result type.
Examples
--------
>>> import dpnp as np
>>> a = np.arange(3, dtype=np.int64)
>>> b = np.arange(7, dtype=np.int32)
>>> np.result_type(a, b)
dtype('int64')
>>> np.result_type(np.int64, np.complex128)
dtype('complex128')
>>> np.result_type(np.ones(10, dtype=np.float32), np.float64)
dtype('float64')
"""
usm_arrays_and_dtypes = [
(
dpnp.get_usm_ndarray(X)
if isinstance(X, (dpnp_array, dpt.usm_ndarray))
else X
)
for X in arrays_and_dtypes
]
return dpt.result_type(*usm_arrays_and_dtypes)
[docs]
def roll(x, shift, axis=None):
"""
Roll the elements of an array by a number of positions along a given axis.
Array elements that roll beyond the last position are re-introduced
at the first position. Array elements that roll beyond the first position
are re-introduced at the last position.
For full documentation refer to :obj:`numpy.roll`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input array.
shift : {int, tuple of ints}
The number of places by which elements are shifted. If a tuple, then
`axis` must be a tuple of the same size, and each of the given axes
is shifted by the corresponding number. If an integer while `axis` is
a tuple of integers, then the same value is used for all given axes.
axis : {None, int, tuple of ints}, optional
Axis or axes along which elements are shifted. By default, the
array is flattened before shifting, after which the original
shape is restored.
Returns
-------
out : dpnp.ndarray
An array with the same data type as `x`
and whose elements, relative to `x`, are shifted.
See Also
--------
:obj:`dpnp.moveaxis` : Move array axes to new positions.
:obj:`dpnp.rollaxis` : Roll the specified axis backwards
until it lies in a given position.
Examples
--------
>>> import dpnp as np
>>> x1 = np.arange(10)
>>> np.roll(x1, 2)
array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])
>>> np.roll(x1, -2)
array([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])
>>> x2 = np.reshape(x1, (2, 5))
>>> np.roll(x2, 1, axis=0)
array([[5, 6, 7, 8, 9],
[0, 1, 2, 3, 4]])
>>> np.roll(x2, (2, 1), axis=(1, 0))
array([[8, 9, 5, 6, 7],
[3, 4, 0, 1, 2]])
"""
usm_x = dpnp.get_usm_ndarray(x)
if dpnp.is_supported_array_type(shift):
shift = dpnp.asnumpy(shift)
if axis is None:
return roll(dpt.reshape(usm_x, -1), shift, 0).reshape(x.shape)
usm_res = dpt.roll(usm_x, shift=shift, axis=axis)
return dpnp_array._create_from_usm_ndarray(usm_res)
[docs]
def rollaxis(x, axis, start=0):
"""
Roll the specified axis backwards, until it lies in a given position.
For full documentation refer to :obj:`numpy.rollaxis`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input array.
axis : int
The axis to be rolled. The positions of the other axes do not
change relative to one another.
start : int, optional
When ``start <= axis``, the axis is rolled back until it lies in
this position. When ``start > axis``, the axis is rolled until it
lies before this position. The default, ``0``, results in a "complete"
roll.
Returns
-------
out : dpnp.ndarray
An array with the same data type as `x` where the specified axis
has been moved to the requested position.
See Also
--------
:obj:`dpnp.moveaxis` : Move array axes to new positions.
:obj:`dpnp.roll` : Roll the elements of an array
by a number of positions along a given axis.
Examples
--------
>>> import dpnp as np
>>> a = np.ones((3,4,5,6))
>>> np.rollaxis(a, 3, 1).shape
(3, 6, 4, 5)
>>> np.rollaxis(a, 2).shape
(5, 3, 4, 6)
>>> np.rollaxis(a, 1, 4).shape
(3, 5, 6, 4)
"""
n = x.ndim
axis = normalize_axis_index(axis, n)
if start < 0:
start += n
msg = "'%s' arg requires %d <= %s < %d, but %d was passed in"
if not 0 <= start < n + 1:
raise ValueError(msg % ("start", -n, "start", n + 1, start))
if axis < start:
start -= 1
if axis == start:
return x
usm_array = dpnp.get_usm_ndarray(x)
return dpnp.moveaxis(usm_array, source=axis, destination=start)
[docs]
def rot90(m, k=1, axes=(0, 1)):
"""
Rotate an array by 90 degrees in the plane specified by axes.
Rotation direction is from the first towards the second axis.
This means for a 2D array with the default `k` and `axes`, the
rotation will be counterclockwise.
For full documentation refer to :obj:`numpy.rot90`.
Parameters
----------
m : {dpnp.ndarray, usm_ndarray}
Array of two or more dimensions.
k : integer, optional
Number of times the array is rotated by 90 degrees.
Default: ``1``.
axes : (2,) array_like of ints, optional
The array is rotated in the plane defined by the axes.
Axes must be different.
Default: ``(0, 1)``.
Returns
-------
out : dpnp.ndarray
A rotated view of `m`.
See Also
--------
:obj:`dpnp.flip` : Reverse the order of elements in an array along
the given axis.
:obj:`dpnp.fliplr` : Flip an array horizontally.
:obj:`dpnp.flipud` : Flip an array vertically.
Notes
-----
``rot90(m, k=1, axes=(1,0))`` is the reverse of
``rot90(m, k=1, axes=(0,1))``.
``rot90(m, k=1, axes=(1,0))`` is equivalent to
``rot90(m, k=-1, axes=(0,1))``.
Examples
--------
>>> import dpnp as np
>>> m = np.array([[1, 2], [3, 4]])
>>> m
array([[1, 2],
[3, 4]])
>>> np.rot90(m)
array([[2, 4],
[1, 3]])
>>> np.rot90(m, 2)
array([[4, 3],
[2, 1]])
>>> m = np.arange(8).reshape((2, 2, 2))
>>> np.rot90(m, 1, (1, 2))
array([[[1, 3],
[0, 2]],
[[5, 7],
[4, 6]]])
"""
dpnp.check_supported_arrays_type(m)
k = operator.index(k)
m_ndim = m.ndim
if m_ndim < 2:
raise ValueError("Input must be at least 2-d.")
if len(axes) != 2:
raise ValueError("len(axes) must be 2.")
if axes[0] == axes[1] or abs(axes[0] - axes[1]) == m_ndim:
raise ValueError("Axes must be different.")
if not (-m_ndim <= axes[0] < m_ndim and -m_ndim <= axes[1] < m_ndim):
raise ValueError(
f"Axes={axes} out of range for array of ndim={m_ndim}."
)
k %= 4
if k == 0:
return m[:]
if k == 2:
return dpnp.flip(dpnp.flip(m, axes[0]), axes[1])
axes_list = list(range(0, m_ndim))
(axes_list[axes[0]], axes_list[axes[1]]) = (
axes_list[axes[1]],
axes_list[axes[0]],
)
if k == 1:
return dpnp.transpose(dpnp.flip(m, axes[1]), axes_list)
# k == 3
return dpnp.flip(dpnp.transpose(m, axes_list), axes[1])
[docs]
def shape(a):
"""
Return the shape of an array.
For full documentation refer to :obj:`numpy.shape`.
Parameters
----------
a : array_like
Input array.
Returns
-------
shape : tuple of integers
The elements of the shape tuple give the lengths of the
corresponding array dimensions.
See Also
--------
len : ``len(a)`` is equivalent to ``np.shape(a)[0]`` for N-D arrays with
``N>=1``.
:obj:`dpnp.ndarray.shape` : Equivalent array method.
Examples
--------
>>> import dpnp as np
>>> np.shape(np.eye(3))
(3, 3)
>>> np.shape([[1, 3]])
(1, 2)
>>> np.shape([0])
(1,)
>>> np.shape(0)
()
"""
if dpnp.is_supported_array_type(a):
return a.shape
return numpy.shape(a)
[docs]
def size(a, axis=None):
"""
Return the number of elements along a given axis.
For full documentation refer to :obj:`numpy.size`.
Parameters
----------
a : array_like
Input data.
axis : {None, int}, optional
Axis along which the elements are counted.
By default, give the total number of elements.
Default: ``None``.
Returns
-------
element_count : int
Number of elements along the specified axis.
See Also
--------
:obj:`dpnp.ndarray.size` : number of elements in array.
:obj:`dpnp.shape` : Return the shape of an array.
:obj:`dpnp.ndarray.shape` : Return the shape of an array.
Examples
--------
>>> import dpnp as np
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> np.size(a)
6
>>> np.size(a, 1)
3
>>> np.size(a, 0)
2
>>> a = np.asarray(a)
>>> np.size(a)
6
>>> np.size(a, 1)
3
"""
if dpnp.is_supported_array_type(a):
if axis is None:
return a.size
return a.shape[axis]
return numpy.size(a, axis)
[docs]
def split(ary, indices_or_sections, axis=0):
"""
Split an array into multiple sub-arrays as views into `ary`.
For full documentation refer to :obj:`numpy.split`.
Parameters
----------
ary : {dpnp.ndarray, usm_ndarray}
Array to be divided into sub-arrays.
indices_or_sections : {int, sequence of ints}
If `indices_or_sections` is an integer, N, the array will be divided
into N equal arrays along `axis`. If such a split is not possible,
an error is raised.
If `indices_or_sections` is a sequence of sorted integers, the entries
indicate where along `axis` the array is split. For example,
``[2, 3]`` would, for ``axis=0``, result in
- ary[:2]
- ary[2:3]
- ary[3:]
If an index exceeds the dimension of the array along `axis`,
an empty sub-array is returned correspondingly.
axis : int, optional
The axis along which to split.
Default: ``0``.
Returns
-------
sub-arrays : list of dpnp.ndarray
A list of sub arrays. Each array is a view of the corresponding input
array.
Raises
------
ValueError
If `indices_or_sections` is given as an integer, but
a split does not result in equal division.
See Also
--------
:obj:`dpnp.array_split` : Split an array into multiple sub-arrays of equal
or near-equal size. Does not raise an exception if an
equal division cannot be made.
:obj:`dpnp.hsplit` : Split array into multiple sub-arrays horizontally
(column-wise).
:obj:`dpnp.vsplit` : Split array into multiple sub-arrays vertically
(row wise).
:obj:`dpnp.dsplit` : Split array into multiple sub-arrays along the 3rd
axis (depth).
:obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis.
:obj:`dpnp.stack` : Join a sequence of arrays along a new axis.
:obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise).
:obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise).
:obj:`dpnp.dstack` : Stack arrays in sequence depth wise
(along third dimension).
Examples
--------
>>> import dpnp as np
>>> x = np.arange(9.0)
>>> np.split(x, 3)
[array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7., 8.])]
>>> x = np.arange(8.0)
>>> np.split(x, [3, 5, 6, 10])
[array([0., 1., 2.]), array([3., 4.]), array([5.]), array([6., 7.]), \
array([])]
"""
dpnp.check_supported_arrays_type(ary)
if ary.ndim <= axis:
raise IndexError("Axis exceeds ndim")
try:
len(indices_or_sections)
except TypeError:
if ary.shape[axis] % indices_or_sections != 0:
raise ValueError(
"indices_or_sections must divide the size along the axes.\n"
"If you want to split the array into non-equally-sized "
"arrays, use array_split instead."
) from None
return array_split(ary, indices_or_sections, axis)
[docs]
def squeeze(a, /, axis=None):
"""
Removes singleton dimensions (axes) from array `a`.
For full documentation refer to :obj:`numpy.squeeze`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input data.
axis : None or int or tuple of ints, optional
Selects a subset of the entries of length one in the shape.
If an axis is selected with shape entry greater than one,
an error is raised.
Returns
-------
out : dpnp.ndarray
Output array is a view, if possible, and a copy otherwise, but with all
or a subset of the dimensions of length 1 removed. Output has the same
data type as the input, is allocated on the same device as the input
and has the same USM allocation type as the input array `a`.
Examples
--------
>>> import dpnp as np
>>> x = np.array([[[0], [1], [2]]])
>>> x.shape
(1, 3, 1)
>>> np.squeeze(x).shape
(3,)
>>> np.squeeze(x, axis=0).shape
(3, 1)
>>> np.squeeze(x, axis=1).shape
Traceback (most recent call last):
...
ValueError: Cannot select an axis to squeeze out which has size not equal
to one.
>>> np.squeeze(x, axis=2).shape
(1, 3)
"""
usm_a = dpnp.get_usm_ndarray(a)
usm_res = dpt.squeeze(usm_a, axis=axis)
return dpnp_array._create_from_usm_ndarray(usm_res)
[docs]
def stack(arrays, /, *, axis=0, out=None, dtype=None, casting="same_kind"):
"""
Join a sequence of arrays along a new axis.
For full documentation refer to :obj:`numpy.stack`.
Parameters
----------
arrays : {dpnp.ndarray, usm_ndarray}
Each array must have the same shape.
axis : int, optional
The axis in the result array along which the input arrays are stacked.
out : dpnp.ndarray, optional
If provided, the destination to place the result. The shape must be
correct, matching that of what stack would have returned if no out
argument were specified.
dtype : str or dtype
If provided, the destination array will have this dtype. Cannot be
provided together with `out`.
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
Controls what kind of data casting may occur. Defaults to 'same_kind'.
Returns
-------
out : dpnp.ndarray
The stacked array which has one more dimension than the input arrays.
See Also
--------
:obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis.
:obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise).
:obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise).
:obj:`dpnp.dstack` : Stack arrays in sequence depth wise
(along third dimension).
:obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array.
:obj:`dpnp.block` : Assemble an ndarray from nested lists of blocks.
:obj:`dpnp.split` : Split array into a list of multiple sub-arrays of equal
size.
:obj:`dpnp.unstack` : Split an array into a tuple of sub-arrays along
an axis.
Examples
--------
>>> import dpnp as np
>>> arrays = [np.random.randn(3, 4) for _ in range(10)]
>>> np.stack(arrays, axis=0).shape
(10, 3, 4)
>>> np.stack(arrays, axis=1).shape
(3, 10, 4)
>>> np.stack(arrays, axis=2).shape
(3, 4, 10)
>>> a = np.array([1, 2, 3])
>>> b = np.array([4, 5, 6])
>>> np.stack((a, b))
array([[1, 2, 3],
[4, 5, 6]])
>>> np.stack((a, b), axis=-1)
array([[1, 4],
[2, 5],
[3, 6]])
"""
_check_stack_arrays(arrays)
if dtype is not None and out is not None:
raise TypeError(
"stack() only takes `out` or `dtype` as an argument, "
"but both were provided."
)
usm_arrays = [dpnp.get_usm_ndarray(x) for x in arrays]
usm_res = dpt.stack(usm_arrays, axis=axis)
res = dpnp_array._create_from_usm_ndarray(usm_res)
if dtype is not None:
res = res.astype(dtype, casting=casting, copy=False)
elif out is not None:
dpnp.copyto(out, res, casting=casting)
return out
return res
[docs]
def swapaxes(a, axis1, axis2):
"""
Interchange two axes of an array.
For full documentation refer to :obj:`numpy.swapaxes`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input array.
axis1 : int
First axis.
axis2 : int
Second axis.
Returns
-------
out : dpnp.ndarray
An array with with swapped axes.
A view is returned whenever possible.
Notes
-----
If `a` has rank (i.e., number of dimensions) `N`,
a valid `axis` must be in the half-open interval `[-N, N)`.
Examples
--------
>>> import dpnp as np
>>> x = np.array([[1, 2, 3]])
>>> np.swapaxes(x, 0, 1)
array([[1],
[2],
[3]])
>>> x = np.array([[[0,1],[2,3]],[[4,5],[6,7]]])
>>> x
array([[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]])
>>> np.swapaxes(x,0,2)
array([[[0, 4],
[2, 6]],
[[1, 5],
[3, 7]]])
"""
usm_a = dpnp.get_usm_ndarray(a)
usm_res = dpt.swapaxes(usm_a, axis1=axis1, axis2=axis2)
return dpnp_array._create_from_usm_ndarray(usm_res)
# pylint: disable=invalid-name
[docs]
def tile(A, reps):
"""
Construct an array by repeating `A` the number of times given by reps.
If `reps` has length ``d``, the result will have dimension of
``max(d, A.ndim)``.
If ``A.ndim < d``, `A` is promoted to be d-dimensional by prepending new
axes. So a shape (3,) array is promoted to (1, 3) for 2-D replication,
or shape (1, 1, 3) for 3-D replication. If this is not the desired
behavior, promote `A` to d-dimensions manually before calling this
function.
If ``A.ndim > d``, `reps` is promoted to `A`.ndim by prepending 1's to it.
Thus for an `A` of shape (2, 3, 4, 5), a `reps` of (2, 2) is treated as
(1, 1, 2, 2).
Note : Although tile may be used for broadcasting, it is strongly
recommended to use dpnp's broadcasting operations and functions.
For full documentation refer to :obj:`numpy.tile`.
Parameters
----------
A : {dpnp.ndarray, usm_ndarray}
The input array.
reps : int or tuple of ints
The number of repetitions of `A` along each axis.
Returns
-------
out : dpnp.ndarray
The tiled output array.
See Also
--------
:obj:`dpnp.repeat` : Repeat elements of an array.
:obj:`dpnp.broadcast_to` : Broadcast an array to a new shape
Examples
--------
>>> import dpnp as np
>>> a = np.array([0, 1, 2])
>>> np.tile(a, 2)
array([0, 1, 2, 0, 1, 2])
>>> np.tile(a, (2, 2))
array([[0, 1, 2, 0, 1, 2],
[0, 1, 2, 0, 1, 2]])
>>> np.tile(a, (2, 1, 2))
array([[[0, 1, 2, 0, 1, 2]],
[[0, 1, 2, 0, 1, 2]]])
>>> b = np.array([[1, 2], [3, 4]])
>>> np.tile(b, 2)
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
>>> np.tile(b, (2, 1))
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
>>> c = np.array([1, 2, 3, 4])
>>> np.tile(c, (4, 1))
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
"""
usm_a = dpnp.get_usm_ndarray(A)
usm_res = dpt.tile(usm_a, reps)
return dpnp_array._create_from_usm_ndarray(usm_res)
[docs]
def transpose(a, axes=None):
"""
Returns an array with axes transposed.
Note that :obj:`dpnp.permute_dims` is an alias of :obj:`dpnp.transpose`.
For full documentation refer to :obj:`numpy.transpose`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input array.
axes : {None, tuple or list of ints}, optional
If specified, it must be a tuple or list which contains a permutation
of [0, 1, ..., N-1] where N is the number of axes of `a`.
The `i`'th axis of the returned array will correspond to the axis
numbered ``axes[i]`` of the input. If not specified or ``None``,
defaults to ``range(a.ndim)[::-1]``, which reverses the order of
the axes.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
`a` with its axes permuted. A view is returned whenever possible.
See Also
--------
:obj:`dpnp.ndarray.transpose` : Equivalent method.
:obj:`dpnp.moveaxis` : Move array axes to new positions.
:obj:`dpnp.argsort` : Returns the indices that would sort an array.
Examples
--------
>>> import dpnp as np
>>> a = np.array([[1, 2], [3, 4]])
>>> a
array([[1, 2],
[3, 4]])
>>> np.transpose(a)
array([[1, 3],
[2, 4]])
>>> a = np.array([1, 2, 3, 4])
>>> a
array([1, 2, 3, 4])
>>> np.transpose(a)
array([1, 2, 3, 4])
>>> a = np.ones((1, 2, 3))
>>> np.transpose(a, (1, 0, 2)).shape
(2, 1, 3)
>>> a = np.ones((2, 3, 4, 5))
>>> np.transpose(a).shape
(5, 4, 3, 2)
"""
dpnp.check_supported_arrays_type(a)
if isinstance(a, dpt.usm_ndarray):
a = dpnp_array._create_from_usm_ndarray(a)
if axes is None:
return a.transpose()
return a.transpose(*axes)
permute_dims = transpose # permute_dims is an alias for transpose
[docs]
def trim_zeros(filt, trim="fb", axis=None):
"""
Remove values along a dimension which are zero along all other.
For full documentation refer to :obj:`numpy.trim_zeros`.
Parameters
----------
filt : {dpnp.ndarray, usm_ndarray}
Input array.
trim : {"fb", "f", "b"}, optional
A string with `"f"` representing trim from front and `"b"` to trim from
back. By default, zeros are trimmed on both sides. Front and back refer
to the edges of a dimension, with "front" referring to the side with
the lowest index 0, and "back" referring to the highest index
(or index -1).
Default: ``"fb"``.
axis : {None, int}, optional
If ``None``, `filt` is cropped such, that the smallest bounding box is
returned that still contains all values which are not zero.
If an `axis` is specified, `filt` will be sliced in that dimension only
on the sides specified by `trim`. The remaining area will be the
smallest that still contains all values which are not zero.
Default: ``None``.
Returns
-------
out : dpnp.ndarray
The result of trimming the input. The number of dimensions and the
input data type are preserved.
Notes
-----
For all-zero arrays, the first axis is trimmed first.
Examples
--------
>>> import dpnp as np
>>> a = np.array((0, 0, 0, 1, 2, 3, 0, 2, 1, 0))
>>> np.trim_zeros(a)
array([1, 2, 3, 0, 2, 1])
>>> np.trim_zeros(a, trim='b')
array([0, 0, 0, 1, 2, 3, 0, 2, 1])
Multiple dimensions are supported:
>>> b = np.array([[0, 0, 2, 3, 0, 0],
... [0, 1, 0, 3, 0, 0],
... [0, 0, 0, 0, 0, 0]])
>>> np.trim_zeros(b)
array([[0, 2, 3],
[1, 0, 3]])
>>> np.trim_zeros(b, axis=-1)
array([[0, 2, 3],
[1, 0, 3],
[0, 0, 0]])
"""
dpnp.check_supported_arrays_type(filt)
if not isinstance(trim, str):
raise TypeError("only string trim is supported")
trim = trim.lower()
if trim not in ["fb", "bf", "f", "b"]:
raise ValueError(f"unexpected character(s) in `trim`: {trim!r}")
nd = filt.ndim
if axis is not None:
axis = normalize_axis_index(axis, nd)
if filt.size == 0:
return filt # no trailing zeros in empty array
non_zero = dpnp.argwhere(filt)
if non_zero.size == 0:
# `filt` has all zeros, so assign `start` and `stop` to the same value,
# then the resulting slice will be empty
start = stop = dpnp.zeros_like(filt, shape=nd, dtype=dpnp.intp)
else:
if "f" in trim:
start = non_zero.min(axis=0)
else:
start = (None,) * nd
if "b" in trim:
stop = non_zero.max(axis=0)
stop += 1 # Adjust for slicing
else:
stop = (None,) * nd
if axis is None:
# trim all axes
sl = tuple(slice(*x) for x in zip(start, stop))
else:
# only trim single axis
sl = (slice(None),) * axis + (slice(start[axis], stop[axis]),) + (...,)
return filt[sl]
[docs]
def unique(
ar,
return_index=False,
return_inverse=False,
return_counts=False,
axis=None,
*,
equal_nan=True,
):
"""
Find the unique elements of an array.
Returns the sorted unique elements of an array. There are three optional
outputs in addition to the unique elements:
* the indices of the input array that give the unique values
* the indices of the unique array that reconstruct the input array
* the number of times each unique value comes up in the input array
For full documentation refer to :obj:`numpy.unique`.
Parameters
----------
ar : {dpnp.ndarray, usm_ndarray}
Input array. Unless `axis` is specified, this will be flattened if it
is not already 1-D.
return_index : bool, optional
If ``True``, also return the indices of `ar` (along the specified axis,
if provided, or in the flattened array) that result in the unique array.
Default: ``False``.
return_inverse : bool, optional
If ``True``, also return the indices of the unique array (for the
specified axis, if provided) that can be used to reconstruct `ar`.
Default: ``False``.
return_counts : bool, optional
If ``True``, also return the number of times each unique item appears
in `ar`.
Default: ``False``.
axis : {int, None}, optional
The axis to operate on. If ``None``, `ar` will be flattened. If an
integer, the subarrays indexed by the given axis will be flattened and
treated as the elements of a 1-D array with the dimension of the given
axis, see the notes for more details.
Default: ``None``.
equal_nan : bool, optional
If ``True``, collapses multiple NaN values in the return array into one.
Default: ``True``.
Returns
-------
unique : dpnp.ndarray
The sorted unique values.
unique_indices : dpnp.ndarray, optional
The indices of the first occurrences of the unique values in the
original array. Only provided if `return_index` is ``True``.
unique_inverse : dpnp.ndarray, optional
The indices to reconstruct the original array from the unique array.
Only provided if `return_inverse` is ``True``.
unique_counts : dpnp.ndarray, optional
The number of times each of the unique values comes up in the original
array. Only provided if `return_counts` is ``True``.
See Also
--------
:obj:`dpnp.repeat` : Repeat elements of an array.
Notes
-----
When an axis is specified the subarrays indexed by the axis are sorted.
This is done by making the specified axis the first dimension of the array
(move the axis to the first dimension to keep the order of the other axes)
and then flattening the subarrays in C order.
For complex arrays all NaN values are considered equivalent (no matter
whether the NaN is in the real or imaginary part). As the representative for
the returned array the smallest one in the lexicographical order is chosen.
For multi-dimensional inputs, `unique_inverse` is reshaped such that the
input can be reconstructed using
``dpnp.take(unique, unique_inverse, axis=axis)``.
Examples
--------
>>> import dpnp as np
>>> a = np.array([1, 1, 2, 2, 3, 3])
>>> np.unique(a)
array([1, 2, 3])
>>> a = np.array([[1, 1], [2, 3]])
>>> np.unique(a)
array([1, 2, 3])
Return the unique rows of a 2D array
>>> a = np.array([[1, 0, 0], [1, 0, 0], [2, 3, 4]])
>>> np.unique(a, axis=0)
array([[1, 0, 0],
[2, 3, 4]])
Reconstruct the input array from the unique values and inverse:
>>> a = np.array([1, 2, 6, 4, 2, 3, 2])
>>> u, indices = np.unique(a, return_inverse=True)
>>> u
array([1, 2, 3, 4, 6])
>>> indices
array([0, 1, 4, 3, 1, 2, 1])
>>> u[indices]
array([1, 2, 6, 4, 2, 3, 2])
Reconstruct the input values from the unique values and counts:
>>> a = np.array([1, 2, 6, 4, 2, 3, 2])
>>> values, counts = np.unique(a, return_counts=True)
>>> values
array([1, 2, 3, 4, 6])
>>> counts
array([1, 3, 1, 1, 1])
>>> np.repeat(values, counts)
array([1, 2, 2, 2, 3, 4, 6]) # original order not preserved
"""
if axis is None:
return _unique_1d(
ar, return_index, return_inverse, return_counts, equal_nan
)
# axis was specified and not None
try:
ar = dpnp.moveaxis(ar, axis, 0)
except AxisError:
# this removes the "axis1" or "axis2" prefix from the error message
raise AxisError(axis, ar.ndim) from None
# reshape input array into a contiguous 2D array
orig_sh = ar.shape
ar = ar.reshape(orig_sh[0], math.prod(orig_sh[1:]))
ar = dpnp.ascontiguousarray(ar)
# build the indices for result array with unique values
sorted_indices = _unique_build_sort_indices(ar, orig_sh[0])
ar = ar[sorted_indices]
if ar.size > 0:
mask = dpnp.empty_like(ar, dtype=dpnp.bool)
mask[:1] = True
mask[1:] = ar[1:] != ar[:-1]
mask = mask.any(axis=1)
else:
# if the array is empty, then the mask should grab the first empty
# array as the unique one
mask = dpnp.ones_like(ar, shape=(ar.shape[0]), dtype=dpnp.bool)
mask[1:] = False
# index the input array with the unique elements and reshape it into the
# original size and dimension order
ar = ar[mask]
ar = ar.reshape(mask.sum().asnumpy(), *orig_sh[1:])
ar = dpnp.moveaxis(ar, 0, axis)
result = (ar,)
if return_index:
result += (sorted_indices[mask],)
if return_inverse:
imask = dpnp.cumsum(mask) - 1
inv_idx = dpnp.empty_like(mask, dtype=dpnp.intp)
inv_idx[sorted_indices] = imask
result += (inv_idx,)
if return_counts:
nonzero = dpnp.nonzero(mask)[0]
idx = dpnp.empty_like(
nonzero, shape=(nonzero.size + 1,), dtype=nonzero.dtype
)
idx[:-1] = nonzero
idx[-1] = mask.size
result += (idx[1:] - idx[:-1],)
return _unpack_tuple(result)
[docs]
def unstack(x, /, *, axis=0):
"""
Split an array into a sequence of arrays along the given axis.
The `axis` parameter specifies the dimension along which the array will
be split. For example, if ``axis=0`` (the default) it will be the first
dimension and if ``axis=-1`` it will be the last dimension.
The result is a tuple of arrays split along `axis`.
For full documentation refer to :obj:`numpy.unstack`.
Parameters
----------
x : {dpnp.ndarray, usm_ndarray}
The array to be unstacked.
axis : int, optional
Axis along which the array will be split.
Default: ``0``.
Returns
-------
unstacked : tuple of dpnp.ndarray
The unstacked arrays.
See Also
--------
:obj:`dpnp.stack` : Join a sequence of arrays along a new axis.
:obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis.
:obj:`dpnp.block` : Assemble an ndarray from nested lists of blocks.
:obj:`dpnp.split` : Split array into a list of multiple sub-arrays of equal
size.
Notes
-----
:obj:`dpnp.unstack` serves as the reverse operation of :obj:`dpnp.stack`,
i.e., ``dpnp.stack(dpnp.unstack(x, axis=axis), axis=axis) == x``.
This function is equivalent to ``tuple(dpnp.moveaxis(x, axis, 0))``, since
iterating on an array iterates along the first axis.
Examples
--------
>>> import dpnp as np
>>> arr = np.arange(24).reshape((2, 3, 4))
>>> np.unstack(arr)
(array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]),
array([[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]))
>>> np.unstack(arr, axis=1)
(array([[ 0, 1, 2, 3],
[12, 13, 14, 15]]),
array([[ 4, 5, 6, 7],
[16, 17, 18, 19]]),
array([[ 8, 9, 10, 11],
[20, 21, 22, 23]]))
>>> arr2 = np.stack(np.unstack(arr, axis=1), axis=1)
>>> arr2.shape
(2, 3, 4)
>>> np.all(arr == arr2)
array(True)
"""
usm_x = dpnp.get_usm_ndarray(x)
if usm_x.ndim == 0:
raise ValueError("Input array must be at least 1-d.")
res = dpt.unstack(usm_x, axis=axis)
return tuple(dpnp_array._create_from_usm_ndarray(a) for a in res)
[docs]
def vsplit(ary, indices_or_sections):
"""
Split an array into multiple sub-arrays vertically (row-wise).
Please refer to the :obj:`dpnp.split` documentation. ``vsplit``
is equivalent to ``split`` with ``axis=0`` (default), the array
is always split along the first axis regardless of the array dimension.
For full documentation refer to :obj:`numpy.vsplit`.
Parameters
----------
ary : {dpnp.ndarray, usm_ndarray}
Array to be divided into sub-arrays.
indices_or_sections : {int, sequence of ints}
If `indices_or_sections` is an integer, N, the array will be divided
into N equal arrays along the first axis. If such a split is not
possible, an error is raised.
If `indices_or_sections` is a sequence of sorted integers, the entries
indicate where along the first axis the array is split.
Returns
-------
sub-arrays : list of dpnp.ndarray
A list of sub arrays. Each array is a view of the corresponding input
array.
See Also
--------
:obj:`dpnp.split` : Split array into multiple sub-arrays of equal size.
Examples
--------
>>> import dpnp as np
>>> x = np.arange(16.0).reshape(4, 4)
>>> x
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]])
>>> np.vsplit(x, 2)
[array([[0., 1., 2., 3.],
[4., 5., 6., 7.]]),
array([[ 8., 9., 10., 11.],
[12., 13., 14., 15.]])]
>>> np.vsplit(x, np.array([3, 6]))
[array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]]),
array([[12., 13., 14., 15.]]),
array([], shape=(0, 4), dtype=float64)]
With a higher dimensional array the split is still along the first axis.
>>> x = np.arange(8.0).reshape(2, 2, 2)
>>> x
array([[[0., 1.],
[2., 3.]],
[[4., 5.],
[6., 7.]]])
>>> np.vsplit(x, 2)
[array([[[0., 1.],
[2., 3.]]]),
array([[[4., 5.],
[6., 7.]]])]
"""
dpnp.check_supported_arrays_type(ary)
if ary.ndim < 2:
raise ValueError("vsplit only works on arrays of 2 or more dimensions")
return split(ary, indices_or_sections, 0)
[docs]
def vstack(tup, *, dtype=None, casting="same_kind"):
"""
Stack arrays in sequence vertically (row wise).
:obj:`dpnp.row_stack` is an alias for :obj:`dpnp.vstack`.
They are the same function.
For full documentation refer to :obj:`numpy.vstack`.
Parameters
----------
tup : {dpnp.ndarray, usm_ndarray}
The arrays must have the same shape along all but the first axis.
1-D arrays must have the same length.
dtype : str or dtype
If provided, the destination array will have this dtype.
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
Controls what kind of data casting may occur. Defaults to 'same_kind'.
Returns
-------
out : dpnp.ndarray
The array formed by stacking the given arrays, will be at least 2-D.
See Also
--------
:obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis.
:obj:`dpnp.stack` : Join a sequence of arrays along a new axis.
:obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise).
:obj:`dpnp.dstack` : Stack arrays in sequence depth wise (along third axis).
:obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array.
:obj:`dpnp.block` : Assemble an ndarray from nested lists of blocks.
:obj:`dpnp.split` : Split array into a list of multiple sub-arrays of equal
size.
:obj:`dpnp.unstack` : Split an array into a tuple of sub-arrays along
an axis.
Examples
--------
>>> import dpnp as np
>>> a = np.array([1, 2, 3])
>>> b = np.array([4, 5, 6])
>>> np.vstack((a, b))
array([[1, 2, 3],
[4, 5, 6]])
>>> a = np.array([[1], [2], [3]])
>>> b = np.array([[4], [5], [6]])
>>> np.vstack((a, b))
array([[1],
[2],
[3],
[4],
[5],
[6]])
"""
_check_stack_arrays(tup)
arrs = dpnp.atleast_2d(*tup)
if not isinstance(arrs, list):
arrs = [arrs]
return dpnp.concatenate(arrs, axis=0, dtype=dtype, casting=casting)
row_stack = vstack