Skip to content

Commit 11e2e12

Browse files
authored
implement dpnp.bartlett (#2366)
In this PR, `dpnp.bartlett` is implemented.
1 parent 1b0ce60 commit 11e2e12

File tree

9 files changed

+188
-7
lines changed

9 files changed

+188
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
* Added implementation of `dpnp.hamming` [#2341](https://github.com/IntelPython/dpnp/pull/2341), [#2357](https://github.com/IntelPython/dpnp/pull/2357)
1212
* Added implementation of `dpnp.hanning` [#2358](https://github.com/IntelPython/dpnp/pull/2358)
1313
* Added implementation of `dpnp.blackman` [#2363](https://github.com/IntelPython/dpnp/pull/2363)
14+
* Added implementation of `dpnp.bartlett` [#2366](https://github.com/IntelPython/dpnp/pull/2366)
1415

1516
### Changed
1617

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//*****************************************************************************
2+
// Copyright (c) 2025, Intel Corporation
3+
// All rights reserved.
4+
//
5+
// Redistribution and use in source and binary forms, with or without
6+
// modification, are permitted provided that the following conditions are met:
7+
// - Redistributions of source code must retain the above copyright notice,
8+
// this list of conditions and the following disclaimer.
9+
// - Redistributions in binary form must reproduce the above copyright notice,
10+
// this list of conditions and the following disclaimer in the documentation
11+
// and/or other materials provided with the distribution.
12+
//
13+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23+
// THE POSSIBILITY OF SUCH DAMAGE.
24+
//*****************************************************************************
25+
26+
#pragma once
27+
28+
#include "common.hpp"
29+
#include <sycl/sycl.hpp>
30+
31+
namespace dpnp::extensions::window::kernels
32+
{
33+
34+
template <typename T>
35+
class BartlettFunctor
36+
{
37+
private:
38+
T *data = nullptr;
39+
const std::size_t N;
40+
41+
public:
42+
BartlettFunctor(T *data, const std::size_t N) : data(data), N(N) {}
43+
44+
void operator()(sycl::id<1> id) const
45+
{
46+
const auto i = id.get(0);
47+
48+
const T alpha = (N - 1) / T(2);
49+
data[i] = T(1) - sycl::fabs(i - alpha) / alpha;
50+
}
51+
};
52+
53+
template <typename fnT, typename T>
54+
struct BartlettFactory
55+
{
56+
fnT get()
57+
{
58+
if constexpr (std::is_floating_point_v<T>) {
59+
return window_impl<T, BartlettFunctor>;
60+
}
61+
else {
62+
return nullptr;
63+
}
64+
}
65+
};
66+
67+
} // namespace dpnp::extensions::window::kernels

dpnp/backend/extensions/window/blackman.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ class BlackmanFunctor
4545
{
4646
const auto i = id.get(0);
4747

48-
data[i] = T(0.42) - T(0.5) * sycl::cospi(T(2) * i / (N - 1)) +
49-
T(0.08) * sycl::cospi(T(4) * i / (N - 1));
48+
const T alpha = T(2) * i / (N - 1);
49+
data[i] = T(0.42) - T(0.5) * sycl::cospi(alpha) +
50+
T(0.08) * sycl::cospi(T(2) * alpha);
5051
}
5152
};
5253

dpnp/backend/extensions/window/window_py.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <pybind11/pybind11.h>
3131
#include <pybind11/stl.h>
3232

33+
#include "bartlett.hpp"
3334
#include "blackman.hpp"
3435
#include "common.hpp"
3536
#include "hamming.hpp"
@@ -41,6 +42,7 @@ using window_ns::window_fn_ptr_t;
4142

4243
namespace dpctl_td_ns = dpctl::tensor::type_dispatch;
4344

45+
static window_fn_ptr_t bartlett_dispatch_vector[dpctl_td_ns::num_types];
4446
static window_fn_ptr_t blackman_dispatch_vector[dpctl_td_ns::num_types];
4547
static window_fn_ptr_t hamming_dispatch_vector[dpctl_td_ns::num_types];
4648
static window_fn_ptr_t hanning_dispatch_vector[dpctl_td_ns::num_types];
@@ -50,6 +52,21 @@ PYBIND11_MODULE(_window_impl, m)
5052
using arrayT = dpctl::tensor::usm_ndarray;
5153
using event_vecT = std::vector<sycl::event>;
5254

55+
{
56+
window_ns::init_window_dispatch_vectors<
57+
window_ns::kernels::BartlettFactory>(bartlett_dispatch_vector);
58+
59+
auto bartlett_pyapi = [&](sycl::queue &exec_q, const arrayT &result,
60+
const event_vecT &depends = {}) {
61+
return window_ns::py_window(exec_q, result, depends,
62+
bartlett_dispatch_vector);
63+
};
64+
65+
m.def("_bartlett", bartlett_pyapi, "Call Bartlett kernel",
66+
py::arg("sycl_queue"), py::arg("result"),
67+
py::arg("depends") = py::list());
68+
}
69+
5370
{
5471
window_ns::init_window_dispatch_vectors<
5572
window_ns::kernels::BlackmanFactory>(blackman_dispatch_vector);

dpnp/dpnp_iface_window.py

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
import dpnp
4646
import dpnp.backend.extensions.window._window_impl as wi
4747

48-
__all__ = ["blackman", "hamming", "hanning"]
48+
__all__ = ["bartlett", "blackman", "hamming", "hanning"]
4949

5050

5151
def _call_window_kernel(
@@ -81,6 +81,100 @@ def _call_window_kernel(
8181
return result
8282

8383

84+
def bartlett(M, device=None, usm_type=None, sycl_queue=None):
85+
r"""
86+
Return the Bartlett window.
87+
88+
The Bartlett window is very similar to a triangular window, except that the
89+
end points are at zero. It is often used in signal processing for tapering
90+
a signal, without generating too much ripple in the frequency domain.
91+
92+
For full documentation refer to :obj:`numpy.bartlett`.
93+
94+
Parameters
95+
----------
96+
M : int
97+
Number of points in the output window. If zero or less, an empty array
98+
is returned.
99+
device : {None, string, SyclDevice, SyclQueue, Device}, optional
100+
An array API concept of device where the output array is created.
101+
`device` can be ``None``, a oneAPI filter selector string, an instance
102+
of :class:`dpctl.SyclDevice` corresponding to a non-partitioned SYCL
103+
device, an instance of :class:`dpctl.SyclQueue`, or a
104+
:class:`dpctl.tensor.Device` object returned by
105+
:attr:`dpnp.ndarray.device`.
106+
107+
Default: ``None``.
108+
usm_type : {None, "device", "shared", "host"}, optional
109+
The type of SYCL USM allocation for the output array.
110+
111+
Default: ``None``.
112+
sycl_queue : {None, SyclQueue}, optional
113+
A SYCL queue to use for output array allocation and copying. The
114+
`sycl_queue` can be passed as ``None`` (the default), which means
115+
to get the SYCL queue from `device` keyword if present or to use
116+
a default queue.
117+
118+
Default: ``None``.
119+
120+
Returns
121+
-------
122+
out : dpnp.ndarray of shape (M,)
123+
The triangular window, with the maximum value normalized to one
124+
(the value one appears only if the number of samples is odd), with the
125+
first and last samples equal to zero.
126+
127+
See Also
128+
--------
129+
:obj:`dpnp.blackman` : Return the Blackman window.
130+
:obj:`dpnp.hamming` : Return the Hamming window.
131+
:obj:`dpnp.hanning` : Return the Hanning window.
132+
:obj:`dpnp.kaiser` : Return the Kaiser window.
133+
134+
Notes
135+
-----
136+
The Bartlett window is defined as
137+
138+
.. math:: w(n) = \frac{2}{M-1} \left(\frac{M-1}{2} -
139+
\left|n - \frac{M-1}{2}\right|\right)
140+
\qquad 0 \leq n \leq M-1
141+
142+
Examples
143+
--------
144+
>>> import dpnp as np
145+
>>> np.bartlett(12)
146+
array([0. , 0.18181818, 0.36363636, 0.54545455, 0.72727273,
147+
0.90909091, 0.90909091, 0.72727273, 0.54545455, 0.36363636,
148+
0.18181818, 0. ])
149+
150+
Creating the output array on a different device or with a
151+
specified usm_type:
152+
153+
>>> x = np.bartlett(4) # default case
154+
>>> x, x.device, x.usm_type
155+
(array([0. , 0.66666667, 0.66666667, 0. ]),
156+
Device(level_zero:gpu:0),
157+
'device')
158+
159+
>>> y = np.bartlett(4, device="cpu")
160+
>>> y, y.device, y.usm_type
161+
(array([0. , 0.66666667, 0.66666667, 0. ]),
162+
Device(opencl:cpu:0),
163+
'device')
164+
165+
>>> z = np.bartlett(4, usm_type="host")
166+
>>> z, z.device, z.usm_type
167+
(array([0. , 0.66666667, 0.66666667, 0. ]),
168+
Device(level_zero:gpu:0),
169+
'host')
170+
171+
"""
172+
173+
return _call_window_kernel(
174+
M, wi._bartlett, device=device, usm_type=usm_type, sycl_queue=sycl_queue
175+
)
176+
177+
84178
def blackman(M, device=None, usm_type=None, sycl_queue=None):
85179
r"""
86180
Return the Blackman window.

dpnp/tests/test_sycl_queue.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def assert_sycl_queue_equal(result, expected):
5353
"func, arg, kwargs",
5454
[
5555
pytest.param("arange", [-25.7], {"stop": 10**8, "step": 15}),
56+
pytest.param("bartlett", [10], {}),
5657
pytest.param("blackman", [10], {}),
5758
pytest.param("eye", [4, 2], {}),
5859
pytest.param("empty", [(2, 2)], {}),

dpnp/tests/test_usm_type.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ def test_array_creation_from_array(func, args, usm_type_x, usm_type_y):
177177
"func, arg, kwargs",
178178
[
179179
pytest.param("arange", [-25.7], {"stop": 10**8, "step": 15}),
180+
pytest.param("bartlett", [10], {}),
180181
pytest.param("blackman", [10], {}),
181182
pytest.param("eye", [4, 2], {}),
182183
pytest.param("empty", [(3, 4)], {}),

dpnp/tests/test_window.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from .helper import assert_dtype_allclose
88

99

10-
@pytest.mark.parametrize("func", ["blackman", "hamming", "hanning"])
10+
@pytest.mark.parametrize("func", ["bartlett", "blackman", "hamming", "hanning"])
1111
@pytest.mark.parametrize(
1212
"M",
1313
[
@@ -32,7 +32,7 @@ def test_window(func, M):
3232
assert_dtype_allclose(result, expected)
3333

3434

35-
@pytest.mark.parametrize("func", ["blackman", "hamming", "hanning"])
35+
@pytest.mark.parametrize("func", ["bartlett", "blackman", "hamming", "hanning"])
3636
@pytest.mark.parametrize(
3737
"M",
3838
[

dpnp/tests/third_party/cupy/math_tests/test_window.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
*testing.product(
1111
{
1212
"m": [0, 1, -1, 1024],
13-
# TODO: add ["bartlett"] when supported
14-
"name": ["blackman", "hamming", "hanning"],
13+
"name": ["bartlett", "blackman", "hamming", "hanning"],
1514
}
1615
)
1716
)

0 commit comments

Comments
 (0)