reduce z' mod tau' in theta functions to support larger arguments with reasonable performance

This commit is contained in:
Fredrik Johansson 2017-08-25 15:40:57 +02:00
parent 64fd8a8920
commit 380ce57f6a
5 changed files with 152 additions and 10 deletions

View file

@ -64,7 +64,10 @@ int main()
{
acb_set_dddd(z, testdata[i][0], 0.0, testdata[i][1], 0.0);
acb_set_dddd(tau, testdata[i][2], 0.0, testdata[i][3], 0.0);
acb_set_dddd(p2, testdata[i][4], EPS, testdata[i][5], EPS);
if (i == NUM_TESTS - 1) /* sensitive to rounding errors in doubles */
acb_set_dddd(p2, testdata[i][4], 1e-6, testdata[i][5], 1e-6);
else
acb_set_dddd(p2, testdata[i][4], EPS, testdata[i][5], EPS);
acb_elliptic_zeta(p1, z, tau, 2 + n_randint(state, 400));
@ -77,6 +80,18 @@ int main()
flint_printf("p2 = "); acb_printd(p2, 15); flint_printf("\n\n");
flint_abort();
}
acb_elliptic_zeta(p2, z, tau, 2 + n_randint(state, 800));
if (!acb_overlaps(p1, p2))
{
flint_printf("FAIL (test value 2)\n");
flint_printf("tau = "); acb_printd(tau, 15); flint_printf("\n\n");
flint_printf("z = "); acb_printd(z, 15); flint_printf("\n\n");
flint_printf("p1 = "); acb_printd(p1, 15); flint_printf("\n\n");
flint_printf("p2 = "); acb_printd(p2, 15); flint_printf("\n\n");
flint_abort();
}
}
acb_clear(z);

View file

@ -63,7 +63,10 @@ int main()
{
acb_set_dddd(z, testdata[i][0], 0.0, testdata[i][1], 0.0);
acb_set_dddd(tau, testdata[i][2], 0.0, testdata[i][3], 0.0);
acb_set_dddd(p2, testdata[i][4], EPS, testdata[i][5], EPS);
if (i == NUM_TESTS - 1) /* sensitive to rounding errors in doubles */
acb_set_dddd(p2, testdata[i][4], 1e-6, testdata[i][5], 1e-6);
else
acb_set_dddd(p2, testdata[i][4], EPS, testdata[i][5], EPS);
acb_modular_elliptic_p(p1, z, tau, 2 + n_randint(state, 1000));
@ -76,6 +79,18 @@ int main()
flint_printf("p2 = "); acb_printd(p2, 15); flint_printf("\n\n");
flint_abort();
}
acb_modular_elliptic_p(p2, z, tau, 2 + n_randint(state, 1000));
if (!acb_overlaps(p1, p2))
{
flint_printf("FAIL (test value 2)\n");
flint_printf("tau = "); acb_printd(tau, 15); flint_printf("\n\n");
flint_printf("z = "); acb_printd(z, 15); flint_printf("\n\n");
flint_printf("p1 = "); acb_printd(p1, 15); flint_printf("\n\n");
flint_printf("p2 = "); acb_printd(p2, 15); flint_printf("\n\n");
flint_abort();
}
}
acb_clear(z);

View file

