• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IntelPython / dpnp / 12062282928

28 Nov 2024 04:01AM UTC coverage: 66.72%. First build
12062282928

Pull #2203

github

web-flow
Merge 5963304ba into 6fc7166e2
Pull Request #2203: Correlation via fft implementation

4433 of 10384 branches covered (42.69%)

Branch coverage included in aggregate %.

52 of 56 new or added lines in 1 file covered. (92.86%)

16642 of 21203 relevant lines covered (78.49%)

20139.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.5
/dpnp/dpnp_iface_statistics.py
1
# -*- coding: utf-8 -*-
2
# *****************************************************************************
3
# Copyright (c) 2016-2024, Intel Corporation
4
# All rights reserved.
5
#
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions are met:
8
# - Redistributions of source code must retain the above copyright notice,
9
#   this list of conditions and the following disclaimer.
10
# - Redistributions in binary form must reproduce the above copyright notice,
11
#   this list of conditions and the following disclaimer in the documentation
12
#   and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24
# THE POSSIBILITY OF SUCH DAMAGE.
25
# *****************************************************************************
26

27
"""
28
Interface of the statistics function of the DPNP
29

30
Notes
31
-----
32
This module is a face or public interface file for the library
33
it contains:
34
 - Interface functions
35
 - documentation for the functions
36
 - The functions parameters check
37

38
"""
39

40
import math
1✔
41

42
import dpctl.tensor as dpt
1✔
43
import dpctl.utils as dpu
1✔
44
import numpy
1✔
45
from dpctl.tensor._numpy_helper import (
1✔
46
    normalize_axis_index,
47
    normalize_axis_tuple,
48
)
49

50
import dpnp
1✔
51

52
# pylint: disable=no-name-in-module
53
import dpnp.backend.extensions.statistics._statistics_impl as statistics_ext
1✔
54
from dpnp.dpnp_utils.dpnp_utils_common import (
1✔
55
    result_type_for_device,
56
    to_supported_dtypes,
57
)
58

59
from .dpnp_array import dpnp_array
1✔
60
from .dpnp_utils import call_origin, get_usm_allocations
1✔
61
from .dpnp_utils.dpnp_utils_reduction import dpnp_wrap_reduction_call
1✔
62
from .dpnp_utils.dpnp_utils_statistics import dpnp_cov
1✔
63

64
min_ = min  # pylint: disable=used-before-assignment
1✔
65

66
__all__ = [
1✔
67
    "amax",
68
    "amin",
69
    "average",
70
    "corrcoef",
71
    "correlate",
72
    "cov",
73
    "max",
74
    "mean",
75
    "median",
76
    "min",
77
    "ptp",
78
    "std",
79
    "var",
80
]
81

82

83
def _count_reduce_items(arr, axis, where=True):
1✔
84
    """
85
    Calculates the number of items used in a reduction operation
86
    along the specified axis or axes.
87

88
    Parameters
89
    ----------
90
    arr : {dpnp.ndarray, usm_ndarray}
91
        Input array.
92
    axis : {None, int, tuple of ints}, optional
93
        axis or axes along which the number of items used in a reduction
94
        operation must be counted. If a tuple of unique integers is given,
95
        the items are counted over multiple axes. If ``None``, the variance
96
        is computed over the entire array.
97
        Default: `None`.
98

99
    Returns
100
    -------
101
    out : int
102
        The number of items should be used in a reduction operation.
103

104
    Limitations
105
    -----------
106
    Parameters `where` is only supported with its default value.
107

108
    """
109
    if where is True:
1!
110
        # no boolean mask given, calculate items according to axis
111
        if axis is None:
1✔
112
            axis = tuple(range(arr.ndim))
1✔
113
        elif not isinstance(axis, tuple):
1✔
114
            axis = (axis,)
1✔
115
        items = 1
1✔
116
        for ax in axis:
1✔
117
            items *= arr.shape[normalize_axis_index(ax, arr.ndim)]
1✔
118
        items = dpnp.intp(items)
1✔
119
    else:
120
        raise NotImplementedError(
×
121
            "where keyword argument is only supported with its default value."
122
        )
123
    return items
1✔
124

125

126
def _flatten_array_along_axes(arr, axes_to_flatten):
1✔
127
    """Flatten an array along a specific set of axes."""
128

129
    axes_to_keep = (
1✔
130
        axis for axis in range(arr.ndim) if axis not in axes_to_flatten
131
    )
132

133
    # Move the axes_to_flatten to the front
134
    arr_moved = dpnp.moveaxis(arr, axes_to_flatten, range(len(axes_to_flatten)))
1✔
135

136
    new_shape = (-1,) + tuple(arr.shape[axis] for axis in axes_to_keep)
1✔
137
    flattened_arr = arr_moved.reshape(new_shape)
1✔
138

139
    return flattened_arr
1✔
140

141

142
def _get_comparison_res_dt(a, _dtype, _out):
1✔
143
    """Get a data type used by dpctl for result array in comparison function."""
144

145
    return a.dtype
1✔
146

147

148
def amax(a, axis=None, out=None, keepdims=False, initial=None, where=True):
1✔
149
    """
150
    Return the maximum of an array or maximum along an axis.
151

152
    `amax` is an alias of :obj:`dpnp.max`.
153

154
    See Also
155
    --------
156
    :obj:`dpnp.max` : alias of this function
157
    :obj:`dpnp.ndarray.max` : equivalent method
158

159
    """
160

161
    return max(
1✔
162
        a, axis=axis, out=out, keepdims=keepdims, initial=initial, where=where
163
    )
164

165

166
def amin(a, axis=None, out=None, keepdims=False, initial=None, where=True):
1✔
167
    """
168
    Return the minimum of an array or minimum along an axis.
169

170
    `amin` is an alias of :obj:`dpnp.min`.
171

172
    See Also
173
    --------
174
    :obj:`dpnp.min` : alias of this function
175
    :obj:`dpnp.ndarray.min` : equivalent method
176

177
    """
178

179
    return min(
1✔
180
        a, axis=axis, out=out, keepdims=keepdims, initial=initial, where=where
181
    )
182

183

