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