Skip to content

Commit 3a03fdc

Browse files
Rebase on master
1 parent 2956a29 commit 3a03fdc

6 files changed

+294
-60
lines changed

dpnp/dpnp_iface_mathematical.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@
9090
"clip",
9191
"conj",
9292
"conjugate",
93-
"convolve",
9493
"copysign",
9594
"cross",
9695
"cumprod",
@@ -791,24 +790,6 @@ def clip(a, /, min=None, max=None, *, out=None, order="K", **kwargs):
791790

792791
conj = conjugate
793792

794-
795-
def convolve(a, v, mode="full"):
796-
"""
797-
Returns the discrete, linear convolution of two one-dimensional sequences.
798-
799-
For full documentation refer to :obj:`numpy.convolve`.
800-
801-
Examples
802-
--------
803-
>>> ca = dpnp.convolve([1, 2, 3], [0, 1, 0.5])
804-
>>> print(ca)
805-
[0. , 1. , 2.5, 4. , 1.5]
806-
807-
"""
808-
809-
return call_origin(numpy.convolve, a=a, v=v, mode=mode)
810-
811-
812793
_COPYSIGN_DOCSTRING = """
813794
Composes a floating-point value with the magnitude of `x1_i` and the sign of
814795
`x2_i` for each element of input arrays `x1` and `x2`.

dpnp/dpnp_iface_statistics.py

Lines changed: 134 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"amax",
6363
"amin",
6464
"average",
65+
"convolve",
6566
"corrcoef",
6667
"correlate",
6768
"cov",
@@ -357,6 +358,138 @@ def average(a, axis=None, weights=None, returned=False, *, keepdims=False):
357358
return avg
358359

359360

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+
360493
def corrcoef(x, y=None, rowvar=True, *, dtype=None):
361494
"""
362495
Return Pearson product-moment correlation coefficients.
@@ -714,24 +847,13 @@ def correlate(a, v, mode="valid", method="auto"):
714847
revert = True
715848
a, v = v, a
716849

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)
728851

729852
if revert:
730853
r = r[::-1]
731854

732855
return dpnp.asarray(r, dtype=rdtype, order="C")
733856

734-
735857
def cov(
736858
m,
737859
y=None,

dpnp/tests/test_mathematical.py

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -110,35 +110,6 @@ def test_conj_out(self, dtype):
110110
assert_dtype_allclose(result, expected)
111111

112112

113-
@pytest.mark.usefixtures("allow_fall_back_on_numpy")
114-
class TestConvolve:
115-
def test_object(self):
116-
d = [1.0] * 100
117-
k = [1.0] * 3
118-
assert_array_almost_equal(dpnp.convolve(d, k)[2:-2], dpnp.full(98, 3))
119-
120-
def test_no_overwrite(self):
121-
d = dpnp.ones(100)
122-
k = dpnp.ones(3)
123-
dpnp.convolve(d, k)
124-
assert_array_equal(d, dpnp.ones(100))
125-
assert_array_equal(k, dpnp.ones(3))
126-
127-
def test_mode(self):
128-
d = dpnp.ones(100)
129-
k = dpnp.ones(3)
130-
default_mode = dpnp.convolve(d, k, mode="full")
131-
full_mode = dpnp.convolve(d, k, mode="full")
132-
assert_array_equal(full_mode, default_mode)
133-
# integer mode
134-
with assert_raises(ValueError):
135-
dpnp.convolve(d, k, mode=-1)
136-
assert_array_equal(dpnp.convolve(d, k, mode=2), full_mode)
137-
# illegal arguments
138-
with assert_raises(TypeError):
139-
dpnp.convolve(d, k, mode=None)
140-
141-
142113
class TestClip:
143114
@pytest.mark.parametrize(
144115
"dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True)

0 commit comments

Comments
 (0)