jacobi_theta.hpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  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 INF:
  18. //
  19. // theta_1(z,q) = 2 SUM (-1)^n * q^(n+1/2)^2 * sin((2n+1)z)
  20. // theta_2(z,q) = 2 SUM q^(n+1/2)^2 * cos((2n+1)z)
  21. // theta_3(z,q) = 1 + 2 SUM q^n^2 * cos(2nz)
  22. // theta_4(z,q) = 1 + 2 SUM (-1)^n * q^n^2 * 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'etre.
  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 tau are related by:
  49. //
  50. // q = exp(i PI*Tau)
  51. //
  52. // However, the tau in the equation above is *not* identical to the tau in the function
  53. // signature. Instead, `tau` is the imaginary component of tau. Mathematically, tau can
  54. // be complex - but practically, most applications call for a purely imaginary tau.
  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(-PI) = 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. #ifndef BOOST_MATH_JACOBI_THETA_HPP
  100. #define BOOST_MATH_JACOBI_THETA_HPP
  101. #include <boost/math/tools/complex.hpp>
  102. #include <boost/math/tools/precision.hpp>
  103. #include <boost/math/tools/promotion.hpp>
  104. #include <boost/math/policies/error_handling.hpp>
  105. #include <boost/math/constants/constants.hpp>
  106. namespace boost{ namespace math{
  107. // Simple functions - parameterized by q
  108. template <class T, class U>
  109. inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q);
  110. template <class T, class U>
  111. inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q);
  112. template <class T, class U>
  113. inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q);
  114. template <class T, class U>
  115. inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q);
  116. // Simple functions - parameterized by tau (assumed imaginary)
  117. // q = exp(i*PI*TAU)
  118. // tau = -log(q)/PI
  119. template <class T, class U>
  120. inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau);
  121. template <class T, class U>
  122. inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau);
  123. template <class T, class U>
  124. inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau);
  125. template <class T, class U>
  126. inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau);
  127. // Minus one versions for small q / large tau
  128. template <class T, class U>
  129. inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q);
  130. template <class T, class U>
  131. inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q);
  132. template <class T, class U>
  133. inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau);
  134. template <class T, class U>
  135. inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau);
  136. // Policied versions - parameterized by q
  137. template <class T, class U, class Policy>
  138. inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q, const Policy& pol);
  139. template <class T, class U, class Policy>
  140. inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q, const Policy& pol);
  141. template <class T, class U, class Policy>
  142. inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q, const Policy& pol);
  143. template <class T, class U, class Policy>
  144. inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q, const Policy& pol);
  145. // Policied versions - parameterized by tau
  146. template <class T, class U, class Policy>
  147. inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau, const Policy& pol);
  148. template <class T, class U, class Policy>
  149. inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau, const Policy& pol);
  150. template <class T, class U, class Policy>
  151. inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau, const Policy& pol);
  152. template <class T, class U, class Policy>
  153. inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau, const Policy& pol);
  154. // Policied m1 functions
  155. template <class T, class U, class Policy>
  156. inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q, const Policy& pol);
  157. template <class T, class U, class Policy>
  158. inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q, const Policy& pol);
  159. template <class T, class U, class Policy>
  160. inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau, const Policy& pol);
  161. template <class T, class U, class Policy>
  162. inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau, const Policy& pol);
  163. // Compare the non-oscillating component of the delta to the previous delta.
  164. // Both are assumed to be non-negative.
  165. template <class RealType>
  166. inline bool
  167. _jacobi_theta_converged(RealType last_delta, RealType delta, RealType eps) {
  168. return delta == 0.0 || delta < eps*last_delta;
  169. }
  170. template <class RealType>
  171. inline RealType
  172. _jacobi_theta_sum(RealType tau, RealType z_n, RealType z_increment, RealType eps) {
  173. BOOST_MATH_STD_USING
  174. RealType delta = 0, partial_result = 0;
  175. RealType last_delta = 0;
  176. do {
  177. last_delta = delta;
  178. delta = exp(-tau*z_n*z_n/constants::pi<RealType>());
  179. partial_result += delta;
  180. z_n += z_increment;
  181. } while (!_jacobi_theta_converged(last_delta, delta, eps));
  182. return partial_result;
  183. }
  184. // The following _IMAGINARY theta functions assume imaginary z and are for
  185. // internal use only. They are designed to increase accuracy and reduce the
  186. // number of iterations required for convergence for large |q|. The z argument
  187. // is scaled by tau, and the summations are rewritten to be double-sided
  188. // following DLMF 20.13.4 and 20.13.5. The return values are scaled by
  189. // exp(-tau*z^2/Pi)/sqrt(tau).
  190. //
  191. // These functions are triggered when tau < 1, i.e. |q| > exp(-Pi) = 0.043
  192. //
  193. // Note that jacobi_theta4 uses the imaginary version of jacobi_theta2 (and
  194. // vice-versa). jacobi_theta1 and jacobi_theta3 use the imaginary versions of
  195. // themselves, following DLMF 20.7.30 - 20.7.33.
  196. template <class RealType, class Policy>
  197. inline RealType
  198. _IMAGINARY_jacobi_theta1tau(RealType z, RealType tau, const Policy&) {
  199. BOOST_MATH_STD_USING
  200. RealType eps = policies::get_epsilon<RealType, Policy>();
  201. RealType result = RealType(0);
  202. // n>=0 even
  203. result -= _jacobi_theta_sum(tau, RealType(z + constants::half_pi<RealType>()), constants::two_pi<RealType>(), eps);
  204. // n>0 odd
  205. result += _jacobi_theta_sum(tau, RealType(z + constants::half_pi<RealType>() + constants::pi<RealType>()), constants::two_pi<RealType>(), eps);
  206. // n<0 odd
  207. result += _jacobi_theta_sum(tau, RealType(z - constants::half_pi<RealType>()), RealType (-constants::two_pi<RealType>()), eps);
  208. // n<0 even
  209. result -= _jacobi_theta_sum(tau, RealType(z - constants::half_pi<RealType>() - constants::pi<RealType>()), RealType (-constants::two_pi<RealType>()), eps);
  210. return result * sqrt(tau);
  211. }
  212. template <class RealType, class Policy>
  213. inline RealType
  214. _IMAGINARY_jacobi_theta2tau(RealType z, RealType tau, const Policy&) {
  215. BOOST_MATH_STD_USING
  216. RealType eps = policies::get_epsilon<RealType, Policy>();
  217. RealType result = RealType(0);
  218. // n>=0
  219. result += _jacobi_theta_sum(tau, RealType(z + constants::half_pi<RealType>()), constants::pi<RealType>(), eps);
  220. // n<0
  221. result += _jacobi_theta_sum(tau, RealType(z - constants::half_pi<RealType>()), RealType (-constants::pi<RealType>()), eps);
  222. return result * sqrt(tau);
  223. }
  224. template <class RealType, class Policy>
  225. inline RealType
  226. _IMAGINARY_jacobi_theta3tau(RealType z, RealType tau, const Policy&) {
  227. BOOST_MATH_STD_USING
  228. RealType eps = policies::get_epsilon<RealType, Policy>();
  229. RealType result = 0;
  230. // n=0
  231. result += exp(-z*z*tau/constants::pi<RealType>());
  232. // n>0
  233. result += _jacobi_theta_sum(tau, RealType(z + constants::pi<RealType>()), constants::pi<RealType>(), eps);
  234. // n<0
  235. result += _jacobi_theta_sum(tau, RealType(z - constants::pi<RealType>()), RealType(-constants::pi<RealType>()), eps);
  236. return result * sqrt(tau);
  237. }
  238. template <class RealType, class Policy>
  239. inline RealType
  240. _IMAGINARY_jacobi_theta4tau(RealType z, RealType tau, const Policy&) {
  241. BOOST_MATH_STD_USING
  242. RealType eps = policies::get_epsilon<RealType, Policy>();
  243. RealType result = 0;
  244. // n = 0
  245. result += exp(-z*z*tau/constants::pi<RealType>());
  246. // n > 0 odd
  247. result -= _jacobi_theta_sum(tau, RealType(z + constants::pi<RealType>()), constants::two_pi<RealType>(), eps);
  248. // n < 0 odd
  249. result -= _jacobi_theta_sum(tau, RealType(z - constants::pi<RealType>()), RealType (-constants::two_pi<RealType>()), eps);
  250. // n > 0 even
  251. result += _jacobi_theta_sum(tau, RealType(z + constants::two_pi<RealType>()), constants::two_pi<RealType>(), eps);
  252. // n < 0 even
  253. result += _jacobi_theta_sum(tau, RealType(z - constants::two_pi<RealType>()), RealType (-constants::two_pi<RealType>()), eps);
  254. return result * sqrt(tau);
  255. }
  256. // First Jacobi theta function (Parameterized by tau - assumed imaginary)
  257. // = 2 * SUM (-1)^n * exp(i*Pi*Tau*(n+1/2)^2) * sin((2n+1)z)
  258. template <class RealType, class Policy>
  259. inline RealType
  260. jacobi_theta1tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
  261. {
  262. BOOST_MATH_STD_USING
  263. unsigned n = 0;
  264. RealType eps = policies::get_epsilon<RealType, Policy>();
  265. RealType q_n = 0, last_q_n, delta, result = 0;
  266. if (tau <= 0.0)
  267. return policies::raise_domain_error<RealType>(function, "tau must be greater than 0 but got %1%.", tau, pol);
  268. if (abs(z) == 0.0)
  269. return result;
  270. if (tau < 1.0) {
  271. z = fmod(z, constants::two_pi<RealType>());
  272. while (z > constants::pi<RealType>()) {
  273. z -= constants::two_pi<RealType>();
  274. }
  275. while (z < -constants::pi<RealType>()) {
  276. z += constants::two_pi<RealType>();
  277. }
  278. return _IMAGINARY_jacobi_theta1tau(z, RealType(1/tau), pol);
  279. }
  280. do {
  281. last_q_n = q_n;
  282. q_n = exp(-tau * constants::pi<RealType>() * RealType(n + 0.5)*RealType(n + 0.5) );
  283. delta = q_n * sin(RealType(2*n+1)*z);
  284. if (n%2)
  285. delta = -delta;
  286. result += delta + delta;
  287. n++;
  288. } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
  289. return result;
  290. }
  291. // First Jacobi theta function (Parameterized by q)
  292. // = 2 * SUM (-1)^n * q^(n+1/2)^2 * sin((2n+1)z)
  293. template <class RealType, class Policy>
  294. inline RealType
  295. jacobi_theta1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  296. BOOST_MATH_STD_USING
  297. if (q <= 0.0 || q >= 1.0) {
  298. return policies::raise_domain_error<RealType>(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  299. }
  300. return jacobi_theta1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
  301. }
  302. // Second Jacobi theta function (Parameterized by tau - assumed imaginary)
  303. // = 2 * SUM exp(i*Pi*Tau*(n+1/2)^2) * cos((2n+1)z)
  304. template <class RealType, class Policy>
  305. inline RealType
  306. jacobi_theta2tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
  307. {
  308. BOOST_MATH_STD_USING
  309. unsigned n = 0;
  310. RealType eps = policies::get_epsilon<RealType, Policy>();
  311. RealType q_n = 0, last_q_n, delta, result = 0;
  312. if (tau <= 0.0) {
  313. return policies::raise_domain_error<RealType>(function, "tau must be greater than 0 but got %1%.", tau, pol);
  314. } else if (tau < 1.0 && abs(z) == 0.0) {
  315. return jacobi_theta4tau(z, 1/tau, pol) / sqrt(tau);
  316. } else if (tau < 1.0) { // DLMF 20.7.31
  317. z = fmod(z, constants::two_pi<RealType>());
  318. while (z > constants::pi<RealType>()) {
  319. z -= constants::two_pi<RealType>();
  320. }
  321. while (z < -constants::pi<RealType>()) {
  322. z += constants::two_pi<RealType>();
  323. }
  324. return _IMAGINARY_jacobi_theta4tau(z, RealType(1/tau), pol);
  325. }
  326. do {
  327. last_q_n = q_n;
  328. q_n = exp(-tau * constants::pi<RealType>() * RealType(n + 0.5)*RealType(n + 0.5));
  329. delta = q_n * cos(RealType(2*n+1)*z);
  330. result += delta + delta;
  331. n++;
  332. } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
  333. return result;
  334. }
  335. // Second Jacobi theta function, parameterized by q
  336. // = 2 * SUM q^(n+1/2)^2 * cos((2n+1)z)
  337. template <class RealType, class Policy>
  338. inline RealType
  339. jacobi_theta2_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  340. BOOST_MATH_STD_USING
  341. if (q <= 0.0 || q >= 1.0) {
  342. return policies::raise_domain_error<RealType>(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  343. }
  344. return jacobi_theta2tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
  345. }
  346. // Third Jacobi theta function, minus one (Parameterized by tau - assumed imaginary)
  347. // This function preserves accuracy for small values of q (i.e. |q| < exp(-Pi) = 0.043)
  348. // For larger values of q, the minus one version usually won't help.
  349. // = 2 * SUM exp(i*Pi*Tau*(n)^2) * cos(2nz)
  350. template <class RealType, class Policy>
  351. inline RealType
  352. jacobi_theta3m1tau_imp(RealType z, RealType tau, const Policy& pol)
  353. {
  354. BOOST_MATH_STD_USING
  355. RealType eps = policies::get_epsilon<RealType, Policy>();
  356. RealType q_n = 0, last_q_n, delta, result = 0;
  357. unsigned n = 1;
  358. if (tau < 1.0)
  359. return jacobi_theta3tau(z, tau, pol) - RealType(1);
  360. do {
  361. last_q_n = q_n;
  362. q_n = exp(-tau * constants::pi<RealType>() * RealType(n)*RealType(n));
  363. delta = q_n * cos(RealType(2*n)*z);
  364. result += delta + delta;
  365. n++;
  366. } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
  367. return result;
  368. }
  369. // Third Jacobi theta function, parameterized by tau
  370. // = 1 + 2 * SUM exp(i*Pi*Tau*(n)^2) * cos(2nz)
  371. template <class RealType, class Policy>
  372. inline RealType
  373. jacobi_theta3tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
  374. {
  375. BOOST_MATH_STD_USING
  376. if (tau <= 0.0) {
  377. return policies::raise_domain_error<RealType>(function, "tau must be greater than 0 but got %1%.", tau, pol);
  378. } else if (tau < 1.0 && abs(z) == 0.0) {
  379. return jacobi_theta3tau(z, RealType(1/tau), pol) / sqrt(tau);
  380. } else if (tau < 1.0) { // DLMF 20.7.32
  381. z = fmod(z, constants::pi<RealType>());
  382. while (z > constants::half_pi<RealType>()) {
  383. z -= constants::pi<RealType>();
  384. }
  385. while (z < -constants::half_pi<RealType>()) {
  386. z += constants::pi<RealType>();
  387. }
  388. return _IMAGINARY_jacobi_theta3tau(z, RealType(1/tau), pol);
  389. }
  390. return RealType(1) + jacobi_theta3m1tau_imp(z, tau, pol);
  391. }
  392. // Third Jacobi theta function, minus one (parameterized by q)
  393. // = 2 * SUM q^n^2 * cos(2nz)
  394. template <class RealType, class Policy>
  395. inline RealType
  396. jacobi_theta3m1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  397. BOOST_MATH_STD_USING
  398. if (q <= 0.0 || q >= 1.0) {
  399. return policies::raise_domain_error<RealType>(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  400. }
  401. return jacobi_theta3m1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol);
  402. }
  403. // Third Jacobi theta function (parameterized by q)
  404. // = 1 + 2 * SUM q^n^2 * cos(2nz)
  405. template <class RealType, class Policy>
  406. inline RealType
  407. jacobi_theta3_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  408. BOOST_MATH_STD_USING
  409. if (q <= 0.0 || q >= 1.0) {
  410. return policies::raise_domain_error<RealType>(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  411. }
  412. return jacobi_theta3tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
  413. }
  414. // Fourth Jacobi theta function, minus one (Parameterized by tau)
  415. // This function preserves accuracy for small values of q (i.e. tau > 1)
  416. // = 2 * SUM (-1)^n exp(i*Pi*Tau*(n)^2) * cos(2nz)
  417. template <class RealType, class Policy>
  418. inline RealType
  419. jacobi_theta4m1tau_imp(RealType z, RealType tau, const Policy& pol)
  420. {
  421. BOOST_MATH_STD_USING
  422. RealType eps = policies::get_epsilon<RealType, Policy>();
  423. RealType q_n = 0, last_q_n, delta, result = 0;
  424. unsigned n = 1;
  425. if (tau < 1.0)
  426. return jacobi_theta4tau(z, tau, pol) - RealType(1);
  427. do {
  428. last_q_n = q_n;
  429. q_n = exp(-tau * constants::pi<RealType>() * RealType(n)*RealType(n));
  430. delta = q_n * cos(RealType(2*n)*z);
  431. if (n%2)
  432. delta = -delta;
  433. result += delta + delta;
  434. n++;
  435. } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
  436. return result;
  437. }
  438. // Fourth Jacobi theta function (Parameterized by tau)
  439. // = 1 + 2 * SUM (-1)^n exp(i*Pi*Tau*(n)^2) * cos(2nz)
  440. template <class RealType, class Policy>
  441. inline RealType
  442. jacobi_theta4tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
  443. {
  444. BOOST_MATH_STD_USING
  445. if (tau <= 0.0) {
  446. return policies::raise_domain_error<RealType>(function, "tau must be greater than 0 but got %1%.", tau, pol);
  447. } else if (tau < 1.0 && abs(z) == 0.0) {
  448. return jacobi_theta2tau(z, 1/tau, pol) / sqrt(tau);
  449. } else if (tau < 1.0) { // DLMF 20.7.33
  450. z = fmod(z, constants::pi<RealType>());
  451. while (z > constants::half_pi<RealType>()) {
  452. z -= constants::pi<RealType>();
  453. }
  454. while (z < -constants::half_pi<RealType>()) {
  455. z += constants::pi<RealType>();
  456. }
  457. return _IMAGINARY_jacobi_theta2tau(z, RealType(1/tau), pol);
  458. }
  459. return RealType(1) + jacobi_theta4m1tau_imp(z, tau, pol);
  460. }
  461. // Fourth Jacobi theta function, minus one (Parameterized by q)
  462. // This function preserves accuracy for small values of q
  463. // = 2 * SUM q^n^2 * cos(2nz)
  464. template <class RealType, class Policy>
  465. inline RealType
  466. jacobi_theta4m1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  467. BOOST_MATH_STD_USING
  468. if (q <= 0.0 || q >= 1.0) {
  469. return policies::raise_domain_error<RealType>(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  470. }
  471. return jacobi_theta4m1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol);
  472. }
  473. // Fourth Jacobi theta function, parameterized by q
  474. // = 1 + 2 * SUM q^n^2 * cos(2nz)
  475. template <class RealType, class Policy>
  476. inline RealType
  477. jacobi_theta4_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  478. BOOST_MATH_STD_USING
  479. if (q <= 0.0 || q >= 1.0) {
  480. return policies::raise_domain_error<RealType>(function, "|q| must be greater than zero and less than 1, but got %1%.", q, pol);
  481. }
  482. return jacobi_theta4tau_imp(z, RealType(-log(q)/constants::pi<RealType>()), pol, function);
  483. }
  484. // Begin public API
  485. template <class T, class U, class Policy>
  486. inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau, const Policy&) {
  487. BOOST_FPU_EXCEPTION_GUARD
  488. typedef typename tools::promote_args<T, U>::type result_type;
  489. typedef typename policies::normalise<
  490. Policy,
  491. policies::promote_float<false>,
  492. policies::promote_double<false>,
  493. policies::discrete_quantile<>,
  494. policies::assert_undefined<> >::type forwarding_policy;
  495. static const char* function = "boost::math::jacobi_theta1tau<%1%>(%1%)";
  496. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau), forwarding_policy(), function), function);
  497. }
  498. template <class T, class U>
  499. inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau) {
  500. return jacobi_theta1tau(z, tau, policies::policy<>());
  501. }
  502. template <class T, class U, class Policy>
  503. inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q, const Policy&) {
  504. BOOST_FPU_EXCEPTION_GUARD
  505. typedef typename tools::promote_args<T, U>::type result_type;
  506. typedef typename policies::normalise<
  507. Policy,
  508. policies::promote_float<false>,
  509. policies::promote_double<false>,
  510. policies::discrete_quantile<>,
  511. policies::assert_undefined<> >::type forwarding_policy;
  512. static const char* function = "boost::math::jacobi_theta1<%1%>(%1%)";
  513. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta1_imp(static_cast<result_type>(z), static_cast<result_type>(q), forwarding_policy(), function), function);
  514. }
  515. template <class T, class U>
  516. inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q) {
  517. return jacobi_theta1(z, q, policies::policy<>());
  518. }
  519. template <class T, class U, class Policy>
  520. inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau, const Policy&) {
  521. BOOST_FPU_EXCEPTION_GUARD
  522. typedef typename tools::promote_args<T, U>::type result_type;
  523. typedef typename policies::normalise<
  524. Policy,
  525. policies::promote_float<false>,
  526. policies::promote_double<false>,
  527. policies::discrete_quantile<>,
  528. policies::assert_undefined<> >::type forwarding_policy;
  529. static const char* function = "boost::math::jacobi_theta2tau<%1%>(%1%)";
  530. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta2tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau), forwarding_policy(), function), function);
  531. }
  532. template <class T, class U>
  533. inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau) {
  534. return jacobi_theta2tau(z, tau, policies::policy<>());
  535. }
  536. template <class T, class U, class Policy>
  537. inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q, const Policy&) {
  538. BOOST_FPU_EXCEPTION_GUARD
  539. typedef typename tools::promote_args<T, U>::type result_type;
  540. typedef typename policies::normalise<
  541. Policy,
  542. policies::promote_float<false>,
  543. policies::promote_double<false>,
  544. policies::discrete_quantile<>,
  545. policies::assert_undefined<> >::type forwarding_policy;
  546. static const char* function = "boost::math::jacobi_theta2<%1%>(%1%)";
  547. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta2_imp(static_cast<result_type>(z), static_cast<result_type>(q), forwarding_policy(), function), function);
  548. }
  549. template <class T, class U>
  550. inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q) {
  551. return jacobi_theta2(z, q, policies::policy<>());
  552. }
  553. template <class T, class U, class Policy>
  554. inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau, const Policy&) {
  555. BOOST_FPU_EXCEPTION_GUARD
  556. typedef typename tools::promote_args<T, U>::type result_type;
  557. typedef typename policies::normalise<
  558. Policy,
  559. policies::promote_float<false>,
  560. policies::promote_double<false>,
  561. policies::discrete_quantile<>,
  562. policies::assert_undefined<> >::type forwarding_policy;
  563. static const char* function = "boost::math::jacobi_theta3m1tau<%1%>(%1%)";
  564. return policies::checked_narrowing_cast<result_type, Policy>(
  565. jacobi_theta3m1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau), forwarding_policy()), function);
  566. }
  567. template <class T, class U>
  568. inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau) {
  569. return jacobi_theta3m1tau(z, tau, policies::policy<>());
  570. }
  571. template <class T, class U, class Policy>
  572. inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau, const Policy&) {
  573. BOOST_FPU_EXCEPTION_GUARD
  574. typedef typename tools::promote_args<T, U>::type result_type;
  575. typedef typename policies::normalise<
  576. Policy,
  577. policies::promote_float<false>,
  578. policies::promote_double<false>,
  579. policies::discrete_quantile<>,
  580. policies::assert_undefined<> >::type forwarding_policy;
  581. static const char* function = "boost::math::jacobi_theta3tau<%1%>(%1%)";
  582. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta3tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau), forwarding_policy(), function), function);
  583. }
  584. template <class T, class U>
  585. inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau) {
  586. return jacobi_theta3tau(z, tau, policies::policy<>());
  587. }
  588. template <class T, class U, class Policy>
  589. inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q, const Policy&) {
  590. BOOST_FPU_EXCEPTION_GUARD
  591. typedef typename tools::promote_args<T, U>::type result_type;
  592. typedef typename policies::normalise<
  593. Policy,
  594. policies::promote_float<false>,
  595. policies::promote_double<false>,
  596. policies::discrete_quantile<>,
  597. policies::assert_undefined<> >::type forwarding_policy;
  598. static const char* function = "boost::math::jacobi_theta3m1<%1%>(%1%)";
  599. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta3m1_imp(static_cast<result_type>(z), static_cast<result_type>(q), forwarding_policy(), function), function);
  600. }
  601. template <class T, class U>
  602. inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q) {
  603. return jacobi_theta3m1(z, q, policies::policy<>());
  604. }
  605. template <class T, class U, class Policy>
  606. inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q, const Policy&) {
  607. BOOST_FPU_EXCEPTION_GUARD
  608. typedef typename tools::promote_args<T, U>::type result_type;
  609. typedef typename policies::normalise<
  610. Policy,
  611. policies::promote_float<false>,
  612. policies::promote_double<false>,
  613. policies::discrete_quantile<>,
  614. policies::assert_undefined<> >::type forwarding_policy;
  615. static const char* function = "boost::math::jacobi_theta3<%1%>(%1%)";
  616. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta3_imp(static_cast<result_type>(z), static_cast<result_type>(q), forwarding_policy(), function), function);
  617. }
  618. template <class T, class U>
  619. inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q) {
  620. return jacobi_theta3(z, q, policies::policy<>());
  621. }
  622. template <class T, class U, class Policy>
  623. inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau, const Policy&) {
  624. BOOST_FPU_EXCEPTION_GUARD
  625. typedef typename tools::promote_args<T, U>::type result_type;
  626. typedef typename policies::normalise<
  627. Policy,
  628. policies::promote_float<false>,
  629. policies::promote_double<false>,
  630. policies::discrete_quantile<>,
  631. policies::assert_undefined<> >::type forwarding_policy;
  632. static const char* function = "boost::math::jacobi_theta4m1tau<%1%>(%1%)";
  633. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta4m1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau), forwarding_policy()), function);
  634. }
  635. template <class T, class U>
  636. inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau) {
  637. return jacobi_theta4m1tau(z, tau, policies::policy<>());
  638. }
  639. template <class T, class U, class Policy>
  640. inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau, const Policy&) {
  641. BOOST_FPU_EXCEPTION_GUARD
  642. typedef typename tools::promote_args<T, U>::type result_type;
  643. typedef typename policies::normalise<
  644. Policy,
  645. policies::promote_float<false>,
  646. policies::promote_double<false>,
  647. policies::discrete_quantile<>,
  648. policies::assert_undefined<> >::type forwarding_policy;
  649. static const char* function = "boost::math::jacobi_theta4tau<%1%>(%1%)";
  650. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta4tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau), forwarding_policy(), function), function);
  651. }
  652. template <class T, class U>
  653. inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau) {
  654. return jacobi_theta4tau(z, tau, policies::policy<>());
  655. }
  656. template <class T, class U, class Policy>
  657. inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q, const Policy&) {
  658. BOOST_FPU_EXCEPTION_GUARD
  659. typedef typename tools::promote_args<T, U>::type result_type;
  660. typedef typename policies::normalise<
  661. Policy,
  662. policies::promote_float<false>,
  663. policies::promote_double<false>,
  664. policies::discrete_quantile<>,
  665. policies::assert_undefined<> >::type forwarding_policy;
  666. static const char* function = "boost::math::jacobi_theta4m1<%1%>(%1%)";
  667. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta4m1_imp(static_cast<result_type>(z), static_cast<result_type>(q), forwarding_policy(), function), function);
  668. }
  669. template <class T, class U>
  670. inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q) {
  671. return jacobi_theta4m1(z, q, policies::policy<>());
  672. }
  673. template <class T, class U, class Policy>
  674. inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q, const Policy&) {
  675. BOOST_FPU_EXCEPTION_GUARD
  676. typedef typename tools::promote_args<T, U>::type result_type;
  677. typedef typename policies::normalise<
  678. Policy,
  679. policies::promote_float<false>,
  680. policies::promote_double<false>,
  681. policies::discrete_quantile<>,
  682. policies::assert_undefined<> >::type forwarding_policy;
  683. static const char* function = "boost::math::jacobi_theta4<%1%>(%1%)";
  684. return policies::checked_narrowing_cast<result_type, Policy>(jacobi_theta4_imp(static_cast<result_type>(z), static_cast<result_type>(q), forwarding_policy(), function), function);
  685. }
  686. template <class T, class U>
  687. inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q) {
  688. return jacobi_theta4(z, q, policies::policy<>());
  689. }
  690. }}
  691. #endif