184
def average(a, axis=None, weights=None, returned=False, *, keepdims=False):
1✔
185
    """
186
    Compute the weighted average along the specified axis.
187

188
    For full documentation refer to :obj:`numpy.average`.
189

190
    Parameters
191
    ----------
192
    a : {dpnp.ndarray, usm_ndarray}
193
        Input array.
194
    axis : {None, int, tuple of ints}, optional
195
        Axis or axes along which the averages must be computed. If
196
        a tuple of unique integers, the averages are computed over multiple
197
        axes. If ``None``, the average is computed over the entire array.
198
        Default: ``None``.
199
    weights : {array_like}, optional
200
        An array of weights associated with the values in `a`. Each value in
201
        `a` contributes to the average according to its associated weight.
202
        The weights array can either be 1-D (in which case its length must be
203
        the size of `a` along the given axis) or of the same shape as `a`.
204
        If `weights=None`, then all data in `a` are assumed to have a
205
        weight equal to one.  The 1-D calculation is::
206

207
            avg = sum(a * weights) / sum(weights)
208

209
        The only constraint on `weights` is that `sum(weights)` must not be 0.
210
    returned : {bool}, optional
211
        If ``True``, the tuple (`average`, `sum_of_weights`) is returned,
212
        otherwise only the average is returned. If `weights=None`,
213
        `sum_of_weights` is equivalent to the number of elements over which
214
        the average is taken.
215
        Default: ``False``.
216
    keepdims : {None, bool}, optional
217
        If ``True``, the reduced axes (dimensions) are included in the result
218
        as singleton dimensions, so that the returned array remains
219
        compatible with the input array according to Array Broadcasting
220
        rules. Otherwise, if ``False``, the reduced axes are not included in
221
        the returned array.
222
        Default: ``False``.
223

224
    Returns
225
    -------
226
    out, [sum_of_weights] : dpnp.ndarray, dpnp.ndarray
227
        Return the average along the specified axis. When `returned` is
228
        ``True``, return a tuple with the average as the first element and
229
        the sum of the weights as the second element. `sum_of_weights` is of
230
        the same type as `out`. The result dtype follows a general pattern.
231
        If `weights` is ``None``, the result dtype will be that of `a` , or
232
        default floating point data type for the device where input array `a`
233
        is allocated. Otherwise, if `weights` is not ``None`` and `a` is
234
        non-integral, the result type will be the type of lowest precision
235
        capable of representing values of both `a` and `weights`. If `a`
236
        happens to be integral, the previous rules still applies but the result
237
        dtype will at least be default floating point data type for the device
238
        where input array `a` is allocated.
239

240
    See Also
241
    --------
242
    :obj:`dpnp.mean` : Compute the arithmetic mean along the specified axis.
243
    :obj:`dpnp.sum` : Sum of array elements over a given axis.
244

245
    Examples
246
    --------
247
    >>> import dpnp as np
248
    >>> data = np.arange(1, 5)
249
    >>> data
250
    array([1, 2, 3, 4])
251
    >>> np.average(data)
252
    array(2.5)
253
    >>> np.average(np.arange(1, 11), weights=np.arange(10, 0, -1))
254
    array(4.0)
255

256
    >>> data = np.arange(6).reshape((3, 2))
257
    >>> data
258
    array([[0, 1],
259
        [2, 3],
260
        [4, 5]])
261
    >>> np.average(data, axis=1, weights=[1./4, 3./4])
262
    array([0.75, 2.75, 4.75])
263
    >>> np.average(data, weights=[1./4, 3./4])
264
    TypeError: Axis must be specified when shapes of a and weights differ.
265

266
    With ``keepdims=True``, the following result has shape (3, 1).
267

268
    >>> np.average(data, axis=1, keepdims=True)
269
    array([[0.5],
270
        [2.5],
271
        [4.5]])
272

273
    >>> a = np.ones(5, dtype=np.float64)
274
    >>> w = np.ones(5, dtype=np.complex64)
275
    >>> avg = np.average(a, weights=w)
276
    >>> print(avg.dtype)
277
    complex128
278

279
    """
280

281
    dpnp.check_supported_arrays_type(a)
1✔
282
    usm_type, exec_q = get_usm_allocations([a, weights])
1✔
283

284
    if weights is None:
1✔
285
        avg = dpnp.mean(a, axis=axis, keepdims=keepdims)
1✔
286
        scl = dpnp.asanyarray(
1✔
287
            avg.dtype.type(a.size / avg.size),
288
            usm_type=usm_type,
289
            sycl_queue=exec_q,
290
        )
291
    else:
292
        if not dpnp.is_supported_array_type(weights):
1✔
293
            weights = dpnp.asarray(
1✔
294
                weights, usm_type=usm_type, sycl_queue=exec_q
295
            )
296

297
        a_dtype = a.dtype
1✔
298
        if not dpnp.issubdtype(a_dtype, dpnp.inexact):
1✔
299
            default_dtype = dpnp.default_float_type(a.device)
1✔
300
            res_dtype = dpnp.result_type(a_dtype, weights.dtype, default_dtype)
1✔
301
        else:
302
            res_dtype = dpnp.result_type(a_dtype, weights.dtype)
1✔
303

304
        # Sanity checks
305
        wgt_shape = weights.shape
1✔
306
        a_shape = a.shape
1✔
307
        if a_shape != wgt_shape:
1✔
308
            if axis is None:
1✔
309
                raise TypeError(
1✔
310
                    "Axis must be specified when shapes of input array and "
311
                    "weights differ."
312
                )
313
            if weights.ndim != 1:
1✔
314
                raise TypeError(
1✔
315
                    "1D weights expected when shapes of input array and "
316
                    "weights differ."
317
                )
318
            if wgt_shape[0] != a_shape[axis]:
1✔
319
                raise ValueError(
1✔
320
                    "Length of weights not compatible with specified axis."
321
                )
322

323
            # setup weights to broadcast along axis
324
            weights = dpnp.broadcast_to(
1✔
325
                weights, (a.ndim - 1) * (1,) + wgt_shape
326
            )
327
            weights = weights.swapaxes(-1, axis)
1✔
328

329
        scl = weights.sum(axis=axis, dtype=res_dtype, keepdims=keepdims)
1✔
330
        if dpnp.any(scl == 0.0):
1✔
331
            raise ZeroDivisionError("Weights sum to zero, can't be normalized")
1✔
332

333
        avg = dpnp.multiply(a, weights).sum(
1✔
334
            axis=axis, dtype=res_dtype, keepdims=keepdims
335
        )
336
        avg /= scl
1✔
337

338
    if returned:
1✔
339
        if scl.shape != avg.shape:
1✔
340
            scl = dpnp.broadcast_to(scl, avg.shape).copy()
1✔
341
        return avg, scl
1✔
342
    return avg
1✔
343

344

