jacobi_theta.hpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  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,
  268. "tau must be greater than 0 but got %1%.", tau, pol);
  269. if (abs(z) == 0.0)
  270. return result;
  271. if (tau < 1.0) {
  272. z = fmod(z, constants::two_pi<RealType>());
  273. while (z > constants::pi<RealType>()) {
  274. z -= constants::two_pi<RealType>();
  275. }
  276. while (z < -constants::pi<RealType>()) {
  277. z += constants::two_pi<RealType>();
  278. }
  279. return _IMAGINARY_jacobi_theta1tau(z, RealType(1/tau), pol);
  280. }
  281. do {
  282. last_q_n = q_n;
  283. q_n = exp(-tau * constants::pi<RealType>() * RealType(n + 0.5)*RealType(n + 0.5) );
  284. delta = q_n * sin(RealType(2*n+1)*z);
  285. if (n%2)
  286. delta = -delta;
  287. result += delta + delta;
  288. n++;
  289. } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
  290. return result;
  291. }
  292. // First Jacobi theta function (Parameterized by q)
  293. // = 2 * SUM (-1)^n * q^(n+1/2)^2 * sin((2n+1)z)
  294. template <class RealType, class Policy>
  295. inline RealType
  296. jacobi_theta1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  297. BOOST_MATH_STD_USING
  298. if (q <= 0.0 || q >= 1.0) {
  299. return policies::raise_domain_error<RealType>(function,
  300. "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  301. }
  302. return jacobi_theta1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
  303. }
  304. // Second Jacobi theta function (Parameterized by tau - assumed imaginary)
  305. // = 2 * SUM exp(i*Pi*Tau*(n+1/2)^2) * cos((2n+1)z)
  306. template <class RealType, class Policy>
  307. inline RealType
  308. jacobi_theta2tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
  309. {
  310. BOOST_MATH_STD_USING
  311. unsigned n = 0;
  312. RealType eps = policies::get_epsilon<RealType, Policy>();
  313. RealType q_n = 0, last_q_n, delta, result = 0;
  314. if (tau <= 0.0) {
  315. return policies::raise_domain_error<RealType>(function,
  316. "tau must be greater than 0 but got %1%.", tau, pol);
  317. } else if (tau < 1.0 && abs(z) == 0.0) {
  318. return jacobi_theta4tau(z, 1/tau, pol) / sqrt(tau);
  319. } else if (tau < 1.0) { // DLMF 20.7.31
  320. z = fmod(z, constants::two_pi<RealType>());
  321. while (z > constants::pi<RealType>()) {
  322. z -= constants::two_pi<RealType>();
  323. }
  324. while (z < -constants::pi<RealType>()) {
  325. z += constants::two_pi<RealType>();
  326. }
  327. return _IMAGINARY_jacobi_theta4tau(z, RealType(1/tau), pol);
  328. }
  329. do {
  330. last_q_n = q_n;
  331. q_n = exp(-tau * constants::pi<RealType>() * RealType(n + 0.5)*RealType(n + 0.5));
  332. delta = q_n * cos(RealType(2*n+1)*z);
  333. result += delta + delta;
  334. n++;
  335. } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
  336. return result;
  337. }
  338. // Second Jacobi theta function, parameterized by q
  339. // = 2 * SUM q^(n+1/2)^2 * cos((2n+1)z)
  340. template <class RealType, class Policy>
  341. inline RealType
  342. jacobi_theta2_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  343. BOOST_MATH_STD_USING
  344. if (q <= 0.0 || q >= 1.0) {
  345. return policies::raise_domain_error<RealType>(function,
  346. "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  347. }
  348. return jacobi_theta2tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
  349. }
  350. // Third Jacobi theta function, minus one (Parameterized by tau - assumed imaginary)
  351. // This function preserves accuracy for small values of q (i.e. |q| < exp(-Pi) = 0.043)
  352. // For larger values of q, the minus one version usually won't help.
  353. // = 2 * SUM exp(i*Pi*Tau*(n)^2) * cos(2nz)
  354. template <class RealType, class Policy>
  355. inline RealType
  356. jacobi_theta3m1tau_imp(RealType z, RealType tau, const Policy& pol)
  357. {
  358. BOOST_MATH_STD_USING
  359. RealType eps = policies::get_epsilon<RealType, Policy>();
  360. RealType q_n = 0, last_q_n, delta, result = 0;
  361. unsigned n = 1;
  362. if (tau < 1.0)
  363. return jacobi_theta3tau(z, tau, pol) - RealType(1);
  364. do {
  365. last_q_n = q_n;
  366. q_n = exp(-tau * constants::pi<RealType>() * RealType(n)*RealType(n));
  367. delta = q_n * cos(RealType(2*n)*z);
  368. result += delta + delta;
  369. n++;
  370. } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
  371. return result;
  372. }
  373. // Third Jacobi theta function, parameterized by tau
  374. // = 1 + 2 * SUM exp(i*Pi*Tau*(n)^2) * cos(2nz)
  375. template <class RealType, class Policy>
  376. inline RealType
  377. jacobi_theta3tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
  378. {
  379. BOOST_MATH_STD_USING
  380. if (tau <= 0.0) {
  381. return policies::raise_domain_error<RealType>(function,
  382. "tau must be greater than 0 but got %1%.", tau, pol);
  383. } else if (tau < 1.0 && abs(z) == 0.0) {
  384. return jacobi_theta3tau(z, RealType(1/tau), pol) / sqrt(tau);
  385. } else if (tau < 1.0) { // DLMF 20.7.32
  386. z = fmod(z, constants::pi<RealType>());
  387. while (z > constants::half_pi<RealType>()) {
  388. z -= constants::pi<RealType>();
  389. }
  390. while (z < -constants::half_pi<RealType>()) {
  391. z += constants::pi<RealType>();
  392. }
  393. return _IMAGINARY_jacobi_theta3tau(z, RealType(1/tau), pol);
  394. }
  395. return RealType(1) + jacobi_theta3m1tau_imp(z, tau, pol);
  396. }
  397. // Third Jacobi theta function, minus one (parameterized by q)
  398. // = 2 * SUM q^n^2 * cos(2nz)
  399. template <class RealType, class Policy>
  400. inline RealType
  401. jacobi_theta3m1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  402. BOOST_MATH_STD_USING
  403. if (q <= 0.0 || q >= 1.0) {
  404. return policies::raise_domain_error<RealType>(function,
  405. "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  406. }
  407. return jacobi_theta3m1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol);
  408. }
  409. // Third Jacobi theta function (parameterized by q)
  410. // = 1 + 2 * SUM q^n^2 * cos(2nz)
  411. template <class RealType, class Policy>
  412. inline RealType
  413. jacobi_theta3_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  414. BOOST_MATH_STD_USING
  415. if (q <= 0.0 || q >= 1.0) {
  416. return policies::raise_domain_error<RealType>(function,
  417. "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  418. }
  419. return jacobi_theta3tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol, function);
  420. }
  421. // Fourth Jacobi theta function, minus one (Parameterized by tau)
  422. // This function preserves accuracy for small values of q (i.e. tau > 1)
  423. // = 2 * SUM (-1)^n exp(i*Pi*Tau*(n)^2) * cos(2nz)
  424. template <class RealType, class Policy>
  425. inline RealType
  426. jacobi_theta4m1tau_imp(RealType z, RealType tau, const Policy& pol)
  427. {
  428. BOOST_MATH_STD_USING
  429. RealType eps = policies::get_epsilon<RealType, Policy>();
  430. RealType q_n = 0, last_q_n, delta, result = 0;
  431. unsigned n = 1;
  432. if (tau < 1.0)
  433. return jacobi_theta4tau(z, tau, pol) - RealType(1);
  434. do {
  435. last_q_n = q_n;
  436. q_n = exp(-tau * constants::pi<RealType>() * RealType(n)*RealType(n));
  437. delta = q_n * cos(RealType(2*n)*z);
  438. if (n%2)
  439. delta = -delta;
  440. result += delta + delta;
  441. n++;
  442. } while (!_jacobi_theta_converged(last_q_n, q_n, eps));
  443. return result;
  444. }
  445. // Fourth Jacobi theta function (Parameterized by tau)
  446. // = 1 + 2 * SUM (-1)^n exp(i*Pi*Tau*(n)^2) * cos(2nz)
  447. template <class RealType, class Policy>
  448. inline RealType
  449. jacobi_theta4tau_imp(RealType z, RealType tau, const Policy& pol, const char *function)
  450. {
  451. BOOST_MATH_STD_USING
  452. if (tau <= 0.0) {
  453. return policies::raise_domain_error<RealType>(function,
  454. "tau must be greater than 0 but got %1%.", tau, pol);
  455. } else if (tau < 1.0 && abs(z) == 0.0) {
  456. return jacobi_theta2tau(z, 1/tau, pol) / sqrt(tau);
  457. } else if (tau < 1.0) { // DLMF 20.7.33
  458. z = fmod(z, constants::pi<RealType>());
  459. while (z > constants::half_pi<RealType>()) {
  460. z -= constants::pi<RealType>();
  461. }
  462. while (z < -constants::half_pi<RealType>()) {
  463. z += constants::pi<RealType>();
  464. }
  465. return _IMAGINARY_jacobi_theta2tau(z, RealType(1/tau), pol);
  466. }
  467. return RealType(1) + jacobi_theta4m1tau_imp(z, tau, pol);
  468. }
  469. // Fourth Jacobi theta function, minus one (Parameterized by q)
  470. // This function preserves accuracy for small values of q
  471. // = 2 * SUM q^n^2 * cos(2nz)
  472. template <class RealType, class Policy>
  473. inline RealType
  474. jacobi_theta4m1_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  475. BOOST_MATH_STD_USING
  476. if (q <= 0.0 || q >= 1.0) {
  477. return policies::raise_domain_error<RealType>(function,
  478. "q must be greater than 0 and less than 1 but got %1%.", q, pol);
  479. }
  480. return jacobi_theta4m1tau_imp(z, RealType (-log(q)/constants::pi<RealType>()), pol);
  481. }
  482. // Fourth Jacobi theta function, parameterized by q
  483. // = 1 + 2 * SUM q^n^2 * cos(2nz)
  484. template <class RealType, class Policy>
  485. inline RealType
  486. jacobi_theta4_imp(RealType z, RealType q, const Policy& pol, const char *function) {
  487. BOOST_MATH_STD_USING
  488. if (q <= 0.0 || q >= 1.0) {
  489. return policies::raise_domain_error<RealType>(function,
  490. "|q| must be greater than zero and less than 1, but got %1%.", q, pol);
  491. }
  492. return jacobi_theta4tau_imp(z, RealType(-log(q)/constants::pi<RealType>()), pol, function);
  493. }
  494. // Begin public API
  495. template <class T, class U, class Policy>
  496. inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau, const Policy&) {
  497. BOOST_FPU_EXCEPTION_GUARD
  498. typedef typename tools::promote_args<T, U>::type result_type;
  499. typedef typename policies::normalise<
  500. Policy,
  501. policies::promote_float<false>,
  502. policies::promote_double<false>,
  503. policies::discrete_quantile<>,
  504. policies::assert_undefined<> >::type forwarding_policy;
  505. static const char* function = "boost::math::jacobi_theta1tau<%1%>(%1%)";
  506. return policies::checked_narrowing_cast<result_type, Policy>(
  507. jacobi_theta1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
  508. forwarding_policy(), function), function);
  509. }
  510. template <class T, class U>
  511. inline typename tools::promote_args<T, U>::type jacobi_theta1tau(T z, U tau) {
  512. return jacobi_theta1tau(z, tau, policies::policy<>());
  513. }
  514. template <class T, class U, class Policy>
  515. inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q, const Policy&) {
  516. BOOST_FPU_EXCEPTION_GUARD
  517. typedef typename tools::promote_args<T, U>::type result_type;
  518. typedef typename policies::normalise<
  519. Policy,
  520. policies::promote_float<false>,
  521. policies::promote_double<false>,
  522. policies::discrete_quantile<>,
  523. policies::assert_undefined<> >::type forwarding_policy;
  524. static const char* function = "boost::math::jacobi_theta1<%1%>(%1%)";
  525. return policies::checked_narrowing_cast<result_type, Policy>(
  526. jacobi_theta1_imp(static_cast<result_type>(z), static_cast<result_type>(q),
  527. forwarding_policy(), function), function);
  528. }
  529. template <class T, class U>
  530. inline typename tools::promote_args<T, U>::type jacobi_theta1(T z, U q) {
  531. return jacobi_theta1(z, q, policies::policy<>());
  532. }
  533. template <class T, class U, class Policy>
  534. inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau, const Policy&) {
  535. BOOST_FPU_EXCEPTION_GUARD
  536. typedef typename tools::promote_args<T, U>::type result_type;
  537. typedef typename policies::normalise<
  538. Policy,
  539. policies::promote_float<false>,
  540. policies::promote_double<false>,
  541. policies::discrete_quantile<>,
  542. policies::assert_undefined<> >::type forwarding_policy;
  543. static const char* function = "boost::math::jacobi_theta2tau<%1%>(%1%)";
  544. return policies::checked_narrowing_cast<result_type, Policy>(
  545. jacobi_theta2tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
  546. forwarding_policy(), function), function);
  547. }
  548. template <class T, class U>
  549. inline typename tools::promote_args<T, U>::type jacobi_theta2tau(T z, U tau) {
  550. return jacobi_theta2tau(z, tau, policies::policy<>());
  551. }
  552. template <class T, class U, class Policy>
  553. inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q, const Policy&) {
  554. BOOST_FPU_EXCEPTION_GUARD
  555. typedef typename tools::promote_args<T, U>::type result_type;
  556. typedef typename policies::normalise<
  557. Policy,
  558. policies::promote_float<false>,
  559. policies::promote_double<false>,
  560. policies::discrete_quantile<>,
  561. policies::assert_undefined<> >::type forwarding_policy;
  562. static const char* function = "boost::math::jacobi_theta2<%1%>(%1%)";
  563. return policies::checked_narrowing_cast<result_type, Policy>(
  564. jacobi_theta2_imp(static_cast<result_type>(z), static_cast<result_type>(q),
  565. forwarding_policy(), function), function);
  566. }
  567. template <class T, class U>
  568. inline typename tools::promote_args<T, U>::type jacobi_theta2(T z, U q) {
  569. return jacobi_theta2(z, q, policies::policy<>());
  570. }
  571. template <class T, class U, class Policy>
  572. inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(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_theta3m1tau<%1%>(%1%)";
  582. return policies::checked_narrowing_cast<result_type, Policy>(
  583. jacobi_theta3m1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
  584. forwarding_policy()), function);
  585. }
  586. template <class T, class U>
  587. inline typename tools::promote_args<T, U>::type jacobi_theta3m1tau(T z, U tau) {
  588. return jacobi_theta3m1tau(z, tau, policies::policy<>());
  589. }
  590. template <class T, class U, class Policy>
  591. inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau, const Policy&) {
  592. BOOST_FPU_EXCEPTION_GUARD
  593. typedef typename tools::promote_args<T, U>::type result_type;
  594. typedef typename policies::normalise<
  595. Policy,
  596. policies::promote_float<false>,
  597. policies::promote_double<false>,
  598. policies::discrete_quantile<>,
  599. policies::assert_undefined<> >::type forwarding_policy;
  600. static const char* function = "boost::math::jacobi_theta3tau<%1%>(%1%)";
  601. return policies::checked_narrowing_cast<result_type, Policy>(
  602. jacobi_theta3tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
  603. forwarding_policy(), function), function);
  604. }
  605. template <class T, class U>
  606. inline typename tools::promote_args<T, U>::type jacobi_theta3tau(T z, U tau) {
  607. return jacobi_theta3tau(z, tau, policies::policy<>());
  608. }
  609. template <class T, class U, class Policy>
  610. inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q, const Policy&) {
  611. BOOST_FPU_EXCEPTION_GUARD
  612. typedef typename tools::promote_args<T, U>::type result_type;
  613. typedef typename policies::normalise<
  614. Policy,
  615. policies::promote_float<false>,
  616. policies::promote_double<false>,
  617. policies::discrete_quantile<>,
  618. policies::assert_undefined<> >::type forwarding_policy;
  619. static const char* function = "boost::math::jacobi_theta3m1<%1%>(%1%)";
  620. return policies::checked_narrowing_cast<result_type, Policy>(
  621. jacobi_theta3m1_imp(static_cast<result_type>(z), static_cast<result_type>(q),
  622. forwarding_policy(), function), function);
  623. }
  624. template <class T, class U>
  625. inline typename tools::promote_args<T, U>::type jacobi_theta3m1(T z, U q) {
  626. return jacobi_theta3m1(z, q, policies::policy<>());
  627. }
  628. template <class T, class U, class Policy>
  629. inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q, const Policy&) {
  630. BOOST_FPU_EXCEPTION_GUARD
  631. typedef typename tools::promote_args<T, U>::type result_type;
  632. typedef typename policies::normalise<
  633. Policy,
  634. policies::promote_float<false>,
  635. policies::promote_double<false>,
  636. policies::discrete_quantile<>,
  637. policies::assert_undefined<> >::type forwarding_policy;
  638. static const char* function = "boost::math::jacobi_theta3<%1%>(%1%)";
  639. return policies::checked_narrowing_cast<result_type, Policy>(
  640. jacobi_theta3_imp(static_cast<result_type>(z), static_cast<result_type>(q),
  641. forwarding_policy(), function), function);
  642. }
  643. template <class T, class U>
  644. inline typename tools::promote_args<T, U>::type jacobi_theta3(T z, U q) {
  645. return jacobi_theta3(z, q, policies::policy<>());
  646. }
  647. template <class T, class U, class Policy>
  648. inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau, const Policy&) {
  649. BOOST_FPU_EXCEPTION_GUARD
  650. typedef typename tools::promote_args<T, U>::type result_type;
  651. typedef typename policies::normalise<
  652. Policy,
  653. policies::promote_float<false>,
  654. policies::promote_double<false>,
  655. policies::discrete_quantile<>,
  656. policies::assert_undefined<> >::type forwarding_policy;
  657. static const char* function = "boost::math::jacobi_theta4m1tau<%1%>(%1%)";
  658. return policies::checked_narrowing_cast<result_type, Policy>(
  659. jacobi_theta4m1tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
  660. forwarding_policy()), function);
  661. }
  662. template <class T, class U>
  663. inline typename tools::promote_args<T, U>::type jacobi_theta4m1tau(T z, U tau) {
  664. return jacobi_theta4m1tau(z, tau, policies::policy<>());
  665. }
  666. template <class T, class U, class Policy>
  667. inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau, const Policy&) {
  668. BOOST_FPU_EXCEPTION_GUARD
  669. typedef typename tools::promote_args<T, U>::type result_type;
  670. typedef typename policies::normalise<
  671. Policy,
  672. policies::promote_float<false>,
  673. policies::promote_double<false>,
  674. policies::discrete_quantile<>,
  675. policies::assert_undefined<> >::type forwarding_policy;
  676. static const char* function = "boost::math::jacobi_theta4tau<%1%>(%1%)";
  677. return policies::checked_narrowing_cast<result_type, Policy>(
  678. jacobi_theta4tau_imp(static_cast<result_type>(z), static_cast<result_type>(tau),
  679. forwarding_policy(), function), function);
  680. }
  681. template <class T, class U>
  682. inline typename tools::promote_args<T, U>::type jacobi_theta4tau(T z, U tau) {
  683. return jacobi_theta4tau(z, tau, policies::policy<>());
  684. }
  685. template <class T, class U, class Policy>
  686. inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q, const Policy&) {
  687. BOOST_FPU_EXCEPTION_GUARD
  688. typedef typename tools::promote_args<T, U>::type result_type;
  689. typedef typename policies::normalise<
  690. Policy,
  691. policies::promote_float<false>,
  692. policies::promote_double<false>,
  693. policies::discrete_quantile<>,
  694. policies::assert_undefined<> >::type forwarding_policy;
  695. static const char* function = "boost::math::jacobi_theta4m1<%1%>(%1%)";
  696. return policies::checked_narrowing_cast<result_type, Policy>(
  697. jacobi_theta4m1_imp(static_cast<result_type>(z), static_cast<result_type>(q),
  698. forwarding_policy(), function), function);
  699. }
  700. template <class T, class U>
  701. inline typename tools::promote_args<T, U>::type jacobi_theta4m1(T z, U q) {
  702. return jacobi_theta4m1(z, q, policies::policy<>());
  703. }
  704. template <class T, class U, class Policy>
  705. inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q, const Policy&) {
  706. BOOST_FPU_EXCEPTION_GUARD
  707. typedef typename tools::promote_args<T, U>::type result_type;
  708. typedef typename policies::normalise<
  709. Policy,
  710. policies::promote_float<false>,
  711. policies::promote_double<false>,
  712. policies::discrete_quantile<>,
  713. policies::assert_undefined<> >::type forwarding_policy;
  714. static const char* function = "boost::math::jacobi_theta4<%1%>(%1%)";
  715. return policies::checked_narrowing_cast<result_type, Policy>(
  716. jacobi_theta4_imp(static_cast<result_type>(z), static_cast<result_type>(q),
  717. forwarding_policy(), function), function);
  718. }
  719. template <class T, class U>
  720. inline typename tools::promote_args<T, U>::type jacobi_theta4(T z, U q) {
  721. return jacobi_theta4(z, q, policies::policy<>());
  722. }
  723. }}
  724. #endif