DPNP C++ backend kernel library 0.21.0dev3
Data Parallel Extension for NumPy*
Loading...
Searching...
No Matches
i0.hpp
1//*****************************************************************************
2// Copyright (c) 2024, 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// - Neither the name of the copyright holder nor the names of its contributors
13// may be used to endorse or promote products derived from this software
14// without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26// THE POSSIBILITY OF SUCH DAMAGE.
27//*****************************************************************************
28
29#pragma once
30
31#include <sycl/sycl.hpp>
32
38#if (defined(__SPIR__) || defined(__SPIRV__)) && defined(__INTEL_LLVM_COMPILER)
39#define __SYCL_EXT_INTEL_MATH_SUPPORT
40#endif
41
42#if defined(__SYCL_EXT_INTEL_MATH_SUPPORT)
43#include <sycl/ext/intel/math.hpp>
44#endif
45
47{
48#if defined(__SYCL_EXT_INTEL_MATH_SUPPORT)
49using sycl::ext::intel::math::cyl_bessel_i0;
50
51#else
52
57namespace impl
58{
66template <typename Tp>
67inline Tp cyl_bessel_ij_0_series(const Tp x, const unsigned int max_iter)
68{
69 const Tp x2 = x / Tp(2);
70 const Tp fact = sycl::exp(-sycl::lgamma(Tp(1)));
71
72 const Tp xx4 = x2 * x2;
73 Tp Jn = Tp(1);
74 Tp term = Tp(1);
75 constexpr Tp eps = std::numeric_limits<Tp>::epsilon();
76
77 for (unsigned int i = 1; i < max_iter; ++i) {
78 term *= xx4 / (Tp(i) * Tp(i));
79 Jn += term;
80 if (sycl::fabs(term / Jn) < eps) {
81 break;
82 }
83 }
84 return fact * Jn;
85}
86
93template <typename Tp>
94inline Tp bessel_ik_0(Tp x)
95{
96 constexpr Tp eps = std::numeric_limits<Tp>::epsilon();
97 constexpr Tp fp_min = Tp(10) * eps;
98 constexpr int max_iter = 15000;
99 constexpr Tp x_min = Tp(2);
100
101 const Tp mu = Tp(0);
102 const Tp mu2 = mu * mu;
103 const Tp xi = Tp(1) / x;
104 const Tp xi2 = Tp(2) * xi;
105 Tp h = fp_min;
106
107 Tp b = Tp(0);
108 Tp d = Tp(0);
109 Tp c = h;
110 int i;
111 for (i = 1; i <= max_iter; ++i) {
112 b += xi2;
113 d = Tp(1) / (b + d);
114 c = b + Tp(1) / c;
115
116 const Tp del = c * d;
117 h *= del;
118 if (sycl::fabs(del - Tp(1)) < eps) {
119 break;
120 }
121 }
122 if (i > max_iter) {
123 // argument `x` is too large
124 return std::numeric_limits<Tp>::infinity();
125 }
126
127 Tp Inul = fp_min;
128 const Tp Inul1 = Inul;
129 const Tp Ipnul = h * Inul;
130
131 constexpr Tp pi = static_cast<Tp>(3.1415926535897932384626433832795029L);
132 Tp f = Ipnul / Inul;
133 Tp Kmu, Knu1;
134 if (x < x_min) {
135 const Tp x2 = x / Tp(2);
136 const Tp pimu = pi * mu;
137 const Tp fact =
138 (sycl::fabs(pimu) < eps ? Tp(1) : pimu / sycl::sin(pimu));
139
140 Tp d = -sycl::log(x2);
141 Tp e = mu * d;
142 const Tp fact2 = (sycl::fabs(e) < eps ? Tp(1) : sycl::sinh(e) / e);
143
144 // compute the gamma functions required by the Temme series expansions
145 constexpr Tp gam1 =
146 -static_cast<Tp>(0.5772156649015328606065120900824024L);
147 const Tp gam2 = Tp(1) / sycl::tgamma(Tp(1));
148
149 Tp ff = fact * (gam1 * sycl::cosh(e) + gam2 * fact2 * d);
150 Tp sum = ff;
151 e = sycl::exp(e);
152
153 Tp p = e / (Tp(2) * gam2);
154 Tp q = Tp(1) / (Tp(2) * e * gam2);
155 Tp c = Tp(1);
156 d = x2 * x2;
157 Tp sum1 = p;
158 int i;
159 for (i = 1; i <= max_iter; ++i) {
160 ff = (i * ff + p + q) / (i * i - mu2);
161 c *= d / i;
162 p /= i - mu;
163 q /= i + mu;
164 const Tp del = c * ff;
165 sum += del;
166 const Tp __del1 = c * (p - i * ff);
167 sum1 += __del1;
168 if (sycl::fabs(del) < eps * sycl::fabs(sum)) {
169 break;
170 }
171 }
172 if (i > max_iter) {
173 // Bessel k series failed to converge
174 return std::numeric_limits<Tp>::quiet_NaN();
175 }
176 Kmu = sum;
177 Knu1 = sum1 * xi2;
178 }
179 else {
180 Tp b = Tp(2) * (Tp(1) + x);
181 Tp d = Tp(1) / b;
182 Tp delh = d;
183 Tp h = delh;
184 Tp q1 = Tp(0);
185 Tp q2 = Tp(1);
186 Tp a1 = Tp(0.25L) - mu2;
187 Tp q = c = a1;
188 Tp a = -a1;
189 Tp s = Tp(1) + q * delh;
190 int i;
191 for (i = 2; i <= max_iter; ++i) {
192 a -= 2 * (i - 1);
193 c = -a * c / i;
194 const Tp qnew = (q1 - b * q2) / a;
195 q1 = q2;
196 q2 = qnew;
197 q += c * qnew;
198 b += Tp(2);
199 d = Tp(1) / (b + a * d);
200 delh = (b * d - Tp(1)) * delh;
201 h += delh;
202 const Tp dels = q * delh;
203 s += dels;
204 if (sycl::fabs(dels / s) < eps) {
205 break;
206 }
207 }
208 if (i > max_iter) {
209 // Steed's method failed
210 return std::numeric_limits<Tp>::quiet_NaN();
211 }
212 h = a1 * h;
213 Kmu = sycl::sqrt(pi / (Tp(2) * x)) * sycl::exp(-x) / s;
214 Knu1 = Kmu * (mu + x + Tp(0.5L) - h) * xi;
215 }
216
217 Tp Kpmu = mu * xi * Kmu - Knu1;
218 Tp Inumu = xi / (f * Kmu - Kpmu);
219 return Inumu * Inul1 / Inul;
220}
221
228template <typename Tp>
229inline Tp cyl_bessel_i0(Tp x)
230{
231 if (sycl::isnan(x)) {
232 return std::numeric_limits<Tp>::quiet_NaN();
233 }
234
235 if (sycl::isinf(x)) {
236 // return +inf per any input infinity
237 return std::numeric_limits<Tp>::infinity();
238 }
239
240 if (x == Tp(0)) {
241 return Tp(1);
242 }
243
244 if (x * x < Tp(10)) {
245 return cyl_bessel_ij_0_series<Tp>(x, 200);
246 }
247 return bessel_ik_0(sycl::fabs(x));
248}
249} // namespace impl
250
252
253#endif
254
255template <typename argT, typename resT>
257{
258 // is function constant for given argT
259 using is_constant = typename std::false_type;
260 // constant value, if constant
261 // constexpr resT constant_value = resT{};
262 // is function defined for sycl::vec
263 using supports_vec = typename std::false_type;
264 // do both argT and resT support subgroup store/load operation
265 using supports_sg_loadstore = typename std::true_type;
266
267 resT operator()(const argT &x) const
268 {
269 if constexpr (std::is_same_v<resT, sycl::half>) {
270 return static_cast<resT>(cyl_bessel_i0<float>(float(x)));
271 }
272 else {
273 return cyl_bessel_i0(x);
274 }
275 }
276};
277} // namespace dpnp::kernels::i0
Tp cyl_bessel_i0(Tp x)
Return the regular modified Bessel function of order 0.
Definition i0.hpp:229
Tp cyl_bessel_ij_0_series(const Tp x, const unsigned int max_iter)
This routine returns the cylindrical Bessel functions of order 0 by series expansion.
Definition i0.hpp:67
Tp bessel_ik_0(Tp x)
Compute the modified Bessel functions.
Definition i0.hpp:94