add theta sum and j-invariant evaluation

This commit is contained in:
Fredrik Johansson 2014-10-07 12:59:32 +02:00
parent 969a79e587
commit c94bed5df3
7 changed files with 815 additions and 15 deletions

View file

@ -133,6 +133,12 @@ void acb_modular_addseq_theta(long * exponents, long * aindex, long * bindex, lo
void acb_modular_addseq_eta(long * exponents, long * aindex, long * bindex, long num); void acb_modular_addseq_eta(long * exponents, long * aindex, long * bindex, long num);
void acb_modular_theta_1234_sum(acb_t theta1, acb_t theta2,
acb_t theta3, acb_t theta4,
const acb_t w, int w_is_unit, const acb_t q, long prec);
void acb_modular_j(acb_t z, const acb_t tau, long prec);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

89
acb_modular/j.c Normal file
View file

@ -0,0 +1,89 @@
/*=============================================================================
This file is part of ARB.
ARB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ARB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ARB; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=============================================================================*/
/******************************************************************************
Copyright (C) 2014 Fredrik Johansson
******************************************************************************/
#include "acb_modular.h"
void
acb_modular_j(acb_t z, const acb_t tau, long prec)
{
psl2z_t g;
arf_t one_minus_eps;
acb_t tau_prime, t1, t2, t3, t4, w, q;
psl2z_init(g);
arf_init(one_minus_eps);
acb_init(tau_prime);
acb_init(t1);
acb_init(t2);
acb_init(t3);
acb_init(t4);
acb_init(w);
acb_init(q);
arf_set_ui_2exp_si(one_minus_eps, 63, -6);
acb_modular_fundamental_domain_approx(tau_prime, g, tau,
one_minus_eps, prec);
acb_one(w);
acb_exp_pi_i(q, tau_prime, prec);
acb_modular_theta_1234_sum(t1, t2, t3, t4, w, 1, q, prec);
/* theta2 ^ 8 */
acb_mul(t2, t2, t2, prec);
acb_mul(t2, t2, t2, prec);
acb_mul(t2, t2, q, prec);
acb_mul(t2, t2, t2, prec);
/* theta3 ^ 8 */
acb_mul(t3, t3, t3, prec);
acb_mul(t3, t3, t3, prec);
acb_mul(t3, t3, t3, prec);
/* theta4 ^ 8 */
acb_mul(t4, t4, t4, prec);
acb_mul(t4, t4, t4, prec);
acb_mul(t4, t4, t4, prec);
acb_mul(z, t2, t3, prec);
acb_mul(z, z, t4, prec);
acb_add(t2, t2, t3, prec);
acb_add(t2, t2, t4, prec);
acb_cube(t2, t2, prec);
acb_div(z, t2, z, prec);
acb_mul_2exp_si(z, z, 5);
psl2z_clear(g);
arf_clear(one_minus_eps);
acb_clear(tau_prime);
acb_clear(t1);
acb_clear(t2);
acb_clear(t3);
acb_clear(t4);
acb_clear(w);
acb_clear(q);
}

145
acb_modular/test/t-j.c Normal file
View file

@ -0,0 +1,145 @@
/*=============================================================================
This file is part of ARB.
ARB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ARB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ARB; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=============================================================================*/
/******************************************************************************
Copyright (C) 2014 Fredrik Johansson
******************************************************************************/
#include "acb_modular.h"
int main()
{
long iter;
flint_rand_t state;
printf("j....");
fflush(stdout);
flint_randinit(state);
/* Test SL2Z invariance */
for (iter = 0; iter < 10000; iter++)
{
acb_t tau1, tau2, z1, z2;
long e0, prec0, prec1, prec2;
psl2z_t g;
psl2z_init(g);
acb_init(tau1);
acb_init(tau2);
acb_init(z1);
acb_init(z2);
e0 = 1 + n_randint(state, 100);
prec0 = 2 + n_randint(state, 2000);
prec1 = 2 + n_randint(state, 2000);
prec2 = 2 + n_randint(state, 2000);
acb_randtest(tau1, state, prec0, e0);
acb_randtest(tau2, state, prec0, e0);
acb_randtest(z1, state, prec0, e0);
acb_randtest(z2, state, prec0, e0);
psl2z_randtest(g, state, 1 + n_randint(state, 200));
acb_modular_transform(tau2, g, tau1, prec0);
acb_modular_j(z1, tau1, prec1);
acb_modular_j(z2, tau2, prec2);
if (!acb_overlaps(z1, z2))
{
printf("FAIL (overlap)\n");
printf("tau1 = "); acb_print(tau1); printf("\n\n");
printf("tau2 = "); acb_print(tau2); printf("\n\n");
printf("z1 = "); acb_print(z1); printf("\n\n");
printf("z2 = "); acb_print(z2); printf("\n\n");
abort();
}
acb_modular_j(tau1, tau1, prec2);
if (!acb_overlaps(z1, tau1))
{
printf("FAIL (aliasing)\n");
printf("tau1 = "); acb_print(tau1); printf("\n\n");
printf("tau2 = "); acb_print(tau2); printf("\n\n");
printf("z1 = "); acb_print(z1); printf("\n\n");
printf("z2 = "); acb_print(z2); printf("\n\n");
abort();
}
acb_clear(tau1);
acb_clear(tau2);
acb_clear(z1);
acb_clear(z2);
psl2z_clear(g);
}
/* Test special values */
for (iter = 0; iter < 100; iter++)
{
acb_t tau, z;
long prec;
acb_init(tau);
acb_init(z);
prec = 2 + n_randint(state, 2000);
acb_randtest(z, state, prec, 10);
acb_onei(tau);
acb_modular_j(z, tau, prec);
acb_sub_ui(z, z, 1728, prec);
if (!acb_contains_zero(z))
{
printf("FAIL (value 1)\n");
printf("tau = "); acb_print(tau); printf("\n\n");
printf("z = "); acb_print(z); printf("\n\n");
abort();
}
acb_set_ui(tau, 2);
acb_div_ui(tau, tau, 3, prec);
acb_exp_pi_i(tau, tau, prec);
acb_modular_j(z, tau, prec);
if (!acb_contains_zero(z))
{
printf("FAIL (value 2)\n");
printf("tau = "); acb_print(tau); printf("\n\n");
printf("z = "); acb_print(z); printf("\n\n");
abort();
}
acb_clear(tau);
acb_clear(z);
}
flint_randclear(state);
flint_cleanup();
printf("PASS\n");
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,123 @@
/*=============================================================================
This file is part of ARB.
ARB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ARB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ARB; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=============================================================================*/
/******************************************************************************
Copyright (C) 2014 Fredrik Johansson
******************************************************************************/
#include "acb_modular.h"
int main()
{
long iter;
flint_rand_t state;
printf("theta_1234_sum....");
fflush(stdout);
flint_randinit(state);
/* Very weak test, just testing the error bounds and not
that we compute the right functions */
for (iter = 0; iter < 10000; iter++)
{
acb_t t1a, t1b, t2a, t2b, t3a, t3b, t4a, t4b, w, q;
int w_is_unit;
long prec0, e0, prec1, prec2;
acb_init(t1a);
acb_init(t1b);
acb_init(t2a);
acb_init(t2b);
acb_init(t3a);
acb_init(t3b);
acb_init(t4a);
acb_init(t4b);
acb_init(w);
acb_init(q);
e0 = 1 + n_randint(state, 100);
prec0 = 2 + n_randint(state, 3000);
prec1 = 2 + n_randint(state, 3000);
prec2 = 2 + n_randint(state, 3000);
if (n_randint(state, 2))
{
arb_randtest(acb_realref(q), state, prec0, e0);
arb_zero(acb_imagref(q));
acb_exp_pi_i(w, q, prec0);
w_is_unit = n_randint(state, 2);
}
else
{
acb_randtest(w, state, prec0, e0);
w_is_unit = 0;
}
acb_randtest(q, state, prec0, e0);
acb_randtest(t1a, state, prec0, e0);
acb_randtest(t1b, state, prec0, e0);
acb_randtest(t2a, state, prec0, e0);
acb_randtest(t2b, state, prec0, e0);
acb_randtest(t3a, state, prec0, e0);
acb_randtest(t3b, state, prec0, e0);
acb_randtest(t4a, state, prec0, e0);
acb_randtest(t4b, state, prec0, e0);
acb_modular_theta_1234_sum(t1a, t2a, t3a, t4a, w, w_is_unit, q, prec1);
acb_modular_theta_1234_sum(t1b, t2b, t3b, t4b, w, w_is_unit & n_randint(state, 2), q, prec2);
if (!acb_overlaps(t1a, t1b) || !acb_overlaps(t2a, t2b)
|| !acb_overlaps(t3a, t3b) || !acb_overlaps(t4a, t4b))
{
printf("FAIL (overlap)\n");
printf("q = "); acb_print(q); printf("\n\n");
printf("w = "); acb_print(w); printf("\n\n");
printf("t1a = "); acb_print(t1a); printf("\n\n");
printf("t1b = "); acb_print(t1b); printf("\n\n");
printf("t2a = "); acb_print(t2a); printf("\n\n");
printf("t2b = "); acb_print(t2b); printf("\n\n");
printf("t3a = "); acb_print(t3a); printf("\n\n");
printf("t3b = "); acb_print(t3b); printf("\n\n");
printf("t4a = "); acb_print(t4a); printf("\n\n");
printf("t4b = "); acb_print(t4b); printf("\n\n");
abort();
}
acb_clear(t1a);
acb_clear(t1b);
acb_clear(t2a);
acb_clear(t2b);
acb_clear(t3a);
acb_clear(t3b);
acb_clear(t4a);
acb_clear(t4b);
acb_clear(w);
acb_clear(q);
}
flint_randclear(state);
flint_cleanup();
printf("PASS\n");
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,358 @@
/*=============================================================================
This file is part of ARB.
ARB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ARB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ARB; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=============================================================================*/
/******************************************************************************
Copyright (C) 2014 Fredrik Johansson
******************************************************************************/
#include "acb_modular.h"
static void
acb_mul_approx(acb_t z, acb_t tmp1, acb_t tmp2, const acb_t x, const acb_t y, long wprec, long prec)
{
if (prec <= 1024)
{
acb_mul(z, x, y, wprec);
}
else if (x == y)
{
acb_set_round(tmp1, x, wprec);
acb_mul(z, tmp1, tmp1, wprec);
}
else
{
acb_set_round(tmp1, x, wprec);
acb_set_round(tmp2, y, wprec);
acb_mul(z, tmp1, tmp2, wprec);
}
}
void mag_sub_lower(mag_t z, const mag_t x, const mag_t y);
double
mag_get_log2_d_approx(const mag_t x)
{
if (mag_is_zero(x))
{
return COEFF_MIN;
}
else if (mag_is_inf(x))
{
return COEFF_MAX;
}
else if (COEFF_IS_MPZ(MAG_EXP(x)))
{
if (fmpz_sgn(MAG_EXPREF(x)) < 0)
return COEFF_MIN;
else
return COEFF_MAX;
}
else
{
long e = MAG_EXP(x);
if (e < -20 || e > 20)
return e;
else
return e + 1.4426950408889634074 *
mag_d_log_upper_bound(MAG_MAN(x) * ldexp(1.0, -MAG_BITS));
}
}
void
acb_modular_theta_1234_sum(acb_t theta1, acb_t theta2,
acb_t theta3, acb_t theta4,
const acb_t w, int w_is_unit, const acb_t q, long prec)
{
mag_t err, qmag, wmag, vmag;
double log2q_approx, log2w_approx, log2term_approx;
long e, e1, e2, k, k1, k2, N, WN, term_prec;
long *exponents, *aindex, *bindex;
acb_ptr qpow, wpow, vpow;
acb_t tmp1, tmp2, v;
int q_is_real, w_is_one;
q_is_real = arb_is_zero(acb_imagref(q));
w_is_one = acb_is_one(w);
acb_init(tmp1);
acb_init(tmp2);
acb_init(v);
mag_init(err);
mag_init(qmag);
mag_init(wmag);
mag_init(vmag);
if (w_is_one)
acb_one(v);
else
acb_inv(v, w, prec);
acb_get_mag(qmag, q);
log2q_approx = mag_get_log2_d_approx(qmag);
if (w_is_unit)
{
mag_one(wmag);
mag_one(vmag);
log2w_approx = 0.0;
}
else
{
acb_get_mag(wmag, w);
acb_get_mag(vmag, v);
mag_max(wmag, wmag, vmag);
log2w_approx = mag_get_log2_d_approx(wmag);
}
if (log2q_approx >= 0.0)
{
N = 1;
mag_inf(err);
}
else /* Pick N and compute error bound */
{
mag_t den;
mag_init(den);
N = 1;
while (0.05 * N * N < prec)
{
log2term_approx = log2q_approx * ((N+2)*(N+2)/4) + (N+2)*log2w_approx;
if (log2term_approx < -prec - 2)
break;
N++;
}
if (w_is_unit)
{
mag_one(den);
mag_sub_lower(den, den, qmag); /* 1 - |q| is good enough */
}
else /* denominator: 1 - |q|^(floor((N+1)/2)+1) * max(|w|,1/|w|) */
{
mag_pow_ui(err, qmag, (N + 1) / 2 + 1);
mag_mul(err, err, wmag);
mag_one(den);
mag_sub_lower(den, den, err);
}
/* no convergence */
if (mag_is_zero(den))
{
N = 1;
mag_inf(err);
}
else if (w_is_unit)
{
mag_pow_ui(err, qmag, ((N + 2) * (N + 2)) / 4);
mag_div(err, err, den);
mag_mul_2exp_si(err, err, 1);
}
else
{
mag_pow_ui(err, qmag, ((N + 2) * (N + 2)) / 4);
mag_pow_ui(vmag, wmag, N + 2);
mag_mul(err, err, vmag);
mag_div(err, err, den);
mag_mul_2exp_si(err, err, 1);
}
mag_clear(den);
}
exponents = flint_malloc(sizeof(long) * 3 * N);
aindex = exponents + N;
bindex = aindex + N;
qpow = _acb_vec_init(N);
acb_modular_addseq_theta(exponents, aindex, bindex, N);
acb_set_round(qpow + 0, q, prec);
acb_zero(theta1);
acb_zero(theta2);
acb_zero(theta3);
acb_zero(theta4);
WN = (N + 3) / 2;
/* compute powers of w^2 and v = 1/w^2 */
if (!w_is_one)
{
wpow = _acb_vec_init(WN);
vpow = _acb_vec_init(WN + 1);
acb_mul(tmp1, w, w, prec);
acb_mul(tmp2, v, v, prec);
_acb_vec_set_powers(wpow, tmp1, WN, prec);
_acb_vec_set_powers(vpow, tmp2, WN + 1, prec);
}
else
{
wpow = vpow = NULL;
}
for (k = 0; k < N; k++)
{
e = exponents[k];
log2term_approx = e * log2q_approx + (k+2) * log2w_approx;
term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec);
if (k > 0)
{
k1 = aindex[k];
k2 = bindex[k];
e1 = exponents[k1];
e2 = exponents[k2];
if (e == e1 + e2)
{
acb_mul_approx(qpow + k, tmp1, tmp2, qpow + k1, qpow + k2, term_prec, prec);
}
else if (e == 2 * e1 + e2)
{
acb_mul_approx(qpow + k, tmp1, tmp2, qpow + k1, qpow + k1, term_prec, prec);
acb_mul_approx(qpow + k, tmp1, tmp2, qpow + k, qpow + k2, term_prec, prec);
}
else
{
printf("exponent not in addition sequence!\n");
abort();
}
}
if (w_is_one)
{
if (k % 2 == 0)
{
acb_add(theta3, theta3, qpow + k, prec);
if (k % 4 == 0)
acb_sub(theta4, theta4, qpow + k, prec);
else
acb_add(theta4, theta4, qpow + k, prec);
}
else
{
acb_add(theta2, theta2, qpow + k, prec);
}
}
else
{
if (k % 2 == 0)
{
acb_add(tmp1, wpow + k / 2 + 1, vpow + k / 2 + 1, term_prec);
acb_mul(tmp1, qpow + k, tmp1, term_prec);
acb_add(theta3, theta3, tmp1, prec);
if (k % 4 == 0)
acb_sub(theta4, theta4, tmp1, prec);
else
acb_add(theta4, theta4, tmp1, prec);
}
else
{
if (k / 2 + 1 > WN - 1)
abort();
if (k / 2 + 2 > WN + 1 - 1)
abort();
acb_add(tmp1, wpow + k / 2 + 1, vpow + k / 2 + 2, term_prec);
acb_mul(tmp1, qpow + k, tmp1, term_prec);
acb_add(theta2, theta2, tmp1, prec);
acb_sub(tmp1, wpow + k / 2 + 1, vpow + k / 2 + 2, term_prec);
acb_mul(tmp1, qpow + k, tmp1, term_prec);
if (k % 4 == 1)
acb_sub(theta1, theta1, tmp1, prec);
else
acb_add(theta1, theta1, tmp1, prec);
}
}
}
if (w_is_one)
{
acb_mul_2exp_si(theta2, theta2, 1);
acb_mul_2exp_si(theta3, theta3, 1);
acb_mul_2exp_si(theta4, theta4, 1);
acb_add_ui(theta2, theta2, 2, prec);
acb_add_ui(theta3, theta3, 1, prec);
acb_add_ui(theta4, theta4, 1, prec);
}
else
{
/* w * [(1 - w^-2) + series] */
acb_sub(theta1, theta1, vpow + 1, prec);
acb_mul(theta1, theta1, w, prec);
acb_add(theta1, theta1, w, prec);
/* multiply by -i */
acb_mul_onei(theta1, theta1);
acb_neg(theta1, theta1);
/* w * [(1 + w^-2) + series] */
acb_add(theta2, theta2, vpow + 1, prec);
acb_mul(theta2, theta2, w, prec);
acb_add(theta2, theta2, w, prec);
acb_add_ui(theta3, theta3, 1, prec);
acb_add_ui(theta4, theta4, 1, prec);
}
if (q_is_real && w_is_unit) /* result must be real */
{
arb_add_error_mag(acb_realref(theta1), err);
arb_add_error_mag(acb_realref(theta2), err);
arb_add_error_mag(acb_realref(theta3), err);
arb_add_error_mag(acb_realref(theta4), err);
}
else
{
acb_add_error_mag(theta1, err);
acb_add_error_mag(theta2, err);
acb_add_error_mag(theta3, err);
acb_add_error_mag(theta4, err);
}
if (!w_is_one)
{
_acb_vec_clear(wpow, WN);
_acb_vec_clear(vpow, WN + 1);
}
flint_free(exponents);
_acb_vec_clear(qpow, N);
acb_clear(tmp1);
acb_clear(tmp2);
acb_clear(v);
mag_clear(err);
mag_clear(qmag);
mag_clear(wmag);
mag_clear(vmag);
}

View file

@ -32,6 +32,12 @@ arb_sin_pi(arb_t y, const arb_t x, long prec)
arb_t u; arb_t u;
fmpz_t v; fmpz_t v;
if (!arb_is_finite(x))
{
arb_indeterminate(y);
return;
}
if (arf_cmpabs_2exp_si(arb_midref(x), FLINT_MAX(65536, (4*prec))) > 0) if (arf_cmpabs_2exp_si(arb_midref(x), FLINT_MAX(65536, (4*prec))) > 0)
{ {
arf_zero(arb_midref(y)); arf_zero(arb_midref(y));
@ -81,6 +87,12 @@ arb_cos_pi(arb_t y, const arb_t x, long prec)
arb_t u; arb_t u;
fmpz_t v; fmpz_t v;
if (!arb_is_finite(x))
{
arb_indeterminate(y);
return;
}
if (arf_cmpabs_2exp_si(arb_midref(x), FLINT_MAX(65536, (4*prec))) > 0) if (arf_cmpabs_2exp_si(arb_midref(x), FLINT_MAX(65536, (4*prec))) > 0)
{ {
arf_zero(arb_midref(y)); arf_zero(arb_midref(y));
@ -130,6 +142,13 @@ arb_sin_cos_pi(arb_t s, arb_t c, const arb_t x, long prec)
arb_t u; arb_t u;
fmpz_t v; fmpz_t v;
if (!arb_is_finite(x))
{
arb_indeterminate(s);
arb_indeterminate(c);
return;
}
if (arf_cmpabs_2exp_si(arb_midref(x), FLINT_MAX(65536, (4*prec))) > 0) if (arf_cmpabs_2exp_si(arb_midref(x), FLINT_MAX(65536, (4*prec))) > 0)
{ {
arf_zero(arb_midref(s)); arf_zero(arb_midref(s));

View file

@ -130,29 +130,89 @@ Modular transformations
`|\operatorname{Re}(z)| \le 1/2 + \varepsilon` where `\varepsilon` is `|\operatorname{Re}(z)| \le 1/2 + \varepsilon` where `\varepsilon` is
specified by *tol*. Returns zero if this is false or cannot be determined. specified by *tol*. Returns zero if this is false or cannot be determined.
The Dedekind eta function
-------------------------------------------------------------------------------
To be done
.. function:: void acb_modular_addseq_eta(long * exponents, long * aindex, long * bindex, long num)
Constructs an addition sequence for the first *num* generalized pentagonal
numbers (excluding zero), i.e. 1, 2, 5, 7, 12, 15, 22, 26, 35, 40 etc.
Jacobi theta functions Jacobi theta functions
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
To be done
.. function:: void acb_modular_addseq_theta(long * exponents, long * aindex, long * bindex, long num) .. function:: void acb_modular_addseq_theta(long * exponents, long * aindex, long * bindex, long num)
Constructs an addition sequence for the first *num* squares and triangular Constructs an addition sequence for the first *num* squares and triangular
numbers interleaved (excluding zero), i.e. 1, 2, 4, 6, 9, 12, 16, 20, 25, 30 etc. numbers interleaved (excluding zero), i.e. 1, 2, 4, 6, 9, 12, 16, 20, 25, 30 etc.
Eisenstein series .. function:: void acb_modular_theta_1234_sum(acb_t theta1, acb_t theta2, acb_t theta3, acb_t theta4, const acb_t w, int w_is_unit, const acb_t q, long prec)
Simultaneously evaluates
.. math ::
q^{-1/4} \theta_1 = 2 \sum_{n=0}^{\infty} (-1)^n q^{n(n+1)} \sin((2n+1) \pi z)
q^{-1/4} \theta_2 = 2 \sum_{n=0}^{\infty} q^{n(n+1)} \cos((2n+1) \pi z)
\theta_3 = 1 + 2 \sum_{n=1}^{\infty} q^{n^2} \cos(2n \pi z)
\theta_4 = 1 + 2 \sum_{n=1}^{\infty} (-1)^n q^{n^2} \cos(2n \pi z)
given `w = \exp(\pi i z)` and `q = \exp(\pi i \tau)`.
If *w_is_unit* is nonzero, *w* is assumed to lie on the unit circle,
i.e. *z* is assumed to be real.
Note that the factor `q^{1/4}` is removed from `\theta_1` and `\theta_2`.
To get the true theta function values, the user has to multiply
this factor back. This convention avoids an unnecessary root extraction,
since the user can compute `q^{1/4} = \exp(\pi i \tau / 4)` followed by
`q = (q^{1/4})^4`, and in many cases when computing products or quotients
of theta functions, the factor `q^{1/4}` can be eliminated entirely.
This function is intended for `|q| \ll 1`. It can be called with any
`q`, but will return useless intervals if convergence is not rapid.
For general evaluation of theta functions, the user should only call
this function after applying a suitable modular transformation.
We consider the sums together, alternatingly updating `(\theta_1, \theta_2)`
or `(\theta_3, \theta_4)`. For `k = 0, 1, 2, \ldots`, the powers of `q`
are `\lfloor (k+2)^2 / 4 \rfloor = 1, 2, 4, 6, 9` etc. and the powers of `w` are
`\pm (k+2) = \pm 2, \pm 3, \pm 4, \ldots` etc.
For some integer `N \ge 1`, the summation is stopped just before term
`k = N`. The error can then be bounded as
.. math ::
\frac{2 |q|^E \max(|w|,|w^{-1}|)^{N+2}}{1 - |q|^{\lfloor (N+1)/2 \rfloor + 1} \max(|w|,|w^{-1}|)}
where `E = \lfloor (N+2)^2 / 4 \rfloor`, assuming that the denominator
is positive.
This is simply the bound for a geometric series, with the leading
factor 2 coming from the fact that we sum both negative and positive
powers of `w`.
To actually evaluate the series, when `w \ne 1`, we write the even
cosine terms as `w^{2n} + w^{-2n}`, the odd cosine terms as
`w (w^{2n} + w^{-2n-2})`, and the sine terms as `w (w^{2n} - w^{-2n-2})`.
This way we only need even powers of `w` and `w^{-1}`.
The implementation is not yet optimized for real `z`, in which case
further work can be saved.
This function does not permit aliasing between input and output
arguments.
The Dedekind eta function
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
To be done .. function:: void acb_modular_addseq_eta(long * exponents, long * aindex, long * bindex, long num)
Constructs an addition sequence for the first *num* generalized pentagonal
numbers (excluding zero), i.e. 1, 2, 5, 7, 12, 15, 22, 26, 35, 40 etc.
Modular forms
-------------------------------------------------------------------------------
.. function:: void acb_modular_j(acb_t r, const acb_t tau, long prec)
Computes Klein's j-invariant `j(\tau)` given `\tau` in the upper
half-plane. The function is normalized so that `j(i) = 1728`.
We first move `\tau` to the fundamental domain, which does not change
the value of the function. Then we use the formula
`j(\tau) = 32 (\theta_2^8 + \theta_3^8 + \theta_4^8)^3 / (\theta_2 \theta_3 \theta_4)^8`
where `\theta_k` is the respective theta constant evaluated at `\tau`.