345
def corrcoef(x, y=None, rowvar=True, *, dtype=None):
1✔
346
    """
347
    Return Pearson product-moment correlation coefficients.
348

349
    For full documentation refer to :obj:`numpy.corrcoef`.
350

351
    Parameters
352
    ----------
353
    x : {dpnp.ndarray, usm_ndarray}
354
        A 1-D or 2-D array containing multiple variables and observations.
355
        Each row of `x` represents a variable, and each column a single
356
        observation of all those variables. Also see `rowvar` below.
357
    y : {None, dpnp.ndarray, usm_ndarray}, optional
358
        An additional set of variables and observations. `y` has the same
359
        shape as `x`.
360
        Default: ``None``.
361
    rowvar : {bool}, optional
362
        If `rowvar` is ``True``, then each row represents a variable,
363
        with observations in the columns. Otherwise, the relationship
364
        is transposed: each column represents a variable, while the rows
365
        contain observations.
366
        Default: ``True``.
367
    dtype : {None, dtype}, optional
368
        Data-type of the result.
369
        Default: ``None``.
370

371
    Returns
372
    -------
373
    R : {dpnp.ndarray}
374
        The correlation coefficient matrix of the variables.
375

376
    See Also
377
    --------
378
    :obj:`dpnp.cov` : Covariance matrix.
379

380
    Examples
381
    --------
382
    In this example we generate two random arrays, ``xarr`` and ``yarr``, and
383
    compute the row-wise and column-wise Pearson correlation coefficients,
384
    ``R``. Since `rowvar` is true by default, we first find the row-wise
385
    Pearson correlation coefficients between the variables of ``xarr``.
386

387
    >>> import dpnp as np
388
    >>> np.random.seed(123)
389
    >>> xarr = np.random.rand(3, 3).astype(np.float32)
390
    >>> xarr
391
    array([[7.2858386e-17, 2.2066992e-02, 3.9520904e-01],
392
           [4.8012391e-01, 5.9377134e-01, 4.5147297e-01],
393
           [9.0728188e-01, 9.9387854e-01, 5.8399546e-01]], dtype=float32)
394
    >>> R1 = np.corrcoef(xarr)
395
    >>> R1
396
    array([[ 0.99999994, -0.6173796 , -0.9685411 ],
397
           [-0.6173796 ,  1.        ,  0.7937219 ],
398
           [-0.9685411 ,  0.7937219 ,  0.9999999 ]], dtype=float32)
399

400
    If we add another set of variables and observations ``yarr``, we can
401
    compute the row-wise Pearson correlation coefficients between the
402
    variables in ``xarr`` and ``yarr``.
403

404
    >>> yarr = np.random.rand(3, 3).astype(np.float32)
405
    >>> yarr
406
    array([[0.17615308, 0.65354985, 0.15716429],
407
           [0.09373496, 0.2123185 , 0.84086883],
408
           [0.9011005 , 0.45206687, 0.00225109]], dtype=float32)
409
    >>> R2 = np.corrcoef(xarr, yarr)
410
    >>> R2
411
    array([[ 0.99999994, -0.6173796 , -0.968541  , -0.48613155,  0.9951523 ,
412
            -0.8900264 ],
413
           [-0.6173796 ,  1.        ,  0.7937219 ,  0.9875833 , -0.53702235,
414
             0.19083664],
415
           [-0.968541  ,  0.7937219 ,  0.9999999 ,  0.6883078 , -0.9393724 ,
416
             0.74857277],
417
           [-0.48613152,  0.9875833 ,  0.6883078 ,  0.9999999 , -0.39783284,
418
             0.0342579 ],
419
           [ 0.9951523 , -0.53702235, -0.9393725 , -0.39783284,  0.99999994,
420
            -0.9305482 ],
421
           [-0.89002645,  0.19083665,  0.7485727 ,  0.0342579 , -0.9305482 ,
422
             1.        ]], dtype=float32)
423

424
    Finally if we use the option ``rowvar=False``, the columns are now
425
    being treated as the variables and we will find the column-wise Pearson
426
    correlation coefficients between variables in ``xarr`` and ``yarr``.
427

428
    >>> R3 = np.corrcoef(xarr, yarr, rowvar=False)
429
    >>> R3
430
    array([[ 1.        ,  0.9724453 , -0.9909503 ,  0.8104691 , -0.46436927,
431
            -0.1643624 ],
432
           [ 0.9724453 ,  1.        , -0.9949381 ,  0.6515728 , -0.6580445 ,
433
             0.07012729],
434
           [-0.99095035, -0.994938  ,  1.        , -0.72450536,  0.5790461 ,
435
             0.03047091],
436
           [ 0.8104691 ,  0.65157276, -0.72450536,  1.        ,  0.14243561,
437
            -0.71102554],
438
           [-0.4643693 , -0.6580445 ,  0.57904613,  0.1424356 ,  0.99999994,
439
            -0.79727215],
440
           [-0.1643624 ,  0.07012729,  0.03047091, -0.7110255 , -0.7972722 ,
441
             0.99999994]], dtype=float32)
442
    """
443

444
    out = dpnp.cov(x, y, rowvar, dtype=dtype)
1✔
445
    if out.ndim == 0:
1✔
446
        # scalar covariance
447
        # nan if incorrect value (nan, inf, 0), 1 otherwise
448
        return out / out
1✔
449

450
    d = dpnp.diag(out)
1✔
451

452
    stddev = dpnp.sqrt(d.real)
1✔
453
    out /= stddev[:, None]
1✔
454
    out /= stddev[None, :]
1✔
455

456
    # Clip real and imaginary parts to [-1, 1]. This does not guarantee
457
    # abs(a[i,j]) <= 1 for complex arrays, but is the best we can do without
458
    # excessive work.
459
    dpnp.clip(out.real, -1, 1, out=out.real)
1✔
460
    if dpnp.iscomplexobj(out):
1✔
461
        dpnp.clip(out.imag, -1, 1, out=out.imag)
1✔
462

463
    return out
1✔
464

465

466
def _get_padding(a_size, v_size, mode):
1✔
467
    if v_size > a_size:
1!
468
        a_size, v_size = v_size, a_size
×
469

470
    if mode == "valid":
1✔
471
        l_pad, r_pad = 0, 0
1✔
472
    elif mode == "same":
1✔
473
        l_pad = v_size // 2
1✔
474
        r_pad = v_size - l_pad - 1
1✔
475
    elif mode == "full":
1✔
476
        l_pad, r_pad = v_size - 1, v_size - 1
1✔
477
    else:
478
        raise ValueError(
1✔
479
            f"Unknown mode: {mode}. Only 'valid', 'same', 'full' are supported."
480
        )
481

482
    return l_pad, r_pad
1✔
483

484

485
def _choose_conv_method(a, v, rdtype):
1✔
486
    assert a.size >= v.size
1✔
487
    if rdtype == dpnp.bool:
1✔
488
        return "direct"
1✔
489

490
    if v.size < 10**4 or a.size < 10**4:
1✔
491
        return "direct"
1✔
492

493
    if dpnp.issubdtype(rdtype, dpnp.integer):
1✔
494
        max_a = int(dpnp.max(dpnp.abs(a)))
1✔
495
        sum_v = int(dpnp.sum(dpnp.abs(v)))
1✔
496
        max_value = int(max_a * sum_v)
1✔
497

498
        default_float = dpnp.default_float_type(a.sycl_device)
1✔
499
        if max_value > 2 ** numpy.finfo(default_float).nmant - 1:
1!
NEW
500
            return "direct"
×
501

502
    if dpnp.issubdtype(rdtype, dpnp.number):
1!
503
        return "fft"
1✔
504

NEW
505
    raise ValueError(f"Unsupported dtype: {rdtype}")
×
506

507

508
def _run_native_sliding_dot_product1d(a, v, l_pad, r_pad, rdtype):
1✔
509
    queue = a.sycl_queue
1✔
510
    device = a.sycl_device
1✔
511

512
    supported_types = statistics_ext.sliding_dot_product1d_dtypes()
1✔
513
    supported_dtype = to_supported_dtypes(rdtype, supported_types, device)
1✔
514

515
    if supported_dtype is None:
1!
NEW
516
        raise ValueError(
×
517
            f"Unsupported input types ({a.dtype}, {v.dtype}), "
518
            "and the inputs could not be coerced to any "
519
            f"supported types. List of supported types: {supported_types}"
520
        )
521

522
    a_casted = dpnp.asarray(a, dtype=supported_dtype, order="C")
1✔
523
    v_casted = dpnp.asarray(v, dtype=supported_dtype, order="C")
1✔
524

525
    usm_type = dpu.get_coerced_usm_type([a_casted.usm_type, v_casted.usm_type])
1✔
526
    out_size = l_pad + r_pad + a_casted.size - v_casted.size + 1
1✔
527
    out = dpnp.empty(
1✔
528
        shape=out_size,
529
        sycl_queue=queue,
530
        dtype=supported_dtype,
531
        usm_type=usm_type,
532
    )
533

534
    a_usm = dpnp.get_usm_ndarray(a_casted)
1✔
535
    v_usm = dpnp.get_usm_ndarray(v_casted)
1✔
536
    out_usm = dpnp.get_usm_ndarray(out)
1✔
537

538
    _manager = dpu.SequentialOrderManager[queue]
1✔
539

540
    mem_ev, corr_ev = statistics_ext.sliding_dot_product1d(
1✔
541
        a_usm,
542
        v_usm,
543
        out_usm,
544
        l_pad,
545
        r_pad,
546
        depends=_manager.submitted_events,
547
    )
