DPNP C++ backend kernel library 0.18.0dev0
Data Parallel Extension for NumPy*
Loading...
Searching...
No Matches
sinc.hpp
1//*****************************************************************************
2// Copyright (c) 2024-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#define SYCL_EXT_ONEAPI_COMPLEX
29#if __has_include(<sycl/ext/oneapi/experimental/sycl_complex.hpp>)
30#include <sycl/ext/oneapi/experimental/sycl_complex.hpp>
31#else
32#include <sycl/ext/oneapi/experimental/complex/complex.hpp>
33#endif
34
35#include <sycl/sycl.hpp>
36
37// dpctl tensor headers
38#include "utils/type_utils.hpp"
39
40namespace dpnp::kernels::sinc
41{
42namespace tu_ns = dpctl::tensor::type_utils;
43
44namespace impl
45{
46namespace exprm_ns = sycl::ext::oneapi::experimental;
47
48template <typename Tp>
49inline Tp sin(const Tp &in)
50{
51 if constexpr (tu_ns::is_complex<Tp>::value) {
52 using realTp = typename Tp::value_type;
53
54 constexpr realTp q_nan = std::numeric_limits<realTp>::quiet_NaN();
55
56 realTp const &in_re = std::real(in);
57 realTp const &in_im = std::imag(in);
58
59 const bool in_re_finite = sycl::isfinite(in_re);
60 const bool in_im_finite = sycl::isfinite(in_im);
61 /*
62 * Handle the nearly-non-exceptional cases where
63 * real and imaginary parts of input are finite.
64 */
65 if (in_re_finite && in_im_finite) {
66 Tp res = exprm_ns::sin(exprm_ns::complex<realTp>(in)); // sin(in);
67 if (in_re == realTp(0)) {
68 res.real(sycl::copysign(realTp(0), in_re));
69 }
70 return res;
71 }
72
73 /*
74 * since sin(in) = -I * sinh(I * in), for special cases,
75 * we calculate real and imaginary parts of z = sinh(I * in) and
76 * then return { imag(z) , -real(z) } which is sin(in).
77 */
78 const realTp x = -in_im;
79 const realTp y = in_re;
80 const bool xfinite = in_im_finite;
81 const bool yfinite = in_re_finite;
82 /*
83 * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN.
84 * The sign of 0 in the result is unspecified. Choice = normally
85 * the same as dNaN.
86 *
87 * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN).
88 * The sign of 0 in the result is unspecified. Choice = normally
89 * the same as d(NaN).
90 */
91 if (x == realTp(0) && !yfinite) {
92 const realTp sinh_im = q_nan;
93 const realTp sinh_re = sycl::copysign(realTp(0), x * sinh_im);
94 return Tp{sinh_im, -sinh_re};
95 }
96
97 /*
98 * sinh(+-Inf +- I 0) = +-Inf + I +-0.
99 *
100 * sinh(NaN +- I 0) = d(NaN) + I +-0.
101 */
102 if (y == realTp(0) && !xfinite) {
103 if (std::isnan(x)) {
104 const realTp sinh_re = x;
105 const realTp sinh_im = y;
106 return Tp{sinh_im, -sinh_re};
107 }
108 const realTp sinh_re = x;
109 const realTp sinh_im = sycl::copysign(realTp(0), y);
110 return Tp{sinh_im, -sinh_re};
111 }
112
113 /*
114 * sinh(x +- I Inf) = dNaN + I dNaN.
115 *
116 * sinh(x + I NaN) = d(NaN) + I d(NaN).
117 */
118 if (xfinite && !yfinite) {
119 const realTp sinh_re = q_nan;
120 const realTp sinh_im = x * sinh_re;
121 return Tp{sinh_im, -sinh_re};
122 }
123
124 /*
125 * sinh(+-Inf + I NaN) = +-Inf + I d(NaN).
126 * The sign of Inf in the result is unspecified. Choice = normally
127 * the same as d(NaN).
128 *
129 * sinh(+-Inf +- I Inf) = +Inf + I dNaN.
130 * The sign of Inf in the result is unspecified.
131 * Choice = always - here for sinh to have positive result for
132 * imaginary part of sin.
133 *
134 * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y)
135 */
136 if (std::isinf(x)) {
137 if (!yfinite) {
138 const realTp sinh_re = -x * x;
139 const realTp sinh_im = x * (y - y);
140 return Tp{sinh_im, -sinh_re};
141 }
142 const realTp sinh_re = x * sycl::cos(y);
143 const realTp sinh_im =
144 std::numeric_limits<realTp>::infinity() * sycl::sin(y);
145 return Tp{sinh_im, -sinh_re};
146 }
147
148 /*
149 * sinh(NaN + I NaN) = d(NaN) + I d(NaN).
150 *
151 * sinh(NaN +- I Inf) = d(NaN) + I d(NaN).
152 *
153 * sinh(NaN + I y) = d(NaN) + I d(NaN).
154 */
155 const realTp y_m_y = (y - y);
156 const realTp sinh_re = (x * x) * y_m_y;
157 const realTp sinh_im = (x + x) * y_m_y;
158 return Tp{sinh_im, -sinh_re};
159 }
160 else {
161 if (in == Tp(0)) {
162 return in;
163 }
164 return sycl::sin(in);
165 }
166}
167} // namespace impl
168
169template <typename argT, typename Tp>
171{
172 // is function constant for given argT
173 using is_constant = typename std::false_type;
174 // constant value, if constant
175 // constexpr Tp constant_value = Tp{};
176 // is function defined for sycl::vec
177 using supports_vec = typename std::false_type;
178 // do both argT and Tp support subgroup store/load operation
179 using supports_sg_loadstore = typename std::negation<
180 std::disjunction<tu_ns::is_complex<Tp>, tu_ns::is_complex<argT>>>;
181
182 Tp operator()(const argT &x) const
183 {
184 constexpr argT pi =
185 static_cast<argT>(3.1415926535897932384626433832795029L);
186 const argT y = pi * x;
187
188 if (y == argT(0)) {
189 return Tp(1);
190 }
191
192 if constexpr (tu_ns::is_complex<argT>::value) {
193 return impl::sin(y) / y;
194 }
195 else {
196 return sycl::sinpi(x) / y;
197 }
198 }
199};
200} // namespace dpnp::kernels::sinc