1 // Jacobi theta functions
2 // Copyright Evan Miller 2020
3 //
4 // Use, modification and distribution are subject to the
5 // Boost Software License, Version 1.0. (See accompanying file
6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Four main theta functions with various flavors of parameterization,
9 // floating-point policies, and bonus "minus 1" versions of functions 3 and 4
10 // designed to preserve accuracy for small q. Twenty-four C++ functions are
11 // provided in all.
12 //
13 // The functions take a real argument z and a parameter known as q, or its close
14 // relative tau.
15 //
16 // The mathematical functions are best understood in terms of their Fourier
17 // series. Using the q parameterization, and summing from n = 0 to ∞:
18 //
19 // θ₁(z,q) = 2 Σ (-1)ⁿ * q^(n+1/2)² * sin((2n+1)z)
20 // θ₂(z,q) = 2 Σ q^(n+1/2)² * cos((2n+1)z)
21 // θ₃(z,q) = 1 + 2 Σ q^n² * cos(2nz)
22 // θ₄(z,q) = 1 + 2 Σ (-1)ⁿ * q^n² * cos(2nz)
23 //
24 // Appropriately multiplied and divided, these four theta functions can be used
25 // to implement the famous Jacabi elliptic functions - but this is not really
26 // recommended, as the existing Boost implementations are likely faster and
27 // more accurate. More saliently, setting z = 0 on the fourth theta function
28 // will produce the limiting CDF of the Kolmogorov-Smirnov distribution, which
29 // is this particular implementation’s raison d'être.
30 //
31 // Separate C++ functions are provided for q and for tau. The main q functions are:
32 //
33 // template <class T> inline T jacobi_theta1(T z, T q);
34 // template <class T> inline T jacobi_theta2(T z, T q);
35 // template <class T> inline T jacobi_theta3(T z, T q);
36 // template <class T> inline T jacobi_theta4(T z, T q);
37 //
38 // The parameter q, also known as the nome, is restricted to the domain (0, 1),
39 // and will throw a domain error otherwise.
40 //
41 // The equivalent functions that use tau instead of q are:
42 //
43 // template <class T> inline T jacobi_theta1tau(T z, T tau);
44 // template <class T> inline T jacobi_theta2tau(T z, T tau);
45 // template <class T> inline T jacobi_theta3tau(T z, T tau);
46 // template <class T> inline T jacobi_theta4tau(T z, T tau);
47 //
48 // Mathematically, q and τ are related by:
49 //
50 // q = exp(iπτ)
51 //
52 // However, the τ in the equation above is *not* identical to the tau in the function
53 // signature. Instead, `tau` is the imaginary component of τ. Mathematically, τ can
54 // be complex - but practically, most applications call for a purely imaginary τ.
55 // Rather than provide a full complex-number API, the author decided to treat the
56 // parameter `tau` as an imaginary number. So in computational terms, the
57 // relationship between `q` and `tau` is given by:
58 //
59 // q = exp(-constants::pi<T>() * tau)
60 //
61 // The tau versions are provided for the sake of accuracy, as well as conformance
62 // with common notation. If your q is an exponential, you are better off using
63 // the tau versions, e.g.
64 //
65 // jacobi_theta1(z, exp(-a)); // rather poor accuracy
66 // jacobi_theta1tau(z, a / constants::pi<T>()); // better accuracy
67 //
68 // Similarly, if you have a precise (small positive) value for the complement
69 // of q, you can obtain a more precise answer overall by passing the result of
70 // `log1p` to the tau parameter:
71 //
72 // jacobi_theta1(z, 1-q_complement); // precision lost in subtraction
73 // jacobi_theta1tau(z, -log1p(-q_complement) / constants::pi<T>()); // better!
74 //
75 // A third quartet of functions are provided for improving accuracy in cases
76 // where q is small, specifically |q| < exp(-π) ≅ 0.04 (or, equivalently, tau
77 // greater than unity). In this domain of q values, the third and fourth theta
78 // functions always return values close to 1. So the following "m1" functions
79 // are provided, similar in spirit to `expm1`, which return one less than their
80 // regular counterparts:
81 //
82 // template <class T> inline T jacobi_theta3m1(T z, T q);
83 // template <class T> inline T jacobi_theta4m1(T z, T q);
84 // template <class T> inline T jacobi_theta3m1tau(T z, T tau);
85 // template <class T> inline T jacobi_theta4m1tau(T z, T tau);
86 //
87 // Note that "m1" versions of the first and second theta would not be useful,
88 // as their ranges are not confined to a neighborhood around 1 (see the Fourier
89 // transform representations above).
90 //
91 // Finally, the twelve functions above are each available with a third Policy
92 // argument, which can be used to define a custom epsilon value. These Policy
93 // versions bring the total number of functions provided by jacobi_theta.hpp
94 // to twenty-four.
95 //
96 // See:
97 // https://mathworld.wolfram.com/JacobiThetaFunctions.html
98 // https://dlmf.nist.gov/20
99
100 #ifndef BOOST_MATH_JACOBI_THETA_HPP
101 #define BOOST_MATH_JACOBI_THETA_HPP
102
103 #include <boost/math/tools/complex.hpp>
104 #include <boost/math/tools/precision.hpp>
105 #include <boost/math/tools/promotion.hpp>
106 #include <boost/math/policies/error_handling.hpp>
107 #include <boost/math/constants/constants.hpp>
108
109 namespace boost{ namespace math{
110
111 // Simple functions - parameterized by q
112 template <class T, class U>
113 inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q);
114 template <class T, class U>
115 inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q);
116 template <class T, class U>
117 inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q);
118 template <class T, class U>
119 inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q);
120
121 // Simple functions - parameterized by tau (assumed imaginary)
122 // q = exp(iπτ)
123 // tau = -log(q)/π
124 template <class T, class U>
125 inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau);
126 template <class T, class U>
127 inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau);
128 template <class T, class U>
129 inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau);
130 template <class T, class U>
131 inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau);
132
133 // Minus one versions for small q / large tau
134 template <class T, class U>
135 inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q);
136 template <class T, class U>
137 inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q);
138 template <class T, class U>
139 inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau);
140 template <class T, class U>
141 inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau);
142
143 // Policied versions - parameterized by q
144 template <class T, class U, class Policy>
145 inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q, const Policy& pol);
146 template <class T, class U, class Policy>
147 inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q, const Policy& pol);
148 template <class T, class U, class Policy>
149 inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q, const Policy& pol);
150 template <class T, class U, class Policy>
151 inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q, const Policy& pol);
152
153 // Policied versions - parameterized by tau
154 template <class T, class U, class Policy>
155 inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau, const Policy& pol);
156 template <class T, class U, class Policy>
157 inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau, const Policy& pol);
158 template <class T, class U, class Policy>
159 inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau, const Policy& pol);
160 template <class T, class U, class Policy>
161 inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau, const Policy& pol);
162
163 // Policied m1 functions
164 template <class T, class U, class Policy>
165 inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q, const Policy& pol);
166 template <class T, class U, class Policy>
167 inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q, const Policy& pol);
168 template <class T, class U, class Policy>
169 inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau, const Policy& pol);
170 template <class T, class U, class Policy>
171 inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau, const Policy& pol);
172
173 // Compare the non-oscillating component of the delta to the previous delta.
174 // Both are assumed to be non-negative.
175 template <class RealType>
176 inline bool
_jacobi_theta_converged(RealType last_delta,RealType delta,RealType eps)177 _jacobi_theta_converged(RealType last_delta, RealType delta, RealType eps) {
178 return delta == 0.0 || delta < eps*last_delta;
179 }
180
181 template <class RealType>
182 inline RealType
_jacobi_theta_sum(RealType tau,RealType z_n,RealType z_increment,RealType eps)183 _jacobi_theta_sum(RealType tau, RealType z_n, RealType z_increment, RealType eps) {
184 BOOST_MATH_STD_USING
185 RealType delta = 0, partial_result = 0;
186 RealType last_delta = 0;
187
188 do {
189 last_delta = delta;
190 delta = exp(-tau*z_n*z_n/constants::pi<RealType>());
191 partial_result += delta;
192 z_n += z_increment;
193 } while (!_jacobi_theta_converged(last_delta, delta, eps));
194
195 return partial_result;
196 }
197
198 // The following _IMAGINARY theta functions assume imaginary z and are for
199 // internal use only. They are designed to increase accuracy and reduce the
200 // number of iterations required for convergence for large |q|. The z argument
201 // is scaled by tau, and the summations are rewritten to be double-sided
202 // following DLMF 20.13.4 and 20.13.5. The return values are scaled by
203 // exp(-tau*z²/π)/sqrt(tau).
204 //
205 // These functions are triggered when tau < 1, i.e. |q| > exp(-π) ≅ 0.043
206 //
207 // Note that jacobi_theta4 uses the imaginary version of jacobi_theta2 (and
208 // vice-versa). jacobi_theta1 and jacobi_theta3 use the imaginary versions of
209 // themselves, following DLMF 20.7.30 - 20.7.33.
210 template <class RealType, class Policy>
211 inline RealType
_IMAGINARY_jacobi_theta1tau(RealType z,RealType tau,const Policy &)212 _IMAGINARY_jacobi_theta1tau(RealType z, RealType tau, const Policy&) {
213 BOOST_MATH_STD_USING
214 RealType eps = policies::get_epsilon<RealType, Policy>();
215 RealType result = RealType(0);
216
217 // n>=0 even
218 result -= _jacobi_theta_sum(tau, RealType(z + constants::half_pi<RealType>()), constants::two_pi<RealType>(), eps);
219 // n>0 odd
220 result += _jacobi_theta_sum(tau, RealType(z + constants::half_pi<RealType>() + constants::pi<RealType>()), constants::two_pi<RealType>(), eps);
221 // n<0 odd
222 result += _jacobi_theta_sum(tau, RealType(z - constants::half_pi<RealType>()), RealType (-constants::two_pi<RealType>()), eps);
223 // n<0 even
224 result -= _jacobi_theta_sum(tau, RealType(z - constants::half_pi<RealType>() - constants::pi<RealType>()), RealType (-constants::two_pi<RealType>()), eps);
225
226 return result * sqrt(tau);
227 }
228
229 template <class RealType, class Policy>
230 inline RealType
_IMAGINARY_jacobi_theta2tau(RealType z,RealType tau,const Policy &)231 _IMAGINARY_jacobi_theta2tau(RealType z, RealType tau, const Policy&) {
232 BOOST_MATH_STD_USING
233 RealType eps = policies::get_epsilon<RealType, Policy>();
234 RealType result = RealType(0);
235
236 // n>=0
237 result += _jacobi_theta_sum(tau, RealType(z + constants::half_pi<RealType>()), constants::pi<RealType>(), eps);
238 // n<0
239 result += _jacobi_theta_sum(tau, RealType(z - constants::half_pi<RealType>()), RealType (-constants::pi<RealType>()), eps);
240
241 return result * sqrt(tau);
242 }
243
244 template <class RealType, class Policy>
245 inline RealType
_IMAGINARY_jacobi_theta3tau(RealType z,RealType tau,const Policy &)246 _IMAGINARY_jacobi_theta3tau(RealType z, RealType tau, const Policy&) {
247 BOOST_MATH_STD_USING
248 RealType eps = policies::get_epsilon<RealType, Policy>();
249 RealType result = 0;
250
251 // n=0
252 result += exp(-z*z*tau/constants::pi<RealType>());
253 // n>0
254 result += _jacobi_theta_sum(tau, RealType(z + constants::pi<RealType>()), constants::pi<RealType>(), eps);
255 // n<0
256 result += _jacobi_theta_sum(tau, RealType(z - constants::pi<RealType>()), RealType(-constants::pi<RealType>()), eps);
257
258 return result * sqrt(tau);
259 }
260
261 template <class RealType, class Policy>
262 inline RealType
_IMAGINARY_jacobi_theta4tau(RealType z,RealType tau,const Policy &)263 _IMAGINARY_jacobi_theta4tau(RealType z, RealType tau, const Policy&) {
264 BOOST_MATH_STD_USING
265 RealType eps = policies::get_epsilon<RealType, Policy>();
266 RealType result = 0;
267
268 // n = 0
269 result += exp(-z*z*tau/constants::pi<RealType>());
270
271 // n > 0 odd
272 result -= _jacobi_theta_sum(tau, RealType(z + constants::pi<RealType>()), constants::two_pi<RealType>(), eps);
273 // n < 0 odd
274 result -= _jacobi_theta_sum(tau, RealType(z - constants::pi<RealType>()), RealType (-constants::two_pi<RealType>()), eps);
275 // n > 0 even
276 result += _jacobi_theta_sum(tau, RealType(z + constants::two_pi<RealType>()), constants::two_pi<RealType>(), eps);
277 // n < 0 even
278 result += _jacobi_theta_sum(tau, RealType(z - constants::two_pi<RealType>()), RealType (-constants::two_pi<RealType>()), eps);
279
280 return result * sqrt(tau);
281 }
282
283 // First Jacobi theta function (Parameterized by tau - assumed imaginary)
284 // = 2 * Σ (-1)^n * exp(iπτ*(n+1/2)^2) * sin((2n+1)z)
285 template <class RealType, class Policy>
286 inline RealType
jacobi_theta1tau_imp(RealType z,RealType tau,const Policy & pol,const char * function)287 jacobi_theta1tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
288 {
289 BOOST_MATH_STD_USING
290 unsigned n = 0;
291 RealType eps = policies::get_epsilon<RealType, Policy>();
292 RealType q_n = 0, last_q_n, delta, result = 0;
293
294 if (tau <= 0.0)
295 return policies::raise_domain_error<RealType>(function,
296 "tau must be greater than 0 but got %1%.", tau, pol);
297
298 if (abs(z) == 0.0)
299 return result;
300
301 if (tau < 1.0) {
302 z = fmod(z, constants::two_pi<RealType>());
303 while (z > constants::pi<RealType>()) {
304 z -= constants::two_pi<RealType>();
305 }
306 while (z < -constants::pi<RealType>()) {
307 z += constants::two_pi<RealType>();
308 }
309
310 return _IMAGINARY_jacobi_theta1tau(z, RealType(1/tau), pol);
311 }
312
313 do {
314 last_q_n = q_n;
315 q_n = exp(-tau * constants::pi<RealType>() * RealType(n + 0.5)*RealType(n + 0.5) );
316 delta = q_n * sin(RealType(2*n+1)*z);
317 if (n%2)
318 delta = -delta;
319
320 result += delta + delta;
321 n++;
322 } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
323
324 return result;
325 }
326
327 // First Jacobi theta function (Parameterized by q)
328 // = 2 * Σ (-1)^n * q^(n+1/2)^2 * sin((2n+1)z)
329 template <class RealType, class Policy>
330 inline RealType
jacobi_theta1_imp(RealType z,RealType q,const Policy & pol,const char * function)331 jacobi_theta1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
332 BOOST_MATH_STD_USING
333 if (q <= 0.0 || q >= 1.0) {
334 return policies::raise_domain_error<RealType>(function,
335 "q must be greater than 0 and less than 1 but got %1%.", q, pol);
336 }
337 return jacobi_theta1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
338 }
339
340 // Second Jacobi theta function (Parameterized by tau - assumed imaginary)
341 // = 2 * Σ exp(iπτ*(n+1/2)^2) * cos((2n+1)z)
342 template <class RealType, class Policy>
343 inline RealType
jacobi_theta2tau_imp(RealType z,RealType tau,const Policy & pol,const char * function)344 jacobi_theta2tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
345 {
346 BOOST_MATH_STD_USING
347 unsigned n = 0;
348 RealType eps = policies::get_epsilon<RealType, Policy>();
349 RealType q_n = 0, last_q_n, delta, result = 0;
350
351 if (tau <= 0.0) {
352 return policies::raise_domain_error<RealType>(function,
353 "tau must be greater than 0 but got %1%.", tau, pol);
354 } else if (tau < 1.0 && abs(z) == 0.0) {
355 return jacobi_theta4tau(z, 1/tau, pol) / sqrt(tau);
356 } else if (tau < 1.0) { // DLMF 20.7.31
357 z = fmod(z, constants::two_pi<RealType>());
358 while (z > constants::pi<RealType>()) {
359 z -= constants::two_pi<RealType>();
360 }
361 while (z < -constants::pi<RealType>()) {
362 z += constants::two_pi<RealType>();
363 }
364
365 return _IMAGINARY_jacobi_theta4tau(z, RealType(1/tau), pol);
366 }
367
368 do {
369 last_q_n = q_n;
370 q_n = exp(-tau * constants::pi<RealType>() * RealType(n + 0.5)*RealType(n + 0.5));
371 delta = q_n * cos(RealType(2*n+1)*z);
372 result += delta + delta;
373 n++;
374 } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
375
376 return result;
377 }
378
379 // Second Jacobi theta function, parameterized by q
380 // = 2 * Σ q^(n+1/2)^2 * cos((2n+1)z)
381 template <class RealType, class Policy>
382 inline RealType
jacobi_theta2_imp(RealType z,RealType q,const Policy & pol,const char * function)383 jacobi_theta2_imp(RealType z, RealType q, const Policy& pol, const char *function) {
384 BOOST_MATH_STD_USING
385 if (q <= 0.0 || q >= 1.0) {
386 return policies::raise_domain_error<RealType>(function,
387 "q must be greater than 0 and less than 1 but got %1%.", q, pol);
388 }
389 return jacobi_theta2tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
390 }
391
392 // Third Jacobi theta function, minus one (Parameterized by tau - assumed imaginary)
393 // This function preserves accuracy for small values of q (i.e. |q| < exp(-π) ≅ 0.043)
394 // For larger values of q, the minus one version usually won't help.
395 // = 2 * Σ exp(iπτ*(n)^2) * cos(2nz)
396 template <class RealType, class Policy>
397 inline RealType
jacobi_theta3m1tau_imp(RealType z,RealType tau,const Policy & pol)398 jacobi_theta3m1tau_imp(RealType z, RealType tau, const Policy& pol)
399 {
400 BOOST_MATH_STD_USING
401
402 RealType eps = policies::get_epsilon<RealType, Policy>();
403 RealType q_n = 0, last_q_n, delta, result = 0;
404 unsigned n = 1;
405
406 if (tau < 1.0)
407 return jacobi_theta3tau(z, tau, pol) - RealType(1);
408
409 do {
410 last_q_n = q_n;
411 q_n = exp(-tau * constants::pi<RealType>() * RealType(n)*RealType(n));
412 delta = q_n * cos(RealType(2*n)*z);
413 result += delta + delta;
414 n++;
415 } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
416
417 return result;
418 }
419
420 // Third Jacobi theta function, parameterized by tau
421 // = 1 + 2 * Σ exp(iπτ*(n)^2) * cos(2nz)
422 template <class RealType, class Policy>
423 inline RealType
jacobi_theta3tau_imp(RealType z,RealType tau,const Policy & pol,const char * function)424 jacobi_theta3tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
425 {
426 BOOST_MATH_STD_USING
427 if (tau <= 0.0) {
428 return policies::raise_domain_error<RealType>(function,
429 "tau must be greater than 0 but got %1%.", tau, pol);
430 } else if (tau < 1.0 && abs(z) == 0.0) {
431 return jacobi_theta3tau(z, RealType(1/tau), pol) / sqrt(tau);
432 } else if (tau < 1.0) { // DLMF 20.7.32
433 z = fmod(z, constants::pi<RealType>());
434 while (z > constants::half_pi<RealType>()) {
435 z -= constants::pi<RealType>();
436 }
437 while (z < -constants::half_pi<RealType>()) {
438 z += constants::pi<RealType>();
439 }
440 return _IMAGINARY_jacobi_theta3tau(z, RealType(1/tau), pol);
441 }
442 return RealType(1) + jacobi_theta3m1tau_imp(z, tau, pol);
443 }
444
445 // Third Jacobi theta function, minus one (parameterized by q)
446 // = 2 * Σ q^n^2 * cos(2nz)
447 template <class RealType, class Policy>
448 inline RealType
jacobi_theta3m1_imp(RealType z,RealType q,const Policy & pol,const char * function)449 jacobi_theta3m1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
450 BOOST_MATH_STD_USING
451 if (q <= 0.0 || q >= 1.0) {
452 return policies::raise_domain_error<RealType>(function,
453 "q must be greater than 0 and less than 1 but got %1%.", q, pol);
454 }
455 return jacobi_theta3m1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol);
456 }
457
458 // Third Jacobi theta function (parameterized by q)
459 // = 1 + 2 * Σ q^n^2 * cos(2nz)
460 template <class RealType, class Policy>
461 inline RealType
jacobi_theta3_imp(RealType z,RealType q,const Policy & pol,const char * function)462 jacobi_theta3_imp(RealType z, RealType q, const Policy& pol, const char *function) {
463 BOOST_MATH_STD_USING
464 if (q <= 0.0 || q >= 1.0) {
465 return policies::raise_domain_error<RealType>(function,
466 "q must be greater than 0 and less than 1 but got %1%.", q, pol);
467 }
468 return jacobi_theta3tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
469 }
470
471 // Fourth Jacobi theta function, minus one (Parameterized by tau)
472 // This function preserves accuracy for small values of q (i.e. tau > 1)
473 // = 2 * Σ (-1)^n exp(iπτ*(n)^2) * cos(2nz)
474 template <class RealType, class Policy>
475 inline RealType
jacobi_theta4m1tau_imp(RealType z,RealType tau,const Policy & pol)476 jacobi_theta4m1tau_imp(RealType z, RealType tau, const Policy& pol)
477 {
478 BOOST_MATH_STD_USING
479
480 RealType eps = policies::get_epsilon<RealType, Policy>();
481 RealType q_n = 0, last_q_n, delta, result = 0;
482 unsigned n = 1;
483
484 if (tau < 1.0)
485 return jacobi_theta4tau(z, tau, pol) - RealType(1);
486
487 do {
488 last_q_n = q_n;
489 q_n = exp(-tau * constants::pi<RealType>() * RealType(n)*RealType(n));
490 delta = q_n * cos(RealType(2*n)*z);
491 if (n%2)
492 delta = -delta;
493
494 result += delta + delta;
495 n++;
496 } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
497
498 return result;
499 }
500
501 // Fourth Jacobi theta function (Parameterized by tau)
502 // = 1 + 2 * Σ (-1)^n exp(iπτ*(n)^2) * cos(2nz)
503 template <class RealType, class Policy>
504 inline RealType
jacobi_theta4tau_imp(RealType z,RealType tau,const Policy & pol,const char * function)505 jacobi_theta4tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
506 {
507 BOOST_MATH_STD_USING
508 if (tau <= 0.0) {
509 return policies::raise_domain_error<RealType>(function,
510 "tau must be greater than 0 but got %1%.", tau, pol);
511 } else if (tau < 1.0 && abs(z) == 0.0) {
512 return jacobi_theta2tau(z, 1/tau, pol) / sqrt(tau);
513 } else if (tau < 1.0) { // DLMF 20.7.33
514 z = fmod(z, constants::pi<RealType>());
515 while (z > constants::half_pi<RealType>()) {
516 z -= constants::pi<RealType>();
517 }
518 while (z < -constants::half_pi<RealType>()) {
519 z += constants::pi<RealType>();
520 }
521 return _IMAGINARY_jacobi_theta2tau(z, RealType(1/tau), pol);
522 }
523
524 return RealType(1) + jacobi_theta4m1tau_imp(z, tau, pol);
525 }
526
527 // Fourth Jacobi theta function, minus one (Parameterized by q)
528 // This function preserves accuracy for small values of q
529 // = 2 * Σ q^n^2 * cos(2nz)
530 template <class RealType, class Policy>
531 inline RealType
jacobi_theta4m1_imp(RealType z,RealType q,const Policy & pol,const char * function)532 jacobi_theta4m1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
533 BOOST_MATH_STD_USING
534 if (q <= 0.0 || q >= 1.0) {
535 return policies::raise_domain_error<RealType>(function,
536 "q must be greater than 0 and less than 1 but got %1%.", q, pol);
537 }
538 return jacobi_theta4m1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol);
539 }
540
541 // Fourth Jacobi theta function, parameterized by q
542 // = 1 + 2 * Σ q^n^2 * cos(2nz)
543 template <class RealType, class Policy>
544 inline RealType
jacobi_theta4_imp(RealType z,RealType q,const Policy & pol,const char * function)545 jacobi_theta4_imp(RealType z, RealType q, const Policy& pol, const char *function) {
546 BOOST_MATH_STD_USING
547 if (q <= 0.0 || q >= 1.0) {
548 return policies::raise_domain_error<RealType>(function,
549 "|q| must be greater than zero and less than 1, but got %1%.", q, pol);
550 }
551 return jacobi_theta4tau_imp(z, RealType(-log(q)/constants::pi<RealType>()), pol, function);
552 }
553
554 // Begin public API
555
556 template <class T, class U, class Policy>
jacobi_theta1tau(T z,U tau,const Policy &)557 inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau, const Policy&) {
558 BOOST_FPU_EXCEPTION_GUARD
559 typedef typename tools::promote_args<T, U>::type result_type;
560 typedef typename policies::normalise<
561 Policy,
562 policies::promote_float<false>,
563 policies::promote_double<false>,
564 policies::discrete_quantile<>,
565 policies::assert_undefined<> >::type forwarding_policy;
566
567 static const char* function = "boost::math::jacobi_theta1tau<%1%>(%1%)";
568
569 return policies::checked_narrowing_cast<result_type, Policy>(
570 jacobi_theta1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
571 forwarding_policy(), function), function);
572 }
573
574 template <class T, class U>
jacobi_theta1tau(T z,U tau)575 inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau) {
576 return jacobi_theta1tau(z, tau, policies::policy<>());
577 }
578
579 template <class T, class U, class Policy>
jacobi_theta1(T z,U q,const Policy &)580 inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q, const Policy&) {
581 BOOST_FPU_EXCEPTION_GUARD
582 typedef typename tools::promote_args<T, U>::type result_type;
583 typedef typename policies::normalise<
584 Policy,
585 policies::promote_float<false>,
586 policies::promote_double<false>,
587 policies::discrete_quantile<>,
588 policies::assert_undefined<> >::type forwarding_policy;
589
590 static const char* function = "boost::math::jacobi_theta1<%1%>(%1%)";
591
592 return policies::checked_narrowing_cast<result_type, Policy>(
593 jacobi_theta1_imp(static_cast<result_type>(z), static_cast<result_type>(q),
594 forwarding_policy(), function), function);
595 }
596
597 template <class T, class U>
jacobi_theta1(T z,U q)598 inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q) {
599 return jacobi_theta1(z, q, policies::policy<>());
600 }
601
602 template <class T, class U, class Policy>
jacobi_theta2tau(T z,U tau,const Policy &)603 inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau, const Policy&) {
604 BOOST_FPU_EXCEPTION_GUARD
605 typedef typename tools::promote_args<T, U>::type result_type;
606 typedef typename policies::normalise<
607 Policy,
608 policies::promote_float<false>,
609 policies::promote_double<false>,
610 policies::discrete_quantile<>,
611 policies::assert_undefined<> >::type forwarding_policy;
612
613 static const char* function = "boost::math::jacobi_theta2tau<%1%>(%1%)";
614
615 return policies::checked_narrowing_cast<result_type, Policy>(
616 jacobi_theta2tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
617 forwarding_policy(), function), function);
618 }
619
620 template <class T, class U>
jacobi_theta2tau(T z,U tau)621 inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau) {
622 return jacobi_theta2tau(z, tau, policies::policy<>());
623 }
624
625 template <class T, class U, class Policy>
jacobi_theta2(T z,U q,const Policy &)626 inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q, const Policy&) {
627 BOOST_FPU_EXCEPTION_GUARD
628 typedef typename tools::promote_args<T, U>::type result_type;
629 typedef typename policies::normalise<
630 Policy,
631 policies::promote_float<false>,
632 policies::promote_double<false>,
633 policies::discrete_quantile<>,
634 policies::assert_undefined<> >::type forwarding_policy;
635
636 static const char* function = "boost::math::jacobi_theta2<%1%>(%1%)";
637
638 return policies::checked_narrowing_cast<result_type, Policy>(
639 jacobi_theta2_imp(static_cast<result_type>(z), static_cast<result_type>(q),
640 forwarding_policy(), function), function);
641 }
642
643 template <class T, class U>
jacobi_theta2(T z,U q)644 inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q) {
645 return jacobi_theta2(z, q, policies::policy<>());
646 }
647
648 template <class T, class U, class Policy>
jacobi_theta3m1tau(T z,U tau,const Policy &)649 inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau, const Policy&) {
650 BOOST_FPU_EXCEPTION_GUARD
651 typedef typename tools::promote_args<T, U>::type result_type;
652 typedef typename policies::normalise<
653 Policy,
654 policies::promote_float<false>,
655 policies::promote_double<false>,
656 policies::discrete_quantile<>,
657 policies::assert_undefined<> >::type forwarding_policy;
658
659 static const char* function = "boost::math::jacobi_theta3m1tau<%1%>(%1%)";
660
661 return policies::checked_narrowing_cast<result_type, Policy>(
662 jacobi_theta3m1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
663 forwarding_policy()), function);
664 }
665
666 template <class T, class U>
jacobi_theta3m1tau(T z,U tau)667 inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau) {
668 return jacobi_theta3m1tau(z, tau, policies::policy<>());
669 }
670
671 template <class T, class U, class Policy>
jacobi_theta3tau(T z,U tau,const Policy &)672 inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau, const Policy&) {
673 BOOST_FPU_EXCEPTION_GUARD
674 typedef typename tools::promote_args<T, U>::type result_type;
675 typedef typename policies::normalise<
676 Policy,
677 policies::promote_float<false>,
678 policies::promote_double<false>,
679 policies::discrete_quantile<>,
680 policies::assert_undefined<> >::type forwarding_policy;
681
682 static const char* function = "boost::math::jacobi_theta3tau<%1%>(%1%)";
683
684 return policies::checked_narrowing_cast<result_type, Policy>(
685 jacobi_theta3tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
686 forwarding_policy(), function), function);
687 }
688
689 template <class T, class U>
jacobi_theta3tau(T z,U tau)690 inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau) {
691 return jacobi_theta3tau(z, tau, policies::policy<>());
692 }
693
694
695 template <class T, class U, class Policy>
jacobi_theta3m1(T z,U q,const Policy &)696 inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q, const Policy&) {
697 BOOST_FPU_EXCEPTION_GUARD
698 typedef typename tools::promote_args<T, U>::type result_type;
699 typedef typename policies::normalise<
700 Policy,
701 policies::promote_float<false>,
702 policies::promote_double<false>,
703 policies::discrete_quantile<>,
704 policies::assert_undefined<> >::type forwarding_policy;
705
706 static const char* function = "boost::math::jacobi_theta3m1<%1%>(%1%)";
707
708 return policies::checked_narrowing_cast<result_type, Policy>(
709 jacobi_theta3m1_imp(static_cast<result_type>(z), static_cast<result_type>(q),
710 forwarding_policy(), function), function);
711 }
712
713 template <class T, class U>
jacobi_theta3m1(T z,U q)714 inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q) {
715 return jacobi_theta3m1(z, q, policies::policy<>());
716 }
717
718 template <class T, class U, class Policy>
jacobi_theta3(T z,U q,const Policy &)719 inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q, const Policy&) {
720 BOOST_FPU_EXCEPTION_GUARD
721 typedef typename tools::promote_args<T, U>::type result_type;
722 typedef typename policies::normalise<
723 Policy,
724 policies::promote_float<false>,
725 policies::promote_double<false>,
726 policies::discrete_quantile<>,
727 policies::assert_undefined<> >::type forwarding_policy;
728
729 static const char* function = "boost::math::jacobi_theta3<%1%>(%1%)";
730
731 return policies::checked_narrowing_cast<result_type, Policy>(
732 jacobi_theta3_imp(static_cast<result_type>(z), static_cast<result_type>(q),
733 forwarding_policy(), function), function);
734 }
735
736 template <class T, class U>
jacobi_theta3(T z,U q)737 inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q) {
738 return jacobi_theta3(z, q, policies::policy<>());
739 }
740
741 template <class T, class U, class Policy>
jacobi_theta4m1tau(T z,U tau,const Policy &)742 inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau, const Policy&) {
743 BOOST_FPU_EXCEPTION_GUARD
744 typedef typename tools::promote_args<T, U>::type result_type;
745 typedef typename policies::normalise<
746 Policy,
747 policies::promote_float<false>,
748 policies::promote_double<false>,
749 policies::discrete_quantile<>,
750 policies::assert_undefined<> >::type forwarding_policy;
751
752 static const char* function = "boost::math::jacobi_theta4m1tau<%1%>(%1%)";
753
754 return policies::checked_narrowing_cast<result_type, Policy>(
755 jacobi_theta4m1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
756 forwarding_policy()), function);
757 }
758
759 template <class T, class U>
jacobi_theta4m1tau(T z,U tau)760 inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau) {
761 return jacobi_theta4m1tau(z, tau, policies::policy<>());
762 }
763
764 template <class T, class U, class Policy>
jacobi_theta4tau(T z,U tau,const Policy &)765 inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau, const Policy&) {
766 BOOST_FPU_EXCEPTION_GUARD
767 typedef typename tools::promote_args<T, U>::type result_type;
768 typedef typename policies::normalise<
769 Policy,
770 policies::promote_float<false>,
771 policies::promote_double<false>,
772 policies::discrete_quantile<>,
773 policies::assert_undefined<> >::type forwarding_policy;
774
775 static const char* function = "boost::math::jacobi_theta4tau<%1%>(%1%)";
776
777 return policies::checked_narrowing_cast<result_type, Policy>(
778 jacobi_theta4tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
779 forwarding_policy(), function), function);
780 }
781
782 template <class T, class U>
jacobi_theta4tau(T z,U tau)783 inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau) {
784 return jacobi_theta4tau(z, tau, policies::policy<>());
785 }
786
787 template <class T, class U, class Policy>
jacobi_theta4m1(T z,U q,const Policy &)788 inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q, const Policy&) {
789 BOOST_FPU_EXCEPTION_GUARD
790 typedef typename tools::promote_args<T, U>::type result_type;
791 typedef typename policies::normalise<
792 Policy,
793 policies::promote_float<false>,
794 policies::promote_double<false>,
795 policies::discrete_quantile<>,
796 policies::assert_undefined<> >::type forwarding_policy;
797
798 static const char* function = "boost::math::jacobi_theta4m1<%1%>(%1%)";
799
800 return policies::checked_narrowing_cast<result_type, Policy>(
801 jacobi_theta4m1_imp(static_cast<result_type>(z), static_cast<result_type>(q),
802 forwarding_policy(), function), function);
803 }
804
805 template <class T, class U>
jacobi_theta4m1(T z,U q)806 inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q) {
807 return jacobi_theta4m1(z, q, policies::policy<>());
808 }
809
810 template <class T, class U, class Policy>
jacobi_theta4(T z,U q,const Policy &)811 inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q, const Policy&) {
812 BOOST_FPU_EXCEPTION_GUARD
813 typedef typename tools::promote_args<T, U>::type result_type;
814 typedef typename policies::normalise<
815 Policy,
816 policies::promote_float<false>,
817 policies::promote_double<false>,
818 policies::discrete_quantile<>,
819 policies::assert_undefined<> >::type forwarding_policy;
820
821 static const char* function = "boost::math::jacobi_theta4<%1%>(%1%)";
822
823 return policies::checked_narrowing_cast<result_type, Policy>(
824 jacobi_theta4_imp(static_cast<result_type>(z), static_cast<result_type>(q),
825 forwarding_policy(), function), function);
826 }
827
828 template <class T, class U>
jacobi_theta4(T z,U q)829 inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q) {
830 return jacobi_theta4(z, q, policies::policy<>());
831 }
832
833 }}
834
835 #endif
836