548
    _manager.add_event_pair(mem_ev, corr_ev)
1✔
549

550
    return out
1✔
551

552

553
def _convolve_fft(a, v, l_pad, r_pad, rtype):
1✔
554
    assert a.size >= v.size
1✔
555
    assert l_pad < v.size
1✔
556

557
    # +1 is needed to avoid circular convolution
558
    padded_size = a.size + r_pad + 1
1✔
559
    fft_size = 2 ** math.ceil(math.log2(padded_size))
1✔
560

561
    af = dpnp.fft.fft(a, fft_size)  # pylint: disable=no-member
1✔
562
    vf = dpnp.fft.fft(v, fft_size)  # pylint: disable=no-member
1✔
563

564
    r = dpnp.fft.ifft(af * vf)  # pylint: disable=no-member
1✔
565
    if dpnp.issubdtype(rtype, dpnp.floating):
1✔
566
        r = r.real
1✔
567
    elif dpnp.issubdtype(rtype, dpnp.integer) or rtype == dpnp.bool:
1✔
568
        r = r.real.round()
1✔
569

570
    start = v.size - 1 - l_pad
1✔
571
    end = padded_size - 1
1✔
572

573
    return r[start:end]
1✔
574

575

576
def correlate(a, v, mode="valid", method="auto"):
1✔
577
    r"""
578
    Cross-correlation of two 1-dimensional sequences.
579

580
    This function computes the correlation as generally defined in signal
581
    processing texts [1]:
582

583
    .. math:: c_k = \sum_n a_{n+k} \cdot \overline{v}_n
584

585
    with a and v sequences being zero-padded where necessary and
586
    :math:`\overline v` denoting complex conjugation.
587

588
    For full documentation refer to :obj:`numpy.correlate`.
589

590
    Parameters
591
    ----------
592
    a : {dpnp.ndarray, usm_ndarray}
593
        First input array.
594
    v : {dpnp.ndarray, usm_ndarray}
595
        Second input array.
596
    mode : {'valid', 'same', 'full'}, optional
597
        Refer to the :obj:`dpnp.convolve` docstring. Note that the default
598
        is ``'valid'``, unlike :obj:`dpnp.convolve`, which uses ``'full'``.
599

600
        Default: ``'valid'``.
601
    method : {'auto', 'direct', 'fft'}, optional
602
        `'direct'`: The correlation is determined directly from sums.
603

604
        `'fft'`: The Fourier Transform is used to perform the calculations.
605
        This method is faster for long sequences but can have accuracy issues.
606

607
        `'auto'`: Automatically chooses direct or Fourier method based on
608
        an estimate of which is faster.
609

610
        Note: Use of the FFT convolution on input containing NAN or INF
611
        will lead to the entire output being NAN or INF.
612
        Use method='direct' when your input contains NAN or INF values.
613

614
        Default: ``'auto'``.
615

616
    Notes
617
    -----
618
    The definition of correlation above is not unique and sometimes
619
    correlation may be defined differently. Another common definition is [1]:
620

621
    .. math:: c'_k = \sum_n a_{n} \cdot \overline{v_{n+k}}
622

623
    which is related to :math:`c_k` by :math:`c'_k = c_{-k}`.
624

625
    References
626
    ----------
627
    .. [1] Wikipedia, "Cross-correlation",
628
           https://en.wikipedia.org/wiki/Cross-correlation
629

630
    Returns
631
    -------
632
    out : {dpnp.ndarray}
633
        Discrete cross-correlation of `a` and `v`.
634

635
    See Also
636
    --------
637
    :obj:`dpnp.convolve` : Discrete, linear convolution of two
638
    one-dimensional sequences.
639

640
    Examples
641
    --------
642
    >>> import dpnp as np
643
    >>> a = np.array([1, 2, 3], dtype=np.float32)
644
    >>> v = np.array([0, 1, 0.5], dtype=np.float32)
645
    >>> np.correlate(a, v)
646
    array([3.5], dtype=float32)
647
    >>> np.correlate(a, v, "same")
648
    array([2. , 3.5, 3. ], dtype=float32)
649
    >>> np.correlate([1, 2, 3], [0, 1, 0.5], "full")
650
    array([0.5, 2. , 3.5, 3. , 0. ], dtype=float32)
651

652
    Using complex sequences:
653

654
    >>> ac = np.array([1+1j, 2, 3-1j], dtype=np.complex64)
655
    >>> vc = np.array([0, 1, 0.5j], dtype=np.complex64)
656
    >>> np.correlate(ac, vc, 'full')
657
    array([0.5-0.5j, 1. +0.j , 1.5-1.5j, 3. -1.j , 0. +0.j ], dtype=complex64)
658

659
    Note that you get the time reversed, complex conjugated result
660
    (:math:`\overline{c_{-k}}`) when the two input sequences a and v change
661
    places:
662

663
    >>> np.correlate([0, 1, 0.5j], [1+1j, 2, 3-1j], 'full')
664
    array([0. +0.j , 3. +1.j , 1.5+1.5j, 1. +0.j , 0.5+0.5j], dtype=complex64)
665

666
    """
667

668
    dpnp.check_supported_arrays_type(a, v)
1✔
669

670
    if a.size == 0 or v.size == 0:
1✔
671
        raise ValueError(
1✔
672
            f"Array arguments cannot be empty. "
673
            f"Received sizes: a.size={a.size}, v.size={v.size}"
674
        )
675
    if a.ndim != 1 or v.ndim != 1:
1✔
676
        raise ValueError(
1✔
677
            f"Only 1-dimensional arrays are supported. "
678
            f"Received shapes: a.shape={a.shape}, v.shape={v.shape}"
679
        )
680

681
    supported_methods = ["auto", "direct", "fft"]
1✔
682
    if method not in supported_methods:
1✔
683
        raise ValueError(
1✔
684
            f"Unknown method: {method}. Supported methods: {supported_methods}"
685
        )
686

687
    device = a.sycl_device
1✔
688
    rdtype = result_type_for_device([a.dtype, v.dtype], device)
1✔
689

690
    if dpnp.issubdtype(v.dtype, dpnp.complexfloating):
1✔
691
        v = dpnp.conj(v)
1✔
692

693
    revert = False
1✔
694
    if v.size > a.size:
1✔
695
        revert = True
1✔
696
        a, v = v, a
1✔
697

698
    l_pad, r_pad = _get_padding(a.size, v.size, mode)
1✔
699

700
    if method == "auto":
1✔
701
        method = _choose_conv_method(a, v, rdtype)
1✔
702

703
    if method == "direct":
1✔
704
        r = _run_native_sliding_dot_product1d(a, v, l_pad, r_pad, rdtype)
1✔
705
    elif method == "fft":
1!
706
        r = _convolve_fft(a, v[::-1], l_pad, r_pad, rdtype)
1✔
707
    else:
NEW
708
        raise ValueError(f"Unknown method: {method}")
×
709

710
    if revert:
1✔
711
        r = r[::-1]
1✔
712

713
    return dpnp.asarray(r, dtype=rdtype, order="C")
1✔
714

715