@ -140,6 +140,7 @@ acb_modular_theta(acb_t theta1, acb_t theta2,
if (C == 0)
{
acb_set(z_prime, z);
acb_one(A);
}
else
{
@ -157,18 +158,59 @@ acb_modular_theta(acb_t theta1, acb_t theta2,
acb_sqrt(A, A, prec);
/* B = exp(-pi i c z^2/(c*tau+d)) */
/* we first compute the argument here */
if (acb_is_zero(z))
{
acb_one(B);
acb_zero(B);
}
else
{
acb_mul(B, z_prime, z, prec);
acb_mul_fmpz(B, B, &g->c, prec);
acb_exp_pi_i(B, B, prec);
}
}
/* reduce z_prime modulo tau_prime if the imaginary part is large */
if (arf_cmpabs_2exp_si(arb_midref(acb_imagref(z_prime)), 4) > 0)
{
arb_t nn;
arb_init(nn);
arf_div(arb_midref(nn), arb_midref(acb_imagref(z_prime)),
arb_midref(acb_imagref(tau_prime)), prec, ARF_RND_DOWN);
arf_mul_2exp_si(arb_midref(nn), arb_midref(nn), 1);
arf_add_ui(arb_midref(nn), arb_midref(nn), 1, prec, ARF_RND_DOWN);
arf_mul_2exp_si(arb_midref(nn), arb_midref(nn), -1);
arf_floor(arb_midref(nn), arb_midref(nn));
/* transform z_prime further */
acb_submul_arb(z_prime, tau_prime, nn, prec);
/* add -tau n^2 - 2nz to B */
arb_mul_2exp_si(nn, nn, 1);
acb_submul_arb(B, z_prime, nn, prec);
arb_mul_2exp_si(nn, nn, -1);
arb_sqr(nn, nn, prec);
acb_submul_arb(B, tau_prime, nn, prec);
/* theta1, theta4 pick up factors (-1)^n */
if (!arf_is_int_2exp_si(arb_midref(nn), 1))
{
int i;
for (i = 0; i < 4; i++)
{
if (S[i] == 0 || S[i] == 3)
R[i] += 4;
}
}
C = 1;
arb_clear(nn);
}
if (C != 0)
acb_exp_pi_i(B, B, prec);
/* compute q_{1/4}, q */
acb_mul_2exp_si(q4, tau_prime, -2);
acb_exp_pi_i(q4, q4, prec);

View file

@ -64,7 +64,7 @@ acb_modular_theta_jet(acb_ptr theta1, acb_ptr theta2,
acb_t z_prime, tau_prime, q, q4, w, A;
acb_ptr B;
acb_ptr thetas[4];
int w_is_unit, R[4], S[4], C;
int w_is_unit, R[4], S[4], C, rescale;
slong k;
if (len == 0)
@ -85,7 +85,8 @@ acb_modular_theta_jet(acb_ptr theta1, acb_ptr theta2,
acb_modular_fundamental_domain_approx(tau_prime, g, tau,
one_minus_eps, prec);
if (psl2z_is_one(g))
if (psl2z_is_one(g) &&
arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 4) <= 0)
{
acb_modular_theta_jet_notransform(theta1, theta2, theta3, theta4,
z, tau, len, prec);
@ -110,9 +111,13 @@ acb_modular_theta_jet(acb_ptr theta1, acb_ptr theta2,
if (C == 0)
{
acb_set(z_prime, z);
acb_one(A);
rescale = 0;
}
else
{
rescale = 1;
/* B = 1/(c*tau+d) (temporarily) */
acb_mul_fmpz(B, tau, &g->c, prec);
acb_add_fmpz(B, B, &g->d, prec);
@ -144,10 +149,73 @@ acb_modular_theta_jet(acb_ptr theta1, acb_ptr theta2,
acb_mul(B, z_prime, z, prec);
acb_mul_fmpz(B, B, &g->c, prec);
/* B = exp(-pi i c (z+x)^2/(c*tau+d)) */
_acb_poly_exp_pi_i_series(B, B, FLINT_MIN(len, 3), len, prec);
/* we will have B = exp(-pi i c (z+x)^2/(c*tau+d))
after computing the exponential later */
}
/* reduce z_prime modulo tau_prime if the imaginary part is large */
if (arf_cmpabs_2exp_si(arb_midref(acb_imagref(z_prime)), 4) > 0)
{
arb_t nn;
arb_init(nn);
arf_div(arb_midref(nn), arb_midref(acb_imagref(z_prime)),
arb_midref(acb_imagref(tau_prime)), prec, ARF_RND_DOWN);
arf_mul_2exp_si(arb_midref(nn), arb_midref(nn), 1);
arf_add_ui(arb_midref(nn), arb_midref(nn), 1, prec, ARF_RND_DOWN);
arf_mul_2exp_si(arb_midref(nn), arb_midref(nn), -1);
arf_floor(arb_midref(nn), arb_midref(nn));
/* transform z_prime further */
acb_submul_arb(z_prime, tau_prime, nn, prec);
/* add -tau n^2 - 2n(z+x)' to B */
arb_mul_2exp_si(nn, nn, 1);
acb_submul_arb(B, z_prime, nn, prec);
if (len >= 2)
{
acb_t u;
acb_init(u);
/* the x picks up a factor -1/(tau*c+d) */
if (rescale)
{
acb_mul_fmpz(u, tau, &g->c, prec);
acb_add_fmpz(u, u, &g->d, prec);
acb_inv(u, u, prec);
acb_neg(u, u);
acb_mul_arb(u, u, nn, prec);
acb_sub(B + 1, B + 1, u, prec);
}
else
{
acb_sub_arb(B + 1, B + 1, nn, prec);
}
acb_clear(u);
}
arb_mul_2exp_si(nn, nn, -1);
arb_sqr(nn, nn, prec);
acb_submul_arb(B, tau_prime, nn, prec);
/* theta1, theta4 pick up factors (-1)^n */
if (!arf_is_int_2exp_si(arb_midref(nn), 1))
{
int i;
for (i = 0; i < 4; i++)
{
if (S[i] == 0 || S[i] == 3)
R[i] += 4;
}
}
C = 1;
arb_clear(nn);
}
if (C != 0)
_acb_poly_exp_pi_i_series(B, B, FLINT_MIN(len, 3), len, prec);
/* compute q_{1/4}, q */
acb_mul_2exp_si(q4, tau_prime, -2);
acb_exp_pi_i(q4, q4, prec);
@ -162,8 +230,9 @@ acb_modular_theta_jet(acb_ptr theta1, acb_ptr theta2,
w, w_is_unit, q, len, prec);
/* correct for change of variables */
if (C != 0)
if (rescale)
{
/* [-1/(tau*c+d)]]^k */
acb_mul_fmpz(z_prime, tau, &g->c, prec);
acb_add_fmpz(z_prime, z_prime, &g->d, prec);
acb_inv(z_prime, z_prime, prec);

View file

@ -427,6 +427,7 @@ To avoid confusion, we only write `q^k` when `k` is an integer.
Evaluates the Jacobi theta functions `\theta_i(z,\tau)`, `i = 1, 2, 3, 4`
simultaneously. This function moves `\tau` to the fundamental domain
and then also reduces `z` modulo `\tau`
before calling :func:`acb_modular_theta_sum`.
.. function:: void acb_modular_theta_jet_notransform(acb_ptr theta1, acb_ptr theta2, acb_ptr theta3, acb_ptr theta4, const acb_t z, const acb_t tau, slong len, slong prec)
@ -437,7 +438,7 @@ To avoid confusion, we only write `q^k` when `k` is an integer.
with respect to *z*, writing the first *len* coefficients in the power
series `\theta_i(z+x,\tau) \in \mathbb{C}[[x]]` to
each respective output variable. The *notransform* version does not
move `\tau` to the fundamental domain during the computation.
move `\tau` to the fundamental domain or reduce `z` during the computation.
The Dedekind eta function
-------------------------------------------------------------------------------