|
62 | 62 | "amax",
|
63 | 63 | "amin",
|
64 | 64 | "average",
|
| 65 | + "convolve", |
65 | 66 | "corrcoef",
|
66 | 67 | "correlate",
|
67 | 68 | "cov",
|
@@ -357,6 +358,138 @@ def average(a, axis=None, weights=None, returned=False, *, keepdims=False):
|
357 | 358 | return avg
|
358 | 359 |
|
359 | 360 |
|
| 361 | +def _convolve_impl(a, v, mode, method, rdtype): |
| 362 | + l_pad, r_pad = _get_padding(a.size, v.size, mode) |
| 363 | + |
| 364 | + if method == "auto": |
| 365 | + method = _choose_conv_method(a, v, rdtype) |
| 366 | + |
| 367 | + if method == "direct": |
| 368 | + r = _run_native_sliding_dot_product1d(a, v[::-1], l_pad, r_pad, rdtype) |
| 369 | + elif method == "fft": |
| 370 | + r = _convolve_fft(a, v, l_pad, r_pad, rdtype) |
| 371 | + else: |
| 372 | + raise ValueError( |
| 373 | + f"Unknown method: {method}. Supported methods: auto, direct, fft" |
| 374 | + ) |
| 375 | + |
| 376 | + return r |
| 377 | + |
| 378 | + |
| 379 | +def convolve(a, v, mode="full", method="auto"): |
| 380 | + r""" |
| 381 | + Returns the discrete, linear convolution of two one-dimensional sequences. |
| 382 | + The convolution operator is often seen in signal processing, where it |
| 383 | + models the effect of a linear time-invariant system on a signal [1]_. In |
| 384 | + probability theory, the sum of two independent random variables is |
| 385 | + distributed according to the convolution of their individual |
| 386 | + distributions. |
| 387 | + If `v` is longer than `a`, the arrays are swapped before computation. |
| 388 | + For full documentation refer to :obj:`numpy.convolve`. |
| 389 | + Parameters |
| 390 | + ---------- |
| 391 | + a : {dpnp.ndarray, usm_ndarray} |
| 392 | + First 1-D array. |
| 393 | + v : {dpnp.ndarray, usm_ndarray} |
| 394 | + Second 1-D array. The length of `v` must be less than or equal to |
| 395 | + the length of `a`. |
| 396 | + mode : {'full', 'valid', 'same'}, optional |
| 397 | + 'full': |
| 398 | + By default, mode is 'full'. This returns the convolution |
| 399 | + at each point of overlap, with an output shape of (N+M-1,). At |
| 400 | + the end-points of the convolution, the signals do not overlap |
| 401 | + completely, and boundary effects may be seen. |
| 402 | + 'same': |
| 403 | + Mode 'same' returns output of length ``max(M, N)``. Boundary |
| 404 | + effects are still visible. |
| 405 | + 'valid': |
| 406 | + Mode 'valid' returns output of length |
| 407 | + ``max(M, N) - min(M, N) + 1``. The convolution product is only given |
| 408 | + for points where the signals overlap completely. Values outside |
| 409 | + the signal boundary have no effect. |
| 410 | + method : {'auto', 'direct', 'fft'}, optional |
| 411 | + 'direct': |
| 412 | + The convolution is determined directly from sums. |
| 413 | + 'fft': |
| 414 | + The Fourier Transform is used to perform the calculations. |
| 415 | + This method is faster for long sequences but can have accuracy issues. |
| 416 | + 'auto': |
| 417 | + Automatically chooses direct or Fourier method based on |
| 418 | + an estimate of which is faster. |
| 419 | + Note: Use of the FFT convolution on input containing NAN or INF |
| 420 | + will lead to the entire output being NAN or INF. |
| 421 | + Use method='direct' when your input contains NAN or INF values. |
| 422 | + Default: ``'auto'``. |
| 423 | + Returns |
| 424 | + ------- |
| 425 | + out : ndarray |
| 426 | + Discrete, linear convolution of `a` and `v`. |
| 427 | + See Also |
| 428 | + -------- |
| 429 | + :obj:`dpnp.correlate` : Cross-correlation of two 1-dimensional sequences. |
| 430 | + Notes |
| 431 | + ----- |
| 432 | + The discrete convolution operation is defined as |
| 433 | + .. math:: (a * v)_n = \\sum_{m = -\\infty}^{\\infty} a_m v_{n - m} |
| 434 | + It can be shown that a convolution :math:`x(t) * y(t)` in time/space |
| 435 | + is equivalent to the multiplication :math:`X(f) Y(f)` in the Fourier |
| 436 | + domain, after appropriate padding (padding is necessary to prevent |
| 437 | + circular convolution). Since multiplication is more efficient (faster) |
| 438 | + than convolution, the function implements two approaches - direct and fft |
| 439 | + which are regulated by the keyword `method`. |
| 440 | + References |
| 441 | + ---------- |
| 442 | + .. [1] Wikipedia, "Convolution", |
| 443 | + https://en.wikipedia.org/wiki/Convolution |
| 444 | + Examples |
| 445 | + -------- |
| 446 | + Note how the convolution operator flips the second array |
| 447 | + before "sliding" the two across one another: |
| 448 | + >>> import dpnp as np |
| 449 | + >>> a = np.array([1, 2, 3], dtype=np.float32) |
| 450 | + >>> v = np.array([0, 1, 0.5], dtype=np.float32) |
| 451 | + >>> np.convolve(a, v) |
| 452 | + array([0. , 1. , 2.5, 4. , 1.5], dtype=float32) |
| 453 | + Only return the middle values of the convolution. |
| 454 | + Contains boundary effects, where zeros are taken |
| 455 | + into account: |
| 456 | + >>> np.convolve(a, v, 'same') |
| 457 | + array([1. , 2.5, 4. ], dtype=float32) |
| 458 | + The two arrays are of the same length, so there |
| 459 | + is only one position where they completely overlap: |
| 460 | + >>> np.convolve(a, v, 'valid') |
| 461 | + array([2.5], dtype=float32) |
| 462 | + """ |
| 463 | + |
| 464 | + dpnp.check_supported_arrays_type(a, v) |
| 465 | + |
| 466 | + if a.size == 0 or v.size == 0: |
| 467 | + raise ValueError( |
| 468 | + f"Array arguments cannot be empty. " |
| 469 | + f"Received sizes: a.size={a.size}, v.size={v.size}" |
| 470 | + ) |
| 471 | + if a.ndim > 1 or v.ndim > 1: |
| 472 | + raise ValueError( |
| 473 | + f"Only 1-dimensional arrays are supported. " |
| 474 | + f"Received shapes: a.shape={a.shape}, v.shape={v.shape}" |
| 475 | + ) |
| 476 | + |
| 477 | + if a.ndim == 0: |
| 478 | + a = dpnp.reshape(a, (1,)) |
| 479 | + if v.ndim == 0: |
| 480 | + v = dpnp.reshape(v, (1,)) |
| 481 | + |
| 482 | + device = a.sycl_device |
| 483 | + rdtype = result_type_for_device([a.dtype, v.dtype], device) |
| 484 | + |
| 485 | + if v.size > a.size: |
| 486 | + a, v = v, a |
| 487 | + |
| 488 | + r = _convolve_impl(a, v, mode, method, rdtype) |
| 489 | + |
| 490 | + return dpnp.asarray(r, dtype=rdtype, order="C") |
| 491 | + |
| 492 | + |
360 | 493 | def corrcoef(x, y=None, rowvar=True, *, dtype=None):
|
361 | 494 | """
|
362 | 495 | Return Pearson product-moment correlation coefficients.
|
@@ -714,24 +847,13 @@ def correlate(a, v, mode="valid", method="auto"):
|
714 | 847 | revert = True
|
715 | 848 | a, v = v, a
|
716 | 849 |
|
717 |
| - l_pad, r_pad = _get_padding(a.size, v.size, mode) |
718 |
| - |
719 |
| - if method == "auto": |
720 |
| - method = _choose_conv_method(a, v, rdtype) |
721 |
| - |
722 |
| - if method == "direct": |
723 |
| - r = _run_native_sliding_dot_product1d(a, v, l_pad, r_pad, rdtype) |
724 |
| - elif method == "fft": |
725 |
| - r = _convolve_fft(a, v[::-1], l_pad, r_pad, rdtype) |
726 |
| - else: # pragma: no cover |
727 |
| - raise ValueError(f"Unknown method: {method}") |
| 850 | + r = _convolve_impl(a, v[::-1], mode, method, rdtype) |
728 | 851 |
|
729 | 852 | if revert:
|
730 | 853 | r = r[::-1]
|
731 | 854 |
|
732 | 855 | return dpnp.asarray(r, dtype=rdtype, order="C")
|
733 | 856 |
|
734 |
| - |
735 | 857 | def cov(
|
736 | 858 | m,
|
737 | 859 | y=None,
|
|
0 commit comments