716
def cov(
1✔
717
    m,
718
    y=None,
719
    rowvar=True,
720
    bias=False,
721
    ddof=None,
722
    fweights=None,
723
    aweights=None,
724
    *,
725
    dtype=None,
726
):
727
    """
728
    Estimate a covariance matrix, given data and weights.
729

730
    For full documentation refer to :obj:`numpy.cov`.
731

732
    Returns
733
    -------
734
    out : dpnp.ndarray
735
        The covariance matrix of the variables.
736

737
    Limitations
738
    -----------
739
    Input array ``m`` is supported as :obj:`dpnp.ndarray`.
740
    Dimension of input array ``m`` is limited by ``m.ndim <= 2``.
741
    Size and shape of input arrays are supported to be equal.
742
    Parameter `y` is supported only with default value ``None``.
743
    Parameter `bias` is supported only with default value ``False``.
744
    Parameter `ddof` is supported only with default value ``None``.
745
    Parameter `fweights` is supported only with default value ``None``.
746
    Parameter `aweights` is supported only with default value ``None``.
747
    Otherwise the function will be executed sequentially on CPU.
748
    Input array data types are limited by supported DPNP :ref:`Data types`.
749

750
    See Also
751
    --------
752
    :obj:`dpnp.corrcoef` : Normalized covariance matrix
753

754
    Examples
755
    --------
756
    >>> import dpnp as np
757
    >>> x = np.array([[0, 2], [1, 1], [2, 0]]).T
758
    >>> x.shape
759
    (2, 3)
760
    >>> [i for i in x]
761
    [0, 1, 2, 2, 1, 0]
762
    >>> out = np.cov(x)
763
    >>> out.shape
764
    (2, 2)
765
    >>> [i for i in out]
766
    [1.0, -1.0, -1.0, 1.0]
767

768
    """
769

770
    if not dpnp.is_supported_array_type(m):
1!
771
        pass
×
772
    elif m.ndim > 2:
1✔
773
        pass
1✔
774
    elif bias:
1✔
775
        pass
1✔
776
    elif ddof is not None:
1✔
777
        pass
1✔
778
    elif fweights is not None:
1!
779
        pass
×
780
    elif aweights is not None:
1!
781
        pass
×
782
    else:
783
        return dpnp_cov(m, y=y, rowvar=rowvar, dtype=dtype)
1✔
784

785
    return call_origin(
1✔
786
        numpy.cov, m, y, rowvar, bias, ddof, fweights, aweights, dtype=dtype
787
    )
788

789

790
def max(a, axis=None, out=None, keepdims=False, initial=None, where=True):
1✔
791
    """
792
    Return the maximum of an array or maximum along an axis.
793

794
    For full documentation refer to :obj:`numpy.max`.
795

796
    Parameters
797
    ----------
798
    a : {dpnp.ndarray, usm_ndarray}
799
        Input array.
800
    axis : {None, int or tuple of ints}, optional
801
        Axis or axes along which to operate. By default, flattened input is
802
        used. If this is a tuple of integers, the minimum is selected over
803
        multiple axes, instead of a single axis or all the axes as before.
804
        Default: ``None``.
805
    out : {None, dpnp.ndarray, usm_ndarray}, optional
806
        Alternative output array in which to place the result. Must be of the
807
        same shape and buffer length as the expected output.
808
        Default: ``None``.
809
    keepdims : {None, bool}, optional
810
        If this is set to ``True``, the axes which are reduced are left in the
811
        result as dimensions with size one. With this option, the result will
812
        broadcast correctly against the input array.
813
        Default: ``False``.
814

815
    Returns
816
    -------
817
    out : dpnp.ndarray
818
        Maximum of `a`. If `axis` is ``None``, the result is a zero-dimensional
819
        array. If `axis` is an integer, the result is an array of dimension
820
        ``a.ndim - 1``. If `axis` is a tuple, the result is an array of
821
        dimension ``a.ndim - len(axis)``.
822

823
    Limitations
824
    -----------.
825
    Parameters `where`, and `initial` are only supported with their default
826
    values. Otherwise ``NotImplementedError`` exception will be raised.
827

828
    See Also
829
    --------
830
    :obj:`dpnp.min` : Return the minimum of an array.
831
    :obj:`dpnp.maximum` : Element-wise maximum of two arrays, propagates NaNs.
832
    :obj:`dpnp.fmax` : Element-wise maximum of two arrays, ignores NaNs.
833
    :obj:`dpnp.amax` : The maximum value of an array along a given axis,
834
                       propagates NaNs.
835
    :obj:`dpnp.nanmax` : The maximum value of an array along a given axis,
836
                         ignores NaNs.
837

838
    Examples
839
    --------
840
    >>> import dpnp as np
841
    >>> a = np.arange(4).reshape((2,2))
842
    >>> a
843
    array([[0, 1],
844
           [2, 3]])
845
    >>> np.max(a)
846
    array(3)
847

848
    >>> np.max(a, axis=0)   # Maxima along the first axis
849
    array([2, 3])
850
    >>> np.max(a, axis=1)   # Maxima along the second axis
851
    array([1, 3])
852

853
    >>> b = np.arange(5, dtype=float)
854
    >>> b[2] = np.nan
855
    >>> np.max(b)
856
    array(nan)
857

858
    """
859

860
    dpnp.check_limitations(initial=initial, where=where)
1✔
861
    usm_a = dpnp.get_usm_ndarray(a)
1✔
862

863
    return dpnp_wrap_reduction_call(
1✔
864
        a,
865
        out,
866
        dpt.max,
867
        _get_comparison_res_dt,
868
        usm_a,
869
        axis=axis,
870
        keepdims=keepdims,
871
    )
872

873

