-
Notifications
You must be signed in to change notification settings - Fork 248
Jacobi Theta functions #394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
898c3ad
c78dcd7
10fc561
4b6701d
9c68c11
aa382f5
45e8ab9
0d3bc43
c293d48
6b8dd5a
08391cd
d73472e
78fc9e2
98bc16c
2ecdf32
32a4d73
a2499bb
041ca09
3a0e3f3
4630855
cf7ff40
b116c75
9fab61b
fb8d3f3
dd2fcd1
d629f80
ef39393
7ecda0f
8cea3e9
2902061
5bea1e5
46c59f8
c9ac3a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Add tests for small tau (i.e. large q). The tests are failing with mean ~ 200 EPS and max ~ 800 EPS. These look like worst-case input, and should be the focus of future accuracy improvements. This commit also simplifies the _IMAGINARY code by abstracting all of the loops into a single svelte function.
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -180,6 +180,20 @@ _jacobi_theta_converged(RealType result, RealType delta, RealType eps) { | |
| return abs(delta) < eps && (abs(result) == 0.0 || abs(delta/result) < eps); | ||
| } | ||
|
|
||
| template <class RealType> | ||
| inline RealType | ||
| _jacobi_theta_sum(RealType tau, RealType z_n, RealType z_increment, RealType eps) { | ||
| RealType delta, partial_result = 0; | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe precompute People don't realize that elementary special function evaluations are in the same complexity class as division!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're going to squeeze out divisions like that, it might make sense to divide |
||
| partial_result += delta; | ||
| z_n += z_increment; | ||
| } while (!_jacobi_theta_converged(partial_result, delta, eps)); | ||
|
|
||
| return partial_result; | ||
| } | ||
|
|
||
| // The following _IMAGINARY theta functions assume imaginary z and are for | ||
| // internal use only. They are designed to increase accuracy and reduce the | ||
| // number of iterations required for convergence for large |q|. The z argument | ||
|
|
@@ -196,42 +210,17 @@ template <class RealType, class Policy> | |
| inline RealType | ||
| _IMAGINARY_jacobi_theta1tau(RealType z, RealType tau, const Policy& pol) { | ||
| BOOST_MATH_STD_USING | ||
| unsigned n = 0; | ||
| RealType eps = policies::get_epsilon<RealType, Policy>(); | ||
| RealType delta, result = RealType(0); | ||
|
|
||
| RealType result1 = RealType(0); | ||
| RealType result2 = RealType(0); | ||
|
|
||
| RealType z_n = z + constants::half_pi<RealType>(); | ||
| n = 0; | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
| if (n%2) { | ||
| result1 -= delta; | ||
| } else { | ||
| result1 += delta; | ||
| } | ||
| z_n += constants::pi<RealType>(); | ||
| n++; | ||
| } while (!_jacobi_theta_converged(result1, delta, eps)); | ||
|
|
||
| z_n = z - constants::half_pi<RealType>(); | ||
| n = 1; | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
| if (n%2) { | ||
| result2 -= delta; | ||
| } else { | ||
| result2 += delta; | ||
| } | ||
| z_n -= constants::pi<RealType>(); | ||
| n++; | ||
| } while (!_jacobi_theta_converged(result2, delta, eps)); | ||
| RealType result = RealType(0); | ||
|
|
||
| result -= result1 + result2; | ||
| // n>=0 even | ||
| result -= _jacobi_theta_sum(tau, z + constants::half_pi<RealType>(), constants::two_pi<RealType>(), eps); | ||
| // n>0 odd | ||
| result += _jacobi_theta_sum(tau, z + constants::half_pi<RealType>() + constants::pi<RealType>(), constants::two_pi<RealType>(), eps); | ||
| // n<0 odd | ||
| result += _jacobi_theta_sum(tau, z - constants::half_pi<RealType>(), -constants::two_pi<RealType>(), eps); | ||
| // n<0 even | ||
| result -= _jacobi_theta_sum(tau, z - constants::half_pi<RealType>() - constants::pi<RealType>(), -constants::two_pi<RealType>(), eps); | ||
|
|
||
| return result * sqrt(tau); | ||
| } | ||
|
|
@@ -241,28 +230,12 @@ inline RealType | |
| _IMAGINARY_jacobi_theta2tau(RealType z, RealType tau, const Policy& pol) { | ||
| BOOST_MATH_STD_USING | ||
| RealType eps = policies::get_epsilon<RealType, Policy>(); | ||
| RealType delta, result = RealType(0); | ||
|
|
||
| RealType result1 = RealType(0); | ||
| RealType result2 = RealType(0); | ||
| RealType result = RealType(0); | ||
|
|
||
| RealType z_n = z + constants::half_pi<RealType>(); | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
| result1 += delta; | ||
| z_n += constants::pi<RealType>(); | ||
| } while (!_jacobi_theta_converged(result1, delta, eps)); | ||
|
|
||
| z_n = z - constants::half_pi<RealType>(); | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
| result2 += delta; | ||
| z_n -= constants::pi<RealType>(); | ||
| } while (!_jacobi_theta_converged(result2, delta, eps)); | ||
|
|
||
| result += result1 + result2; | ||
| // n>=0 | ||
| result += _jacobi_theta_sum(tau, z + constants::half_pi<RealType>(), constants::pi<RealType>(), eps); | ||
| // n<0 | ||
| result += _jacobi_theta_sum(tau, z - constants::half_pi<RealType>(), -constants::pi<RealType>(), eps); | ||
|
|
||
| return result * sqrt(tau); | ||
| } | ||
|
|
@@ -272,28 +245,14 @@ inline RealType | |
| _IMAGINARY_jacobi_theta3tau(RealType z, RealType tau, const Policy& pol) { | ||
| BOOST_MATH_STD_USING | ||
| RealType eps = policies::get_epsilon<RealType, Policy>(); | ||
| RealType delta, result = exp(-z*z*tau/constants::pi<RealType>()); | ||
|
|
||
| RealType result1 = RealType(0); | ||
| RealType result2 = RealType(0); | ||
|
|
||
| RealType z_n = z + constants::pi<RealType>(); | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
| result1 += delta; | ||
| z_n += constants::pi<RealType>(); | ||
| } while (!_jacobi_theta_converged(result1, delta, eps)); | ||
|
|
||
| z_n = z - constants::pi<RealType>(); | ||
| RealType result = 0; | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
| result2 += delta; | ||
| z_n -= constants::pi<RealType>(); | ||
| } while (!_jacobi_theta_converged(result2, delta, eps)); | ||
|
|
||
| result += result1 + result2; | ||
| // n=0 | ||
| result += exp(-z*z*tau/constants::pi<RealType>()); | ||
| // n>0 | ||
| result += _jacobi_theta_sum(tau, z + constants::pi<RealType>(), constants::pi<RealType>(), eps); | ||
| // n<0 | ||
| result += _jacobi_theta_sum(tau, z - constants::pi<RealType>(), -constants::pi<RealType>(), eps); | ||
|
|
||
| return result * sqrt(tau); | ||
| } | ||
|
|
@@ -302,42 +261,20 @@ template <class RealType, class Policy> | |
| inline RealType | ||
| _IMAGINARY_jacobi_theta4tau(RealType z, RealType tau, const Policy& pol) { | ||
| BOOST_MATH_STD_USING | ||
| unsigned n = 1; | ||
| RealType eps = policies::get_epsilon<RealType, Policy>(); | ||
| RealType delta, result = exp(-z*z*tau/constants::pi<RealType>()); | ||
|
|
||
| RealType result1 = RealType(0); | ||
| RealType result2 = RealType(0); | ||
|
|
||
| RealType z_n = z + constants::pi<RealType>(); | ||
| n = 1; | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
| if (n%2) { | ||
| result1 -= delta; | ||
| } else { | ||
| result1 += delta; | ||
| } | ||
| z_n += constants::pi<RealType>(); | ||
| n++; | ||
| } while (!_jacobi_theta_converged(result1, delta, eps)); | ||
|
|
||
| z_n = z - constants::pi<RealType>(); | ||
| n = 1; | ||
|
|
||
| do { | ||
| delta = exp(-tau*z_n*z_n/constants::pi<RealType>()); | ||
| if (n%2) { | ||
| result2 -= delta; | ||
| } else { | ||
| result2 += delta; | ||
| } | ||
| z_n -= constants::pi<RealType>(); | ||
| n++; | ||
| } while (!_jacobi_theta_converged(result2, delta, eps)); | ||
|
|
||
| result += result1 + result2; | ||
| RealType result = 0; | ||
|
|
||
| // n = 0 | ||
| result += exp(-z*z*tau/constants::pi<RealType>()); | ||
|
|
||
| // n > 0 odd | ||
| result -= _jacobi_theta_sum(tau, z + constants::pi<RealType>(), constants::two_pi<RealType>(), eps); | ||
| // n < 0 odd | ||
| result -= _jacobi_theta_sum(tau, z - constants::pi<RealType>(), -constants::two_pi<RealType>(), eps); | ||
| // n > 0 even | ||
| result += _jacobi_theta_sum(tau, z + constants::two_pi<RealType>(), constants::two_pi<RealType>(), eps); | ||
| // n < 0 even | ||
| result += _jacobi_theta_sum(tau, z - constants::two_pi<RealType>(), -constants::two_pi<RealType>(), eps); | ||
|
|
||
| return result * sqrt(tau); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.