874
def mean(a, /, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
1✔
875
    """
876
    Compute the arithmetic mean along the specified axis.
877

878
    For full documentation refer to :obj:`numpy.mean`.
879

880
    Parameters
881
    ----------
882
    a : {dpnp.ndarray, usm_ndarray}
883
        Input array.
884
    axis : {None, int, tuple of ints}, optional
885
        Axis or axes along which the arithmetic means must be computed. If
886
        a tuple of unique integers, the means are computed over multiple
887
        axes. If ``None``, the mean is computed over the entire array.
888
        Default: ``None``.
889
    dtype : {None, dtype}, optional
890
        Type to use in computing the mean. By default, if `a` has a
891
        floating-point data type, the returned array will have
892
        the same data type as `a`.
893
        If `a` has a boolean or integral data type, the returned array
894
        will have the default floating point data type for the device
895
        where input array `a` is allocated.
896
    out : {None, dpnp.ndarray, usm_ndarray}, optional
897
        Alternative output array in which to place the result. It must have
898
        the same shape as the expected output but the type (of the calculated
899
        values) will be cast if necessary.
900
        Default: ``None``.
901
    keepdims : {None, bool}, optional
902
        If ``True``, the reduced axes (dimensions) are included in the result
903
        as singleton dimensions, so that the returned array remains
904
        compatible with the input array according to Array Broadcasting
905
        rules. Otherwise, if ``False``, the reduced axes are not included in
906
        the returned array.
907
        Default: ``False``.
908

909
    Returns
910
    -------
911
    out : dpnp.ndarray
912
        An array containing the arithmetic means along the specified axis(axes).
913
        If the input is a zero-size array, an array containing NaN values is
914
        returned.
915

916
    Limitations
917
    -----------
918
    Parameter `where` is only supported with its default value.
919
    Otherwise ``NotImplementedError`` exception will be raised.
920

921
    See Also
922
    --------
923
    :obj:`dpnp.average` : Weighted average.
924
    :obj:`dpnp.std` : Compute the standard deviation along the specified axis.
925
    :obj:`dpnp.var` : Compute the variance along the specified axis.
926
    :obj:`dpnp.nanmean` : Compute the arithmetic mean along the specified axis,
927
                          ignoring NaNs.
928
    :obj:`dpnp.nanstd` : Compute the standard deviation along
929
                         the specified axis, while ignoring NaNs.
930
    :obj:`dpnp.nanvar` : Compute the variance along the specified axis,
931
                         while ignoring NaNs.
932

933
    Examples
934
    --------
935
    >>> import dpnp as np
936
    >>> a = np.array([[1, 2], [3, 4]])
937
    >>> np.mean(a)
938
    array(2.5)
939
    >>> np.mean(a, axis=0)
940
    array([2., 3.])
941
    >>> np.mean(a, axis=1)
942
    array([1.5, 3.5])
943

944
    """
945

946
    dpnp.check_limitations(where=where)
1✔
947

948
    usm_a = dpnp.get_usm_ndarray(a)
1✔
949
    usm_res = dpt.mean(usm_a, axis=axis, keepdims=keepdims)
1✔
950
    if dtype is not None:
1✔
951
        usm_res = dpt.astype(usm_res, dtype)
1✔
952

953
    return dpnp.get_result_array(usm_res, out, casting="unsafe")
1✔
954

955

956
def median(a, axis=None, out=None, overwrite_input=False, keepdims=False):
1✔
957
    """
958
    Compute the median along the specified axis.
959

960
    For full documentation refer to :obj:`numpy.median`.
961

962
    Parameters
963
    ----------
964
    a : {dpnp.ndarray, usm_ndarray}
965
        Input array.
966
    axis : {None, int, tuple or list of ints}, optional
967
        Axis or axes along which the medians are computed. The default,
968
        ``axis=None``, will compute the median along a flattened version of
969
        the array. If a sequence of axes, the array is first flattened along
970
        the given axes, then the median is computed along the resulting
971
        flattened axis.
972
        Default: ``None``.
973
    out : {None, dpnp.ndarray, usm_ndarray}, optional
974
        Alternative output array in which to place the result. It must have
975
        the same shape as the expected output but the type (of the calculated
976
        values) will be cast if necessary.
977
        Default: ``None``.
978
    overwrite_input : bool, optional
979
       If ``True``, then allow use of memory of input array `a` for
980
       calculations. The input array will be modified by the call to
981
       :obj:`dpnp.median`. This will save memory when you do not need to
982
       preserve the contents of the input array. Treat the input as undefined,
983
       but it will probably be fully or partially sorted.
984
       Default: ``False``.
985
    keepdims : {None, bool}, optional
986
        If ``True``, the reduced axes (dimensions) are included in the result
987
        as singleton dimensions, so that the returned array remains
988
        compatible with the input array according to Array Broadcasting
989
        rules. Otherwise, if ``False``, the reduced axes are not included in
990
        the returned array.
991
        Default: ``False``.
992

993
    Returns
994
    -------
995
    dpnp.median : dpnp.ndarray
996
        A new array holding the result. If `a` has a floating-point data type,
997
        the returned array will have the same data type as `a`. If `a` has a
998
        boolean or integral data type, the returned array will have the
999
        default floating point data type for the device where input array `a`
1000
        is allocated.
1001

1002
    See Also
1003
    --------
1004
    :obj:`dpnp.mean` : Compute the arithmetic mean along the specified axis.
1005
    :obj:`dpnp.percentile` : Compute the q-th percentile of the data
1006
                             along the specified axis.
1007

1008
    Notes
1009
    -----
1010
    Given a vector ``V`` of length ``N``, the median of ``V`` is the
1011
    middle value of a sorted copy of ``V``, ``V_sorted`` - i.e.,
1012
    ``V_sorted[(N-1)/2]``, when ``N`` is odd, and the average of the
1013
    two middle values of ``V_sorted`` when ``N`` is even.
1014

1015
    Examples
1016
    --------
1017
    >>> import dpnp as np
1018
    >>> a = np.array([[10, 7, 4], [3, 2, 1]])
1019
    >>> a
1020
    array([[10,  7,  4],
1021
           [ 3,  2,  1]])
1022
    >>> np.median(a)
1023
    array(3.5)
1024

1025
    >>> np.median(a, axis=0)
1026
    array([6.5, 4.5, 2.5])
1027
    >>> np.median(a, axis=1)
1028
    array([7.,  2.])
1029
    >>> np.median(a, axis=(0, 1))
1030
    array(3.5)
1031

1032
    >>> m = np.median(a, axis=0)
1033
    >>> out = np.zeros_like(m)
1034
    >>> np.median(a, axis=0, out=m)
1035
    array([6.5,  4.5,  2.5])
1036
    >>> m
1037
    array([6.5,  4.5,  2.5])
1038

1039
    >>> b = a.copy()
1040
    >>> np.median(b, axis=1, overwrite_input=True)
1041
    array([7.,  2.])
1042
    >>> assert not np.all(a==b)
1043
    >>> b = a.copy()
1044
    >>> np.median(b, axis=None, overwrite_input=True)
1045
    array(3.5)
1046
    >>> assert not np.all(a==b)
1047

1048
    """
1049

1050
    dpnp.check_supported_arrays_type(a)
1✔
1051
    a_ndim = a.ndim
1✔
1052
    a_shape = a.shape
1✔
1053
    _axis = range(a_ndim) if axis is None else axis
1✔
1054
    _axis = normalize_axis_tuple(_axis, a_ndim)
1✔
1055

1056
    if isinstance(axis, (tuple, list)):
1✔
1057
        if len(axis) == 1:
1✔
1058
            axis = axis[0]
1✔
1059
        else:
1060
            # Need to flatten if `axis` is a sequence of axes since `dpnp.sort`
1061
            # only accepts integer `axis`
1062
            # Note that the output of _flatten_array_along_axes is not
1063
            # necessarily a view of the input since `reshape` is used there.
1064
            # If this is the case, using overwrite_input is meaningless
1065
            a = _flatten_array_along_axes(a, _axis)
1✔
1066
            axis = 0
1✔
1067

1068
    if overwrite_input:
1✔
1069
        if axis is None:
1✔
1070
            a_sorted = dpnp.ravel(a)
1✔
1071
            a_sorted.sort()
1✔
1072
        else:
1073
            if isinstance(a, dpt.usm_ndarray):
1✔
1074
                # dpnp.ndarray.sort only works with dpnp_array
1075
                a = dpnp_array._create_from_usm_ndarray(a)
1✔
1076
            a.sort(axis=axis)
1✔
1077
            a_sorted = a
1✔
1078
    else:
1079
        a_sorted = dpnp.sort(a, axis=axis)
1✔
1080

1081
    if axis is None:
1✔
1082
        axis = 0
1✔
1083
    indexer = [slice(None)] * a_sorted.ndim
1✔
1084
    index, remainder = divmod(a_sorted.shape[axis], 2)
1✔
1085
    if remainder == 1:
1✔
1086
        # index with slice to allow mean (below) to work
1087
        indexer[axis] = slice(index, index + 1)
1✔
1088
    else:
1089
        indexer[axis] = slice(index - 1, index + 1)
1✔
1090

1091
    # Use `mean` in odd and even case to coerce data type and use `out` array
1092
    res = dpnp.mean(a_sorted[tuple(indexer)], axis=axis, out=out)
1✔
1093
    nan_mask = dpnp.isnan(a_sorted).any(axis=axis)
1✔
1094
    if nan_mask.any():
1✔
1095
        res[nan_mask] = dpnp.nan
1✔
1096

1097
    if keepdims:
1✔
1098
        # We can't use dpnp.mean(..., keepdims) and dpnp.any(..., keepdims)
1099
        # above because of the reshape hack might have been used in
1100
        # `_flatten_array_along_axes` to handle cases when axis is a tuple.
1101
        res_shape = list(a_shape)
1✔
1102
        for i in _axis:
1✔
1103
            res_shape[i] = 1
1✔
1104
        res = res.reshape(tuple(res_shape))
1✔
1105

1106
    return res
1✔
1107

1108

1109
def min(a, axis=None, out=None, keepdims=False, initial=None, where=True):
1✔
1110
    """
1111
    Return the minimum of an array or maximum along an axis.
1112

1113
    For full documentation refer to :obj:`numpy.min`.
1114

1115
    Parameters
1116
    ----------
1117
    a : {dpnp.ndarray, usm_ndarray}
1118
        Input array.
1119
    axis : {None, int or tuple of ints}, optional
1120
        Axis or axes along which to operate. By default, flattened input is
1121
        used. If this is a tuple of integers, the minimum is selected over
1122
        multiple axes, instead of a single axis or all the axes as before.
1123
        Default: ``None``.
1124
    out : {None, dpnp.ndarray, usm_ndarray}, optional
1125
        Alternative output array in which to place the result. Must be of the
1126
        same shape and buffer length as the expected output.
1127
        Default: ``None``.
1128
    keepdims : {None, bool}, optional
1129
        If this is set to ``True``, the axes which are reduced are left in the
1130
        result as dimensions with size one. With this option, the result will
1131
        broadcast correctly against the input array.
1132
        Default: ``False``.
1133

1134
    Returns
1135
    -------
1136
    out : dpnp.ndarray
1137
        Minimum of `a`. If `axis` is ``None``, the result is a zero-dimensional
1138
        array. If `axis` is an integer, the result is an array of dimension
1139
        ``a.ndim - 1``. If `axis` is a tuple, the result is an array of
1140
        dimension ``a.ndim - len(axis)``.
1141

1142
    Limitations
1143
    -----------
1144
    Parameters `where`, and `initial` are only supported with their default
1145
    values. Otherwise ``NotImplementedError`` exception will be raised.
1146

1147
    See Also
1148
    --------
1149
    :obj:`dpnp.max` : Return the maximum of an array.
1150
    :obj:`dpnp.minimum` : Element-wise minimum of two arrays, propagates NaNs.
1151
    :obj:`dpnp.fmin` : Element-wise minimum of two arrays, ignores NaNs.
1152
    :obj:`dpnp.amin` : The minimum value of an array along a given axis,
1153
                       propagates NaNs.
1154
    :obj:`dpnp.nanmin` : The minimum value of an array along a given axis,
1155
                         ignores NaNs.
1156

1157
    Examples
1158
    --------
1159
    >>> import dpnp as np
1160
    >>> a = np.arange(4).reshape((2,2))
1161
    >>> a
1162
    array([[0, 1],
1163
           [2, 3]])
1164
    >>> np.min(a)
1165
    array(0)
1166

1167
    >>> np.min(a, axis=0)   # Minima along the first axis
1168
    array([0, 1])
1169
    >>> np.min(a, axis=1)   # Minima along the second axis
1170
    array([0, 2])
1171

1172
    >>> b = np.arange(5, dtype=float)
1173
    >>> b[2] = np.nan
1174
    >>> np.min(b)
1175
    array(nan)
1176

1177
    """
1178

1179
    dpnp.check_limitations(initial=initial, where=where)
1✔
1180
    usm_a = dpnp.get_usm_ndarray(a)
1✔
1181

1182
    return dpnp_wrap_reduction_call(
1✔
1183
        a,
1184
        out,
1185
        dpt.min,
1186
        _get_comparison_res_dt,
1187
        usm_a,
1188
        axis=axis,
1189
        keepdims=keepdims,
1190
    )
1191

1192

1193
def ptp(
1✔
1194
    a,
1195
    /,
1196
    axis=None,
1197
    out=None,
1198
    keepdims=False,
1199
):
1200
    """
1201
    Range of values (maximum - minimum) along an axis.
1202

1203
    For full documentation refer to :obj:`numpy.ptp`.
1204

1205
    Returns
1206
    -------
1207
    ptp : dpnp.ndarray
1208
        The range of a given array.
1209

1210
    Limitations
1211
    -----------
1212
    Input array is supported as :class:`dpnp.dpnp.ndarray` or
1213
    :class:`dpctl.tensor.usm_ndarray`.
1214

1215
    Examples
1216
    --------
1217
    >>> import dpnp as np
1218
    >>> x = np.array([[4, 9, 2, 10],[6, 9, 7, 12]])
1219
    >>> np.ptp(x, axis=1)
1220
    array([8, 6])
1221

1222
    >>> np.ptp(x, axis=0)
1223
    array([2, 0, 5, 2])
1224

1225
    >>> np.ptp(x)
1226
    array(10)
1227

1228
    """
1229

1230
    return dpnp.subtract(
1✔
1231
        dpnp.max(a, axis=axis, keepdims=keepdims, out=out),
1232
        dpnp.min(a, axis=axis, keepdims=keepdims),
1233
        out=out,
1234
    )
1235

1236

1237
def std(
1✔
1238
    a, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True
1239
):
1240
    """
1241
    Compute the standard deviation along the specified axis.
1242

1243
    For full documentation refer to :obj:`numpy.std`.
1244

1245
    Parameters
1246
    ----------
1247
    a : {dpnp.ndarray, usm_ndarray}
1248
        Input array.
1249
    axis : {None, int, tuple of ints}, optional
1250
        Axis or axes along which the standard deviations must be computed.
1251
        If a tuple of unique integers is given, the standard deviations
1252
        are computed over multiple axes. If ``None``, the standard deviation
1253
        is computed over the entire array.
1254
        Default: ``None``.
1255
    dtype : {None, dtype}, optional
1256
        Type to use in computing the standard deviation. By default,
1257
        if `a` has a floating-point data type, the returned array
1258
        will have the same data type as `a`.
1259
        If `a` has a boolean or integral data type, the returned array
1260
        will have the default floating point data type for the device
1261
        where input array `a` is allocated.
1262
    out : {None, dpnp.ndarray, usm_ndarray}, optional
1263
        Alternative output array in which to place the result. It must have
1264
        the same shape as the expected output but the type (of the calculated
1265
        values) will be cast if necessary.
1266
    ddof : {int, float}, optional
1267
        Means Delta Degrees of Freedom.  The divisor used in calculations
1268
        is ``N - ddof``, where ``N`` corresponds to the total
1269
        number of elements over which the standard deviation is calculated.
1270
        Default: `0.0`.
1271
    keepdims : {None, bool}, optional
1272
        If ``True``, the reduced axes (dimensions) are included in the result
1273
        as singleton dimensions, so that the returned array remains
1274
        compatible with the input array according to Array Broadcasting
1275
        rules. Otherwise, if ``False``, the reduced axes are not included in
1276
        the returned array. Default: ``False``.
1277

1278
    Returns
1279
    -------
1280
    out : dpnp.ndarray
1281
        An array containing the standard deviations. If the standard
1282
        deviation was computed over the entire array, a zero-dimensional
1283
        array is returned.
1284

1285
    Limitations
1286
    -----------
1287
    Parameters `where` is only supported with its default value.
1288
    Otherwise ``NotImplementedError`` exception will be raised.
1289

1290
    Notes
1291
    -----
1292
    Note that, for complex numbers, the absolute value is taken before squaring,
1293
    so that the result is always real and non-negative.
1294

1295
    See Also
1296
    --------
1297
    :obj:`dpnp.ndarray.std` : corresponding function for ndarrays.
1298
    :obj:`dpnp.var` : Compute the variance along the specified axis.
1299
    :obj:`dpnp.mean` : Compute the arithmetic mean along the specified axis.
1300
    :obj:`dpnp.nanmean` : Compute the arithmetic mean along the specified axis,
1301
                          ignoring NaNs.
1302
    :obj:`dpnp.nanstd` : Compute the standard deviation along
1303
                         the specified axis, while ignoring NaNs.
1304
    :obj:`dpnp.nanvar` : Compute the variance along the specified axis,
1305
                         while ignoring NaNs.
1306

1307
    Examples
1308
    --------
1309
    >>> import dpnp as np
1310
    >>> a = np.array([[1, 2], [3, 4]])
1311
    >>> np.std(a)
1312
    array(1.118033988749895)
1313
    >>> np.std(a, axis=0)
1314
    array([1.,  1.])
1315
    >>> np.std(a, axis=1)
1316
    array([0.5,  0.5])
1317

1318
    """
1319

1320
    dpnp.check_supported_arrays_type(a)
1✔
1321
    dpnp.check_limitations(where=where)
1✔
1322

1323
    if not isinstance(ddof, (int, float)):
1✔
1324
        raise TypeError(
1✔
1325
            f"An integer or float is required, but got {type(ddof)}"
1326
        )
1327

1328
    if dpnp.issubdtype(a.dtype, dpnp.complexfloating):
1✔
1329
        result = dpnp.var(
1✔
1330
            a,
1331
            axis=axis,
1332
            dtype=None,
1333
            out=out,
1334
            ddof=ddof,
1335
            keepdims=keepdims,
1336
            where=where,
1337
        )
1338
        dpnp.sqrt(result, out=result)
1✔
1339
    else:
1340
        usm_a = dpnp.get_usm_ndarray(a)
1✔
1341
        usm_res = dpt.std(usm_a, axis=axis, correction=ddof, keepdims=keepdims)
1✔
1342
        result = dpnp.get_result_array(usm_res, out)
1✔
1343

1344
    if dtype is not None and out is None:
1✔
1345
        result = result.astype(dtype, casting="same_kind")
1✔
1346
    return result
1✔
1347

1348

1349
def var(
1✔
1350
    a, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True
1351
):
1352
    """
1353
    Compute the variance along the specified axis.
1354

1355
    For full documentation refer to :obj:`numpy.var`.
1356

1357
    Parameters
1358
    ----------
1359
    a : {dpnp.ndarray, usm_ndarray}
1360
        Input array.
1361
    axis : {None, int, tuple of ints}, optional
1362
        axis or axes along which the variances must be computed. If a tuple
1363
        of unique integers is given, the variances are computed over multiple
1364
        axes. If ``None``, the variance is computed over the entire array.
1365
        Default: ``None``.
1366
    dtype : {None, dtype}, optional
1367
        Type to use in computing the variance. By default, if `a` has a
1368
        floating-point data type, the returned array will have
1369
        the same data type as `a`.
1370
        If `a` has a boolean or integral data type, the returned array
1371
        will have the default floating point data type for the device
1372
        where input array `a` is allocated.
1373
    out : {None, dpnp.ndarray, usm_ndarray}, optional
1374
        Alternative output array in which to place the result. It must have
1375
        the same shape as the expected output but the type (of the calculated
1376
        values) will be cast if necessary.
1377
    ddof : {int, float}, optional
1378
        Means Delta Degrees of Freedom.  The divisor used in calculations
1379
        is ``N - ddof``, where ``N`` corresponds to the total
1380
        number of elements over which the variance is calculated.
1381
        Default: `0.0`.
1382
    keepdims : {None, bool}, optional
1383
        If ``True``, the reduced axes (dimensions) are included in the result
1384
        as singleton dimensions, so that the returned array remains
1385
        compatible with the input array according to Array Broadcasting
1386
        rules. Otherwise, if ``False``, the reduced axes are not included in
1387
        the returned array. Default: ``False``.
1388

1389
    Returns
1390
    -------
1391
    out : dpnp.ndarray
1392
        An array containing the variances. If the variance was computed
1393
        over the entire array, a zero-dimensional array is returned.
1394

1395
    Limitations
1396
    -----------
1397
    Parameters `where` is only supported with its default value.
1398
    Otherwise ``NotImplementedError`` exception will be raised.
1399

1400
    Notes
1401
    -----
1402
    Note that, for complex numbers, the absolute value is taken before squaring,
1403
    so that the result is always real and non-negative.
1404

1405
    See Also
1406
    --------
1407
    :obj:`dpnp.ndarray.var` : corresponding function for ndarrays.
1408
    :obj:`dpnp.std` : Compute the standard deviation along the specified axis.
1409
    :obj:`dpnp.mean` : Compute the arithmetic mean along the specified axis.
1410
    :obj:`dpnp.nanmean` : Compute the arithmetic mean along the specified axis,
1411
                          ignoring NaNs.
1412
    :obj:`dpnp.nanstd` : Compute the standard deviation along
1413
                         the specified axis, while ignoring NaNs.
1414
    :obj:`dpnp.nanvar` : Compute the variance along the specified axis,
1415
                         while ignoring NaNs.
1416

1417
    Examples
1418
    --------
1419
    >>> import dpnp as np
1420
    >>> a = np.array([[1, 2], [3, 4]])
1421
    >>> np.var(a)
1422
    array(1.25)
1423
    >>> np.var(a, axis=0)
1424
    array([1.,  1.])
1425
    >>> np.var(a, axis=1)
1426
    array([0.25,  0.25])
1427

1428
    """
1429

1430
    dpnp.check_supported_arrays_type(a)
1✔
1431
    dpnp.check_limitations(where=where)
1✔
1432

1433
    if not isinstance(ddof, (int, float)):
1✔
1434
        raise TypeError(
1✔
1435
            f"An integer or float is required, but got {type(ddof)}"
1436
        )
1437

1438
    if dpnp.issubdtype(a.dtype, dpnp.complexfloating):
1✔
1439
        # Note that if dtype is not of inexact type then arrmean
1440
        # will not be either.
1441
        arrmean = dpnp.mean(
1✔
1442
            a, axis=axis, dtype=dtype, keepdims=True, where=where
1443
        )
1444
        x = dpnp.subtract(a, arrmean)
1✔
1445
        x = dpnp.multiply(x, x.conj(), out=x).real
1✔
1446
        result = dpnp.sum(
1✔
1447
            x,
1448
            axis=axis,
1449
            dtype=a.real.dtype,
1450
            out=out,
1451
            keepdims=keepdims,
1452
            where=where,
1453
        )
1454

1455
        cnt = _count_reduce_items(a, axis, where)
1✔
1456
        cnt = numpy.max(cnt - ddof, 0).astype(result.dtype, casting="same_kind")
1✔
1457
        if not cnt:
1✔
1458
            cnt = dpnp.nan
1✔
1459

1460
        dpnp.divide(result, cnt, out=result)
1✔
1461
    else:
1462
        usm_a = dpnp.get_usm_ndarray(a)
1✔
1463
        usm_res = dpt.var(usm_a, axis=axis, correction=ddof, keepdims=keepdims)
1✔
1464
        result = dpnp.get_result_array(usm_res, out)
1✔
1465

1466
    if out is None and dtype is not None:
1✔
1467
        result = result.astype(dtype, casting="same_kind")
1✔
1468
    return result
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc