#include "pari.h"
#include "paripriv.h"
static const long EXTRA_PREC = DEFAULTPREC-2;
typedef struct {
GEN L0, L1, L11, L2;
GEN L1ray, L11ray;
GEN rayZ;
long condZ;
} LISTray;
typedef struct {
long ord;
GEN *val, chi;
} CHI_t;
typedef struct {
GEN M, beta, B, U, nB;
long v, G, N;
} RC_data;
static GEN
chi_get_c(GEN chi) { return gmael(chi,1,2); }
static GEN
chi_get_gdeg(GEN chi) { return gmael(chi,1,1); }
static long
chi_get_deg(GEN chi) { return itou(chi_get_gdeg(chi)); }
static ulong
CharEval_n(GEN chi, GEN logelt)
{
GEN gn = ZV_dotproduct(chi_get_c(chi), logelt);
return umodiu(gn, chi_get_deg(chi));
}
static GEN
CharEval(GEN chi, GEN logelt)
{
ulong n = CharEval_n(chi, logelt), d = chi_get_deg(chi);
long nn = Fl_center(n,d,d>>1);
GEN x = gel(chi,2);
x = gpowgs(x, labs(nn));
if (nn < 0) x = conj_i(x);
return x;
}
static ulong
CHI_eval_n(CHI_t *C, GEN logelt)
{
GEN n = ZV_dotproduct(C->chi, logelt);
return umodiu(n, C->ord);
}
static GEN
CHI_eval(CHI_t *C, GEN logelt)
{
return C->val[CHI_eval_n(C, logelt)];
}
static void
init_CHI(CHI_t *c, GEN CHI, GEN z)
{
long i, d = chi_get_deg(CHI);
GEN *v = (GEN*)new_chunk(d);
v[0] = gen_1;
if (d != 1)
{
v[1] = z;
for (i=2; i<d; i++) v[i] = gmul(v[i-1], z);
}
c->chi = chi_get_c(CHI);
c->ord = d;
c->val = v;
}
static void
init_CHI_alg(CHI_t *c, GEN CHI) {
long d = chi_get_deg(CHI);
GEN z;
switch(d)
{
case 1: z = gen_1; break;
case 2: z = gen_m1; break;
default: z = mkpolmod(pol_x(0), polcyclo(d,0));
}
init_CHI(c,CHI, z);
}
static void
init_CHI_C(CHI_t *c, GEN CHI) {
init_CHI(c,CHI, gel(CHI,2));
}
typedef struct {
long r;
GEN j;
GEN cyc;
} GROUP_t;
static int
NextElt(GROUP_t *G)
{
long i = 1;
if (G->r == 0) return 0;
while (++G->j[i] == G->cyc[i])
{
G->j[i] = 0;
if (++i > G->r) return 0;
}
return i;
}
static GEN
EltsOfGroup(long order, GEN cyc)
{
long i;
GEN rep;
GROUP_t G;
G.cyc = gtovecsmall(cyc);
G.r = lg(cyc)-1;
G.j = zero_zv(G.r);
rep = cgetg(order + 1, t_VEC);
gel(rep,order) = vecsmall_to_col(G.j);
for (i = 1; i < order; i++)
{
(void)NextElt(&G);
gel(rep,i) = vecsmall_to_col(G.j);
}
return rep;
}
GEN
cyc2elts(GEN cyc)
{
long i, n;
GEN z;
GROUP_t G;
G.cyc = typ(cyc)==t_VECSMALL? cyc: gtovecsmall(cyc);
n = zv_prod(G.cyc);
G.r = lg(cyc)-1;
G.j = zero_zv(G.r);
z = cgetg(n+1, t_VEC);
gel(z,n) = leafcopy(G.j);
for (i = 1; i < n; i++)
{
(void)NextElt(&G);
gel(z,i) = leafcopy(G.j);
}
return z;
}
static GEN
ComputeLift(GEN Qt)
{
GEN e, U = gel(Qt,3);
long i, h = itos(gel(Qt,1));
e = EltsOfGroup(h, gel(Qt,2));
if (!RgM_isidentity(U))
{
GEN Ui = ZM_inv(U,NULL);
for (i = 1; i <= h; i++) gel(e,i) = ZM_ZC_mul(Ui, gel(e,i));
}
return e;
}
static GEN
get_Char(GEN nchi, long prec)
{ return mkvec2(nchi, rootsof1_cx(gel(nchi,1), prec)); }
static GEN
divcond(GEN bnr) {GEN bid = bnr_get_bid(bnr); return gel(bid_get_fact(bid),1);}
static GEN
get_prdiff(GEN bnr, GEN condc)
{
GEN prdiff, M = gel(condc,1), D = divcond(bnr), nf = bnr_get_nf(bnr);
long nd, i, l = lg(D);
prdiff = cgetg(l, t_COL);
for (nd=1, i=1; i < l; i++)
if (!idealval(nf, M, gel(D,i))) gel(prdiff,nd++) = gel(D,i);
setlg(prdiff, nd); return prdiff;
}
#define ch_C(x) gel(x,1)
#define ch_bnr(x) gel(x,2)
#define ch_4(x) gel(x,3)
#define ch_CHI(x) gel(x,4)
#define ch_diff(x) gel(x,5)
#define ch_cond(x) gel(x,6)
#define ch_CHI0(x) gel(x,7)
#define ch_comp(x) gel(x,8)
static long
ch_deg(GEN dtcr) { return chi_get_deg(ch_CHI(dtcr)); }
static GEN
GetDeg(GEN dataCR)
{
long i, l = lg(dataCR);
GEN degs = cgetg(l, t_VECSMALL);
for (i = 1; i < l; i++) degs[i] = eulerphiu(ch_deg(gel(dataCR,i)));
return degs;
}
static GEN AllStark(GEN data, GEN nf, long flag, long prec);
static GEN
InitQuotient(GEN C)
{
GEN U, D = ZM_snfall_i(C, &U, NULL, 1), h = ZV_prod(D);
return mkvec5(h, D, U, C, cyc_normalize(D));
}
static GEN
LiftChar(GEN Qt, GEN cyc, GEN chi)
{
GEN ncyc = gel(Qt,5), U = gel(Qt,3);
GEN nchi = char_normalize(chi, ncyc);
GEN c = ZV_ZM_mul(gel(nchi,2), U), d = gel(nchi,1);
return char_denormalize(cyc, d, c);
}
static GEN
ComputeKernel0(GEN P, GEN cycA, GEN cycB)
{
pari_sp av = avma;
long nbA = lg(cycA)-1, rk;
GEN U, DB = diagonal_shallow(cycB);
rk = nbA + lg(cycB) - lg(ZM_hnfall_i(shallowconcat(P, DB), &U, 1));
U = matslice(U, 1,nbA, 1,rk);
return gerepileupto(av, ZM_hnfmodid(U, cycA));
}
static GEN
ComputeKernel(GEN bnrm, GEN bnrn, GEN dtQ)
{
pari_sp av = avma;
GEN P = ZM_mul(gel(dtQ,3), bnrsurjection(bnrm, bnrn));
return gerepileupto(av, ComputeKernel0(P, bnr_get_cyc(bnrm), gel(dtQ,2)));
}
static long
cyc_is_cyclic(GEN cyc) { return lg(cyc) <= 2 || equali1(gel(cyc,2)); }
static long
IsGoodSubgroup(GEN H, GEN bnr, GEN map)
{
pari_sp av = avma;
GEN mod, modH, p1, p2, U, P, PH, bnrH, iH, qH;
long j;
p1 = InitQuotient(H);
if (!cyc_is_cyclic(gel(p1,2))) { avma = av; return 0; }
p2 = ZM_hnfall_i(shallowconcat(map,H), &U, 0);
setlg(U, lg(H));
for (j = 1; j < lg(U); j++) setlg(gel(U,j), lg(H));
p1 = ZM_hnfmodid(U, bnr_get_cyc(bnr));
modH = bnrconductor_i(bnr, p1, 0);
mod = bnr_get_mod(bnr);
if (!gequal(gel(modH,2), gel(mod,2))) { avma = av; return 0; }
if (gequal(gel(modH,1), gel(mod,1))) { avma = av; return 1; }
bnrH = Buchray(bnr, modH, nf_INIT);
P = divcond(bnr);
PH = divcond(bnrH);
p2 = ZM_mul(bnrsurjection(bnr, bnrH), p1);
iH = ZM_hnfmodid(p2, bnr_get_cyc(bnrH));
qH = InitQuotient(iH);
for (j = 1; j < lg(P); j++)
{
GEN pr = gel(P, j), e;
if (tablesearch(PH, pr, cmp_prime_ideal)) continue;
e = ZM_ZC_mul(gel(qH,3), isprincipalray(bnrH, pr));
e = vecmodii(e, gel(qH,2));
if (ZV_equal0(e)) { avma = av; return 0; }
}
avma = av; return 1;
}
static GEN
get_listCR(GEN bnr, GEN dtQ)
{
GEN listCR, vecchi, Mr;
long hD, h, nc, i, tnc;
hashtable *S;
Mr = bnr_get_cyc(bnr);
hD = itos(gel(dtQ,1));
h = hD >> 1;
listCR = cgetg(h+1, t_VEC);
nc = tnc = 1;
vecchi = EltsOfGroup(hD, gel(dtQ,2));
S = hash_create(h, (ulong(*)(void*))&hash_GEN,
(int(*)(void*,void*))&ZV_equal, 1);
for (i = 1; tnc <= h; i++)
{
GEN cond, lchi = LiftChar(dtQ, Mr, gel(vecchi,i));
if (hash_search(S, lchi)) continue;
cond = bnrconductorofchar(bnr, lchi);
if (gequal0(gel(cond,2))) continue;
gel(listCR,nc++) = mkvec2(lchi, cond);
if (absequaliu(charorder(Mr,lchi), 2)) tnc++;
else
{
hash_insert(S, charconj(Mr, lchi), (void*)1);
tnc+=2;
}
}
setlg(listCR, nc); return listCR;
}
static GEN InitChar(GEN bnr, GEN listCR, long prec);
static long
CplxModulus(GEN data, long *newprec)
{
long pr, ex, dprec = DEFAULTPREC;
pari_sp av;
GEN pol, listCR, cpl, bnr = gel(data,1), nf = checknf(bnr);
listCR = get_listCR(bnr, gel(data,3));
for (av = avma;; avma = av)
{
gel(data,5) = InitChar(bnr, listCR, dprec);
pol = AllStark(data, nf, -1, dprec);
pr = nbits2extraprec( gexpo(pol) );
if (pr < 0) pr = 0;
dprec = maxss(dprec, pr) + EXTRA_PREC;
if (!gequal0(leading_coeff(pol)))
{
cpl = RgX_fpnorml2(pol, DEFAULTPREC);
if (!gequal0(cpl)) break;
}
if (DEBUGLEVEL>1) pari_warn(warnprec, "CplxModulus", dprec);
}
ex = gexpo(cpl); avma = av;
if (DEBUGLEVEL>1) err_printf("cpl = 2^%ld\n", ex);
gel(data,5) = listCR;
*newprec = dprec; return ex;
}
static GEN
subgp_intersect(GEN cyc, GEN A, GEN B)
{
GEN H, U;
long k, lH;
if (!A) return B;
if (!B) return A;
H = ZM_hnfall_i(shallowconcat(A,B), &U, 1);
setlg(U, lg(A)); lH = lg(H);
for (k = 1; k < lg(U); k++) setlg(gel(U,k), lH);
return ZM_hnfmodid(ZM_mul(A,U), cyc);
}
static GEN
FindModulus(GEN bnr, GEN dtQ, long *newprec)
{
const long limnorm = 400;
long n, i, narch, maxnorm, minnorm, N;
long first = 1, pr, rb, oldcpl = -1, iscyc;
pari_sp av = avma;
GEN bnf, nf, f, arch, m, rep = NULL;
bnf = bnr_get_bnf(bnr);
nf = bnf_get_nf(bnf);
N = nf_get_degree(nf);
f = gel(bnr_get_mod(bnr), 1);
rb = expi( powii(mulii(nf_get_disc(nf), ZM_det_triangular(f)), gmul2n(bnr_get_no(bnr), 3)) );
arch = const_vec(N, gen_1);
narch = N;
m = mkvec2(NULL, arch);
maxnorm = 50;
minnorm = 1;
iscyc = cyc_is_cyclic(gel(dtQ,2));
if (DEBUGLEVEL>1)
err_printf("Looking for a modulus of norm: ");
for(;;)
{
GEN listid = ideallist0(nf, maxnorm, 4+8);
pari_sp av1 = avma;
for (n = minnorm; n <= maxnorm; n++, avma = av1)
{
GEN idnormn = gel(listid,n);
long nbidnn = lg(idnormn) - 1;
if (DEBUGLEVEL>1) err_printf(" %ld", n);
for (i = 1; i <= nbidnn; i++)
{
long s;
gel(m,1) = idealmul(nf, f, gel(idnormn,i));
for (s = 1; s <= narch; s++)
{
GEN candD, ImC, bnrm;
long nbcand, c;
gel(arch,N+1-s) = gen_0;
bnrm = Buchray(bnf, m, nf_INIT);
c = bnrisconductor(bnrm, NULL);
gel(arch,N+1-s) = gen_1;
if (!c) continue;
ImC = ComputeKernel(bnrm, bnr, dtQ);
candD = subgrouplist_cond_sub(bnrm, ImC, mkvec(gen_2));
nbcand = lg(candD) - 1;
for (c = 1; c <= nbcand; c++)
{
GEN D = gel(candD,c);
long cpl;
GEN p1 = InitQuotient(D), p2;
GEN ord = gel(p1,1), cyc = gel(p1,2), map = gel(p1,3);
if (!cyc_is_cyclic(cyc))
{
GEN lH = subgrouplist(cyc, NULL), IK = NULL;
long j, ok = 0;
for (j = 1; j < lg(lH); j++)
{
GEN H = gel(lH, j), IH = subgp_intersect(cyc, IK, H);
if (IK && gidentical(IH, IK)) continue;
if (IsGoodSubgroup(H, bnrm, map))
{
IK = IH;
if (equalii(ord, ZM_det_triangular(IK))) { ok = 1; break; }
}
}
if (!ok) continue;
}
p2 = cgetg(6, t_VEC);
gel(p2,1) = bnrm;
gel(p2,2) = D;
gel(p2,3) = InitQuotient(D);
gel(p2,4) = InitQuotient(ImC);
if (DEBUGLEVEL>1)
err_printf("\nTrying modulus = %Ps and subgroup = %Ps\n",
bnr_get_mod(bnrm), D);
cpl = CplxModulus(p2, &pr);
if (oldcpl < 0 || cpl < oldcpl)
{
*newprec = pr;
if (rep) gunclone(rep);
rep = gclone(p2);
oldcpl = cpl;
}
if (oldcpl < rb) goto END;
if (DEBUGLEVEL>1) err_printf("Trying to find another modulus...");
first = 0;
}
}
if (!first) goto END;
}
}
minnorm = maxnorm;
maxnorm <<= 1;
if (!iscyc && maxnorm > limnorm) return NULL;
}
END:
if (DEBUGLEVEL>1)
err_printf("No, we're done!\nModulus = %Ps and subgroup = %Ps\n",
bnr_get_mod(gel(rep,1)), gel(rep,2));
gel(rep,5) = InitChar(gel(rep,1), gel(rep,5), *newprec);
return gerepilecopy(av, rep);
}
static GEN
get_ilambda(GEN nf, GEN fa, GEN foo)
{
GEN x, w, E2, P = gel(fa,1), E = gel(fa,2), D = nf_get_diff(nf);
long i, l = lg(P);
if (l == 1) return gen_1;
w = cgetg(l, t_VEC);
E2 = cgetg(l, t_COL);
for (i = 1; i < l; i++)
{
GEN pr = gel(P,i), t = pr_get_tau(pr);
long e = itou(gel(E,i)), v = idealval(nf, D, pr);
if (v) { D = idealdivpowprime(nf, D, pr, utoipos(v)); e += v; }
gel(E2,i) = stoi(e+1);
if (typ(t) == t_MAT) t = gel(t,1);
gel(w,i) = gdiv(nfpow(nf, t, stoi(e)), powiu(pr_get_p(pr),e));
}
x = mkmat2(P, E2);
return idealchinese(nf, mkvec2(x, foo), w);
}
static GEN
ArtinNumber(GEN bnr, GEN LCHI, long check, long prec)
{
long ic, i, j, nz, nChar = lg(LCHI)-1;
pari_sp av = avma, av2;
GEN sqrtnc, cond, condZ, cond0, cond1, nf, T;
GEN cyc, vN, vB, diff, vt, idh, zid, gen, z, nchi;
GEN indW, W, classe, s0, s, den, ilambda, sarch;
CHI_t **lC;
GROUP_t G;
lC = (CHI_t**)new_chunk(nChar + 1);
indW = cgetg(nChar + 1, t_VECSMALL);
W = cgetg(nChar + 1, t_VEC);
for (ic = 0, i = 1; i <= nChar; i++)
{
GEN CHI = gel(LCHI,i);
if (chi_get_deg(CHI) <= 2) { gel(W,i) = gen_1; continue; }
ic++; indW[ic] = i;
lC[ic] = (CHI_t*)new_chunk(sizeof(CHI_t));
init_CHI_C(lC[ic], CHI);
}
if (!ic) return W;
nChar = ic;
nf = bnr_get_nf(bnr);
diff = nf_get_diff(nf);
T = nf_get_Tr(nf);
cond = bnr_get_mod(bnr);
cond0 = gel(cond,1); condZ = gcoeff(cond0,1,1);
cond1 = gel(cond,2);
sqrtnc = gsqrt(idealnorm(nf, cond0), prec);
ilambda = get_ilambda(nf, bid_get_fact(bnr_get_bid(bnr)), cond1);
idh = idealmul(nf, ilambda, idealmul(nf, diff, cond0));
ilambda = Q_remove_denom(ilambda, &den);
z = den? rootsof1_cx(den, prec): NULL;
zid = Idealstar(nf, cond0, nf_GEN);
cyc = abgrp_get_cyc(zid);
gen = abgrp_get_gen(zid);
nz = lg(gen) - 1;
sarch = nfarchstar(nf, cond0, vec01_to_indices(cond1));
nchi = cgetg(nChar+1, t_VEC);
for (ic = 1; ic <= nChar; ic++) gel(nchi,ic) = cgetg(nz + 1, t_VECSMALL);
for (i = 1; i <= nz; i++)
{
if (is_bigint(gel(cyc,i)))
pari_err_OVERFLOW("ArtinNumber [conductor too large]");
gel(gen,i) = set_sign_mod_divisor(nf, NULL, gel(gen,i), sarch);
classe = isprincipalray(bnr, gel(gen,i));
for (ic = 1; ic <= nChar; ic++) {
GEN n = gel(nchi,ic);
n[i] = CHI_eval_n(lC[ic], classe);
}
}
vt = gel(T,1);
if (typ(ilambda) == t_COL)
vt = ZV_ZM_mul(vt, zk_multable(nf, ilambda));
else
vt = ZC_Z_mul(vt, ilambda);
G.cyc = gtovecsmall(cyc);
G.r = nz;
G.j = zero_zv(nz);
vN = zero_Flm_copy(nz, nChar);
av2 = avma;
vB = const_vec(nz, gen_1);
s0 = z? powgi(z, modii(gel(vt,1), den)): gen_1;
s = const_vec(nChar, s0);
while ( (i = NextElt(&G)) )
{
GEN b = gel(vB,i);
b = nfmuli(nf, b, gel(gen,i));
b = typ(b) == t_COL? FpC_red(b, condZ): modii(b, condZ);
for (j=1; j<=i; j++) gel(vB,j) = b;
for (ic = 1; ic <= nChar; ic++)
{
GEN v = gel(vN,ic), n = gel(nchi,ic);
v[i] = Fl_add(v[i], n[i], lC[ic]->ord);
for (j=1; j<i; j++) v[j] = v[i];
}
gel(vB,i) = b = set_sign_mod_divisor(nf, NULL, b, sarch);
if (!z)
s0 = gen_1;
else
{
b = typ(b) == t_COL? ZV_dotproduct(vt, b): mulii(gel(vt,1),b);
s0 = powgi(z, modii(b,den));
}
for (ic = 1; ic <= nChar; ic++)
{
GEN v = gel(vN,ic), val = lC[ic]->val[ v[i] ];
gel(s,ic) = gadd(gel(s,ic), gmul(val, s0));
}
if (gc_needed(av2, 1))
{
if (DEBUGMEM > 1) pari_warn(warnmem,"ArtinNumber");
gerepileall(av2, 2, &s, &vB);
}
}
classe = isprincipalray(bnr, idh);
z = powIs(- (lg(gel(sarch,1))-1));
for (ic = 1; ic <= nChar; ic++)
{
s0 = gmul(gel(s,ic), CHI_eval(lC[ic], classe));
s0 = gdiv(s0, sqrtnc);
if (check && - expo(subrs(gnorm(s0), 1)) < prec2nbits(prec) >> 1)
pari_err_BUG("ArtinNumber");
gel(W, indW[ic]) = gmul(s0, z);
}
return gerepilecopy(av, W);
}
static GEN
ComputeAllArtinNumbers(GEN dataCR, GEN vChar, int check, long prec)
{
long j, k, cl = lg(dataCR) - 1, J = lg(vChar)-1;
GEN W = cgetg(cl+1,t_VEC), WbyCond, LCHI;
for (j = 1; j <= J; j++)
{
GEN LChar = gel(vChar,j), ldata = vecpermute(dataCR, LChar);
GEN dtcr = gel(ldata,1), bnr = ch_bnr(dtcr);
long l = lg(LChar);
if (DEBUGLEVEL>1)
err_printf("* Root Number: cond. no %ld/%ld (%ld chars)\n", j, J, l-1);
LCHI = cgetg(l, t_VEC);
for (k = 1; k < l; k++) gel(LCHI,k) = ch_CHI0(gel(ldata,k));
WbyCond = ArtinNumber(bnr, LCHI, check, prec);
for (k = 1; k < l; k++) gel(W,LChar[k]) = gel(WbyCond,k);
}
return W;
}
static GEN
SingleArtinNumber(GEN bnr, GEN chi, long prec)
{ return gel(ArtinNumber(bnr, mkvec(chi), 1, prec), 1); }
GEN
bnrrootnumber(GEN bnr, GEN chi, long flag, long prec)
{
pari_sp av = avma;
GEN cyc;
if (flag < 0 || flag > 1) pari_err_FLAG("bnrrootnumber");
checkbnr(bnr);
if (flag)
{
cyc = bnr_get_cyc(bnr);
if (!char_check(cyc,chi)) pari_err_TYPE("bnrrootnumber [character]", chi);
}
else
{
GEN z = bnrconductor_i(bnr, chi, 2);
bnr = gel(z,2);
chi = gel(z,3);
cyc = bnr_get_cyc(bnr);
}
chi = char_normalize(chi, cyc_normalize(cyc));
chi = get_Char(chi, prec);
return gerepilecopy(av, SingleArtinNumber(bnr, chi, prec));
}
static GEN
ComputeAChi(GEN dtcr, long *r, long flag, long prec)
{
GEN A, diff = ch_diff(dtcr), bnrc = ch_bnr(dtcr), chi = ch_CHI0(dtcr);
long i, l = lg(diff);
A = gen_1; *r = 0;
for (i = 1; i < l; i++)
{
GEN pr = gel(diff,i), B;
GEN z = CharEval(chi, isprincipalray(bnrc, pr));
if (flag)
B = gsubsg(1, gdiv(z, pr_norm(pr)));
else if (gequal1(z))
{
B = glog(pr_norm(pr), prec);
(*r)++;
}
else
B = gsubsg(1, z);
A = gmul(A, B);
}
return A;
}
static int
L_vanishes_at_0(GEN dtcr)
{
GEN diff = ch_diff(dtcr), bnrc = ch_bnr(dtcr), chi = ch_CHI0(dtcr);
long i, l = lg(diff);
for (i = 1; i < l; i++)
{
GEN pr = gel(diff,i);
if (! CharEval_n(chi, isprincipalray(bnrc, pr))) return 1;
}
return 0;
}
static GEN
_data4(GEN arch, long r1, long r2)
{
GEN z = cgetg(5, t_VECSMALL);
long i, b, q = 0;
for (i=1; i<=r1; i++) if (signe(gel(arch,i))) q++;
z[1] = q; b = r1 - q;
z[2] = b;
z[3] = r2;
z[4] = maxss(b+r2+1, r2+q);
return z;
}
static GEN
InitChar(GEN bnr, GEN listCR, long prec)
{
GEN bnf = checkbnf(bnr), nf = bnf_get_nf(bnf);
GEN modul, dk, C, dataCR, chi, cond, ncyc;
long N, r1, r2, prec2, i, j, l;
pari_sp av = avma;
modul = bnr_get_mod(bnr);
dk = nf_get_disc(nf);
N = nf_get_degree(nf);
nf_get_sign(nf, &r1,&r2);
prec2 = precdbl(prec) + EXTRA_PREC;
C = gmul2n(sqrtr_abs(divir(dk, powru(mppi(prec2),N))), -r2);
ncyc = cyc_normalize( bnr_get_cyc(bnr) );
dataCR = cgetg_copy(listCR, &l);
for (i = 1; i < l; i++)
{
GEN bnrc, olddtcr, dtcr = cgetg(9, t_VEC);
gel(dataCR,i) = dtcr;
chi = gmael(listCR, i, 1);
cond = gmael(listCR, i, 2);
olddtcr = NULL;
for (j = 1; j < i; j++)
if (gequal(cond, gmael(listCR,j,2))) { olddtcr = gel(dataCR,j); break; }
if (!olddtcr)
{
ch_C(dtcr) = gmul(C, gsqrt(ZM_det_triangular(gel(cond,1)), prec2));
ch_4(dtcr) = _data4(gel(cond,2),r1,r2);
ch_cond(dtcr) = cond;
if (gequal(cond,modul))
{
ch_bnr(dtcr) = bnr;
ch_diff(dtcr) = cgetg(1, t_VEC);
}
else
{
ch_bnr(dtcr) = Buchray(bnf, cond, nf_INIT);
ch_diff(dtcr) = get_prdiff(bnr, cond);
}
}
else
{
ch_C(dtcr) = ch_C(olddtcr);
ch_bnr(dtcr) = ch_bnr(olddtcr);
ch_4(dtcr) = ch_4(olddtcr);
ch_diff(dtcr) = ch_diff(olddtcr);
ch_cond(dtcr) = ch_cond(olddtcr);
}
chi = char_normalize(chi,ncyc);
ch_CHI(dtcr) = get_Char(chi, prec2);
ch_comp(dtcr) = gen_1;
bnrc = ch_bnr(dtcr);
if (gequal(bnr_get_mod(bnr), bnr_get_mod(bnrc)))
ch_CHI0(dtcr) = ch_CHI(dtcr);
else
{
chi = bnrchar_primitive(bnr, chi, bnrc);
ch_CHI0(dtcr) = get_Char(chi, prec2);
}
}
return gerepilecopy(av, dataCR);
}
static GEN
CharNewPrec(GEN dataCR, GEN nf, long prec)
{
GEN dk, C;
long N, l, j, prec2;
dk = nf_get_disc(nf);
N = nf_get_degree(nf);
prec2 = precdbl(prec) + EXTRA_PREC;
C = sqrtr(divir(absi_shallow(dk), powru(mppi(prec2), N)));
l = lg(dataCR);
for (j = 1; j < l; j++)
{
GEN dtcr = gel(dataCR,j), f0 = gel(ch_cond(dtcr),1);
ch_C(dtcr) = gmul(C, gsqrt(ZM_det_triangular(f0), prec2));
gmael(ch_bnr(dtcr), 1, 7) = nf;
ch_CHI( dtcr) = get_Char(gel(ch_CHI(dtcr), 1), prec2);
ch_CHI0(dtcr) = get_Char(gel(ch_CHI0(dtcr),1), prec2);
}
return dataCR;
}
static void
_0toCoeff(int *rep, long deg)
{
long i;
for (i=0; i<deg; i++) rep[i] = 0;
}
static void
Polmod2Coeff(int *rep, GEN polmod, long deg)
{
long i;
if (typ(polmod) == t_POLMOD)
{
GEN pol = gel(polmod,2);
long d = degpol(pol);
pol += 2;
for (i=0; i<=d; i++) rep[i] = itos(gel(pol,i));
for ( ; i<deg; i++) rep[i] = 0;
}
else
{
rep[0] = itos(polmod);
for (i=1; i<deg; i++) rep[i] = 0;
}
}
static int**
InitMatAn(long n, long deg, long flag)
{
long i, j;
int *a, **A = (int**)pari_malloc((n+1)*sizeof(int*));
A[0] = NULL;
for (i = 1; i <= n; i++)
{
a = (int*)pari_malloc(deg*sizeof(int));
A[i] = a; a[0] = (i == 1 || flag);
for (j = 1; j < deg; j++) a[j] = 0;
}
return A;
}
static void
FreeMat(int **A, long n)
{
long i;
for (i = 0; i <= n; i++)
if (A[i]) pari_free((void*)A[i]);
pari_free((void*)A);
}
static int**
InitReduction(long d, long deg)
{
long j;
pari_sp av = avma;
int **A;
GEN polmod, pol;
A = (int**)pari_malloc(deg*sizeof(int*));
pol = polcyclo(d, 0);
for (j = 0; j < deg; j++)
{
A[j] = (int*)pari_malloc(deg*sizeof(int));
polmod = gmodulo(pol_xn(deg+j, 0), pol);
Polmod2Coeff(A[j], polmod, deg);
}
avma = av; return A;
}
#if 0#endif
static int
IsZero(int* c, long deg)
{
long i;
for (i = 0; i < deg; i++)
if (c[i]) return 0;
return 1;
}
static void
MulCoeff(int *c0, int* c1, int** reduc, long deg)
{
long i,j;
int c, *T;
if (IsZero(c0,deg)) return;
T = (int*)new_chunk(2*deg);
for (i = 0; i < 2*deg; i++)
{
c = 0;
for (j = 0; j <= i; j++)
if (j < deg && j > i - deg) c += c0[j] * c1[i-j];
T[i] = c;
}
for (i = 0; i < deg; i++)
{
c = T[i];
for (j = 0; j < deg; j++) c += reduc[j][i] * T[deg+j];
c0[i] = c;
}
}
static void
AddMulCoeff(int *c0, int *c1, int* c2, int** reduc, long deg)
{
long i, j;
pari_sp av;
int c, *t;
if (IsZero(c2,deg)) return;
if (!c1)
{
for (i = 0; i < deg; i++) c0[i] += c2[i];
return;
}
av = avma;
t = (int*)new_chunk(2*deg);
for (i = 0; i < 2*deg; i++)
{
c = 0;
for (j = 0; j <= i; j++)
if (j < deg && j > i - deg) c += c1[j] * c2[i-j];
t[i] = c;
}
for (i = 0; i < deg; i++)
{
c = t[i];
for (j = 0; j < deg; j++) c += reduc[j][i] * t[deg+j];
c0[i] += c;
}
avma = av;
}
static GEN
EvalCoeff(GEN z, int* c, long deg)
{
long i,j;
GEN e, r;
if (!c) return gen_0;
#if 0#else
e = NULL;
for (i = deg-1; i >=0; i=j-1)
{
for (j=i; c[j] == 0; j--)
if (j==0)
{
if (!e) return NULL;
if (i!=j) z = gpowgs(z,i-j+1);
return gmul(e,z);
}
if (e)
{
r = (i==j)? z: gpowgs(z,i-j+1);
e = gadd(gmul(e,r), stoi(c[j]));
}
else
e = stoi(c[j]);
}
#endif
return e;
}
static void
CopyCoeff(int** a, int** a2, long n, long m)
{
long i,j;
for (i = 1; i <= n; i++)
{
int *b = a[i], *b2 = a2[i];
for (j = 0; j < m; j++) b2[j] = b[j];
}
}
static void
an_AddMul(int **an,int **an2, long np, long n, long deg, GEN chi, int **reduc)
{
GEN chi2 = chi;
long q, qk, k;
int *c, *c2 = (int*)new_chunk(deg);
CopyCoeff(an, an2, n/np, deg);
for (q=np;;)
{
if (gequal1(chi2)) c = NULL; else { Polmod2Coeff(c2, chi2, deg); c = c2; }
for(k = 1, qk = q; qk <= n; k++, qk += q)
AddMulCoeff(an[qk], c, an2[k], reduc, deg);
if (! (q = umuluu_le(q,np, n)) ) break;
chi2 = gmul(chi2, chi);
}
}
static void
CorrectCoeff(GEN dtcr, int** an, int** reduc, long n, long deg)
{
pari_sp av = avma;
long lg, j;
pari_sp av1;
int **an2;
GEN bnrc, diff;
CHI_t C;
diff = ch_diff(dtcr); lg = lg(diff) - 1;
if (!lg) return;
if (DEBUGLEVEL>2) err_printf("diff(CHI) = %Ps", diff);
bnrc = ch_bnr(dtcr);
init_CHI_alg(&C, ch_CHI0(dtcr));
an2 = InitMatAn(n, deg, 0);
av1 = avma;
for (j = 1; j <= lg; j++)
{
GEN pr = gel(diff,j);
long Np = upr_norm(pr);
GEN chi = CHI_eval(&C, isprincipalray(bnrc, pr));
an_AddMul(an,an2,Np,n,deg,chi,reduc);
avma = av1;
}
FreeMat(an2, n); avma = av;
}
static int**
ComputeCoeff(GEN dtcr, LISTray *R, long n, long deg)
{
pari_sp av = avma, av2;
long i, l;
int **an, **reduc, **an2;
GEN L;
CHI_t C;
init_CHI_alg(&C, ch_CHI(dtcr));
an = InitMatAn(n, deg, 0);
an2 = InitMatAn(n, deg, 0);
reduc = InitReduction(C.ord, deg);
av2 = avma;
L = R->L1; l = lg(L);
for (i=1; i<l; i++, avma = av2)
{
long np = L[i];
GEN chi = CHI_eval(&C, gel(R->L1ray,i));
an_AddMul(an,an2,np,n,deg,chi,reduc);
}
FreeMat(an2, n);
CorrectCoeff(dtcr, an, reduc, n, deg);
FreeMat(reduc, deg-1);
avma = av; return an;
}
static void
deg11(LISTray *R, long p, GEN bnr, GEN pr) {
GEN z = isprincipalray(bnr, pr);
vecsmalltrunc_append(R->L1, p);
vectrunc_append(R->L1ray, z);
}
static void
deg12(LISTray *R, long p, GEN bnr, GEN Lpr) {
GEN z = isprincipalray(bnr, gel(Lpr,1));
vecsmalltrunc_append(R->L11, p);
vectrunc_append(R->L11ray, z);
}
static void
deg0(LISTray *R, long p) { vecsmalltrunc_append(R->L0, p); }
static void
deg2(LISTray *R, long p) { vecsmalltrunc_append(R->L2, p); }
static void
InitPrimesQuad(GEN bnr, ulong N0, LISTray *R)
{
pari_sp av = avma;
GEN bnf = bnr_get_bnf(bnr), cond = gel(bnr_get_mod(bnr), 1);
long p,i,l, condZ = itos(gcoeff(cond,1,1)), contZ = itos(content(cond));
GEN prime, Lpr, nf = bnf_get_nf(bnf), dk = nf_get_disc(nf);
forprime_t T;
l = 1 + primepi_upper_bound(N0);
R->L0 = vecsmalltrunc_init(l);
R->L2 = vecsmalltrunc_init(l); R->condZ = condZ;
R->L1 = vecsmalltrunc_init(l); R->L1ray = vectrunc_init(l);
R->L11= vecsmalltrunc_init(l); R->L11ray= vectrunc_init(l);
prime = utoipos(2);
u_forprime_init(&T, 2, N0);
while ( (p = u_forprime_next(&T)) )
{
prime[2] = p;
switch (kroiu(dk, p))
{
case -1:
if (condZ % p == 0) deg0(R,p); else deg2(R,p);
break;
case 1:
Lpr = idealprimedec(nf, prime);
if (condZ % p != 0) deg12(R, p, bnr, Lpr);
else if (contZ % p == 0) deg0(R,p);
else
{
GEN pr = idealval(nf, cond, gel(Lpr,1))? gel(Lpr,2): gel(Lpr,1);
deg11(R, p, bnr, pr);
}
break;
default:
if (condZ % p == 0)
deg0(R,p);
else
deg11(R, p, bnr, idealprimedec_galois(nf,prime));
break;
}
}
R->rayZ = cgetg(condZ, t_VEC);
for (i=1; i<condZ; i++)
gel(R->rayZ,i) = (ugcd(i,condZ) == 1)? isprincipalray(bnr, utoipos(i)): gen_0;
gerepileall(av, 7, &(R->L0), &(R->L2), &(R->rayZ),
&(R->L1), &(R->L1ray), &(R->L11), &(R->L11ray) );
}
static void
InitPrimes(GEN bnr, ulong N0, LISTray *R)
{
GEN bnf = bnr_get_bnf(bnr), cond = gel(bnr_get_mod(bnr), 1);
long p,j,k,l, condZ = itos(gcoeff(cond,1,1)), N = lg(cond)-1;
GEN tmpray, tabpr, prime, BOUND, nf = bnf_get_nf(bnf);
forprime_t T;
R->condZ = condZ; l = primepi_upper_bound(N0) * N;
tmpray = cgetg(N+1, t_VEC);
R->L1 = vecsmalltrunc_init(l);
R->L1ray = vectrunc_init(l);
u_forprime_init(&T, 2, N0);
prime = utoipos(2);
BOUND = utoi(N0);
while ( (p = u_forprime_next(&T)) )
{
pari_sp av = avma;
prime[2] = p;
if (DEBUGLEVEL>1 && (p & 2047) == 1) err_printf("%ld ", p);
tabpr = idealprimedec_limit_norm(nf, prime, BOUND);
for (j = 1; j < lg(tabpr); j++)
{
GEN pr = gel(tabpr,j);
if (condZ % p == 0 && idealval(nf, cond, pr))
{
gel(tmpray,j) = NULL; continue;
}
vecsmalltrunc_append(R->L1, upowuu(p, pr_get_f(pr)));
gel(tmpray,j) = gclone( isprincipalray(bnr, pr) );
}
avma = av;
for (k = 1; k < j; k++)
{
if (!tmpray[k]) continue;
vectrunc_append(R->L1ray, ZC_copy(gel(tmpray,k)));
gunclone(gel(tmpray,k));
}
}
}
static GEN
_sercoeff(GEN x, long n)
{
long i = n - valp(x);
return (i < 0)? gen_0: gel(x,i+2);
}
static void
affect_coeff(GEN q, long n, GEN y)
{
GEN x = _sercoeff(q,-n);
if (x == gen_0) gel(y,n) = NULL; else affgr(x, gel(y,n));
}
typedef struct {
GEN c1, aij, bij, cS, cT, powracpi;
long i0, a,b,c, r, rc1, rc2;
} ST_t;
static void
ppgamma(ST_t *T, long prec)
{
GEN eul, gam,gamun,gamdm, an,bn,cn_evn,cn_odd, x,x2,X,Y, cf, sqpi;
GEN p1, p2, aij, bij;
long a = T->a;
long b = T->b;
long c = T->c, r = T->r, i0 = T->i0;
long i,j, s,t;
pari_sp av;
aij = cgetg(i0+1, t_VEC);
bij = cgetg(i0+1, t_VEC);
for (i = 1; i <= i0; i++)
{
gel(aij,i) = p1 = cgetg(r+1, t_VEC);
gel(bij,i) = p2 = cgetg(r+1, t_VEC);
for (j=1; j<=r; j++) { gel(p1,j) = cgetr(prec); gel(p2,j) = cgetr(prec); }
}
av = avma;
x = pol_x(0);
x2 = gmul2n(x, -1);
eul = mpeuler(prec);
sqpi= sqrtr_abs(mppi(prec));
gamun = cgetg(r+3, t_SER);
gamun[1] = evalsigne(1) | _evalvalp(0) | evalvarn(0);
gel(gamun,2) = gen_0;
gel(gamun,3) = gneg(eul);
for (i = 2; i <= r; i++)
gel(gamun,i+2) = divrs(szeta(i,prec), odd(i)? -i: i);
gamun = gexp(gamun, prec);
gam = gdiv(gamun,x);
gamdm = cgetg(r+3, t_SER);
gamdm[1] = evalsigne(1) | _evalvalp(0) | evalvarn(0);
gel(gamdm,2) = gen_0;
gel(gamdm,3) = gneg(gadd(gmul2n(mplog2(prec), 1), eul));
for (i = 2; i <= r; i++) gel(gamdm,i+2) = mulri(gel(gamun,i+2), int2um1(i));
gamdm = gmul(sqpi, gexp(gamdm, prec));
if (b > a)
{
t = a; s = b; X = x2; Y = gsub(x2,ghalf);
p1 = ser_unscale(gam, ghalf);
p2 = gdiv(ser_unscale(gamdm,ghalf), Y);
}
else
{
t = b; s = a; X = gadd(x2,ghalf); Y = x2;
p1 = ser_unscale(gamdm,ghalf);
p2 = ser_unscale(gam,ghalf);
}
cf = powru(sqpi, t);
an = gpowgs(gpow(gen_2, gsubsg(1,x), prec), t);
bn = gpowgs(gam, t+c);
cn_evn = gpowgs(p1, s-t);
cn_odd = gpowgs(p2, s-t);
for (i = 0; i < i0/2; i++)
{
GEN C1,q1, A1 = gel(aij,2*i+1), B1 = gel(bij,2*i+1);
GEN C2,q2, A2 = gel(aij,2*i+2), B2 = gel(bij,2*i+2);
C1 = gmul(cf, gmul(bn, gmul(an, cn_evn)));
p1 = gdiv(C1, gsubgs(x, 2*i));
q1 = gdiv(C1, gsubgs(x, 2*i+1));
an = gmul2n(an, t);
bn = gdiv(bn, gpowgs(gsubgs(x, 2*i+1), t+c));
C2 = gmul(cf, gmul(bn, gmul(an, cn_odd)));
p2 = gdiv(C2, gsubgs(x, 2*i+1));
q2 = gdiv(C2, gsubgs(x, 2*i+2));
for (j = 1; j <= r; j++)
{
affect_coeff(p1, j, A1); affect_coeff(q1, j, B1);
affect_coeff(p2, j, A2); affect_coeff(q2, j, B2);
}
an = gmul2n(an, t);
bn = gdiv(bn, gpowgs(gsubgs(x, 2*i+2), t+c));
cn_evn = gdiv(cn_evn, gpowgs(gsubgs(X,i+1), s-t));
cn_odd = gdiv(cn_odd, gpowgs(gsubgs(Y,i+1), s-t));
}
T->aij = aij;
T->bij = bij; avma = av;
}
static GEN
_cond(GEN dtcr) { return mkvec2(ch_cond(dtcr), ch_4(dtcr)); }
static GEN
sortChars(GEN dataCR)
{
const long cl = lg(dataCR) - 1;
GEN vCond = cgetg(cl+1, t_VEC);
GEN CC = cgetg(cl+1, t_VECSMALL);
GEN nvCond = cgetg(cl+1, t_VECSMALL);
long j,k, ncond;
GEN vChar;
for (j = 1; j <= cl; j++) nvCond[j] = 0;
ncond = 0;
for (j = 1; j <= cl; j++)
{
GEN cond = _cond(gel(dataCR,j));
for (k = 1; k <= ncond; k++)
if (gequal(cond, gel(vCond,k))) break;
if (k > ncond) gel(vCond,++ncond) = cond;
nvCond[k]++; CC[j] = k;
}
vChar = cgetg(ncond+1, t_VEC);
for (k = 1; k <= ncond; k++)
{
gel(vChar,k) = cgetg(nvCond[k]+1, t_VECSMALL);
nvCond[k] = 0;
}
for (j = 1; j <= cl; j++)
{
k = CC[j]; nvCond[k]++;
mael(vChar,k,nvCond[k]) = j;
}
return vChar;
}
static GEN
GetValue(GEN dtcr, GEN W, GEN S, GEN T, long fl, long prec)
{
pari_sp av = avma;
GEN cf, z, p1;
long q, b, c, r;
int isreal = (chi_get_deg(ch_CHI0(dtcr)) <= 2);
p1 = ch_4(dtcr);
q = p1[1];
b = p1[2];
c = p1[3];
if (fl & 1)
{
cf = gmul(ch_C(dtcr), powruhalf(mppi(prec), b));
z = gadd(S, gmul(W, T));
if (isreal) z = real_i(z);
z = gdiv(z, cf);
if (fl & 2) z = gmul(z, ComputeAChi(dtcr, &r, 1, prec));
}
else
{
cf = gmul2n(powruhalf(mppi(prec), q), b);
z = gadd(gmul(W, conj_i(S)), conj_i(T));
if (isreal) z = real_i(z);
z = gdiv(z, cf); r = 0;
if (fl & 2) z = gmul(z, ComputeAChi(dtcr, &r, 0, prec));
z = mkvec2(utoi(b + c + r), z);
}
return gerepilecopy(av, z);
}
static GEN
GetValue1(GEN bnr, long flag, long prec)
{
GEN bnf = checkbnf(bnr), nf = bnf_get_nf(bnf);
GEN h, R, c, diff;
long i, l, r, r1, r2;
pari_sp av = avma;
nf_get_sign(nf, &r1,&r2);
h = bnf_get_no(bnf);
R = bnf_get_reg(bnf);
c = gneg_i(gdivgs(mpmul(h, R), bnf_get_tuN(bnf)));
r = r1 + r2 - 1;
if (flag)
{
diff = divcond(bnr);
l = lg(diff) - 1; r += l;
for (i = 1; i <= l; i++)
c = gmul(c, glog(pr_norm(gel(diff,i)), prec));
}
return gerepilecopy(av, mkvec2(stoi(r), c));
}
static long
TestOne(GEN plg, RC_data *d)
{
long j, v = d->v;
GEN z = gsub(d->beta, gel(plg,v));
if (expo(z) >= d->G) return 0;
for (j = 1; j < lg(plg); j++)
if (j != v && mpcmp(d->B, mpabs_shallow(gel(plg,j))) < 0) return 0;
return 1;
}
static GEN
chk_reccoeff_init(FP_chk_fun *chk, GEN r, GEN mat)
{
RC_data *d = (RC_data*)chk->data;
(void)r; d->U = mat; return d->nB;
}
static GEN
chk_reccoeff(void *data, GEN x)
{
RC_data *d = (RC_data*)data;
GEN v = gmul(d->U, x), z = gel(v,1);
if (!gequal1(z)) return NULL;
*++v = evaltyp(t_COL) | evallg( lg(d->M) );
if (TestOne(gmul(d->M, v), d)) return v;
return NULL;
}
static GEN
RecCoeff3(GEN nf, RC_data *d, long prec)
{
GEN A, M, nB, cand, p1, B2, C2, tB, beta2, nf2, Bd;
GEN beta = d->beta, B = d->B;
long N = d->N, v = d->v, e, BIG;
long i, j, k, ct = 0, prec2;
FP_chk_fun chk = { &chk_reccoeff, &chk_reccoeff_init, NULL, NULL, 0 };
chk.data = (void*)d;
d->G = minss(-10, -prec2nbits(prec) >> 4);
BIG = maxss(32, -2*d->G);
tB = sqrtnr(real2n(BIG-N,DEFAULTPREC), N-1);
Bd = grndtoi(gmin_shallow(B, tB), &e);
if (e > 0) return NULL;
Bd = addiu(Bd, 1);
prec2 = nbits2prec( expi(Bd) + 192 );
prec2 = maxss(precdbl(prec), prec2);
B2 = sqri(Bd);
C2 = shifti(B2, BIG<<1);
LABrcf: ct++;
beta2 = gprec_w(beta, prec2);
nf2 = nfnewprec_shallow(nf, prec2);
d->M = M = nf_get_M(nf2);
A = cgetg(N+2, t_MAT);
for (i = 1; i <= N+1; i++) gel(A,i) = cgetg(N+2, t_COL);
gcoeff(A, 1, 1) = gadd(gmul(C2, gsqr(beta2)), B2);
for (j = 2; j <= N+1; j++)
{
p1 = gmul(C2, gmul(gneg_i(beta2), gcoeff(M, v, j-1)));
gcoeff(A, 1, j) = gcoeff(A, j, 1) = p1;
}
for (i = 2; i <= N+1; i++)
for (j = i; j <= N+1; j++)
{
p1 = gen_0;
for (k = 1; k <= N; k++)
{
GEN p2 = gmul(gcoeff(M, k, j-1), gcoeff(M, k, i-1));
if (k == v) p2 = gmul(C2, p2);
p1 = gadd(p1,p2);
}
gcoeff(A, i, j) = gcoeff(A, j, i) = p1;
}
nB = mului(N+1, B2);
d->nB = nB;
cand = fincke_pohst(A, nB, -1, prec2, &chk);
if (!cand)
{
if (ct > 3) return NULL;
prec2 = precdbl(prec2);
if (DEBUGLEVEL>1) pari_warn(warnprec,"RecCoeff", prec2);
goto LABrcf;
}
cand = gel(cand,1);
if (lg(cand) == 2) return gel(cand,1);
if (DEBUGLEVEL>1) err_printf("RecCoeff3: no solution found!\n");
return NULL;
}
static GEN
RecCoeff2(GEN nf, RC_data *d, long prec)
{
pari_sp av;
GEN vec, M = nf_get_M(nf), beta = d->beta;
long bit, min, max, lM = lg(M);
d->G = minss(-20, -prec2nbits(prec) >> 4);
vec = shallowconcat(mkvec(gneg(beta)), row(M, d->v));
min = (long)prec2nbits_mul(prec, 0.75);
max = (long)prec2nbits_mul(prec, 0.98);
av = avma;
for (bit = max; bit >= min; bit-=32, avma = av)
{
long e;
GEN v = lindep_bit(vec, bit), z = gel(v,1);
if (!signe(z)) continue;
*++v = evaltyp(t_COL) | evallg(lM);
v = grndtoi(gdiv(v, z), &e);
if (e > 0) break;
if (TestOne(RgM_RgC_mul(M, v), d)) return v;
}
return RecCoeff3(nf,d,prec);
}
static GEN
RecCoeff(GEN nf, GEN pol, long v, long prec)
{
long j, md, cl = degpol(pol);
pari_sp av = avma;
RC_data d;
for (j = 2; j <= cl+1; j++)
{
GEN t = gel(pol, j);
if (prec2nbits(gprecision(t)) - gexpo(t) < 34) return NULL;
}
md = cl/2;
pol = leafcopy(pol);
d.N = nf_get_degree(nf);
d.v = v;
for (j = 1; j <= cl; j++)
{
long cf = md + (j%2? j/2: -j/2);
GEN t, bound = shifti(binomial(utoipos(cl), cf), cl-cf);
if (DEBUGLEVEL>1) err_printf("RecCoeff (cf = %ld, B = %Ps)\n", cf, bound);
d.beta = real_i( gel(pol,cf+2) );
d.B = bound;
if (! (t = RecCoeff2(nf, &d, prec)) ) return NULL;
gel(pol, cf+2) = coltoalg(nf,t);
}
gel(pol,cl+2) = gen_1;
return gerepilecopy(av, pol);
}
static void
an_mul(int **an, long p, long q, long n, long deg, GEN chi, int **reduc)
{
pari_sp av;
long c,i;
int *T;
if (gequal1(chi)) return;
av = avma;
T = (int*)new_chunk(deg); Polmod2Coeff(T,chi, deg);
for (c = 1, i = q; i <= n; i += q, c++)
if (c == p) c = 0; else MulCoeff(an[i], T, reduc, deg);
avma = av;
}
static void
an_set0_coprime(int **an, long p, long q, long n, long deg)
{
long c,i;
for (c = 1, i = q; i <= n; i += q, c++)
if (c == p) c = 0; else _0toCoeff(an[i], deg);
}
static void
an_set0(int **an, long p, long n, long deg)
{
long i;
for (i = p; i <= n; i += p) _0toCoeff(an[i], deg);
}
static int**
computean(GEN dtcr, LISTray *R, long n, long deg)
{
pari_sp av = avma, av2;
long i, p, q, condZ, l;
int **an, **reduc;
GEN L, chi, chi1;
CHI_t C;
init_CHI_alg(&C, ch_CHI(dtcr));
condZ= R->condZ;
an = InitMatAn(n, deg, 1);
reduc = InitReduction(C.ord, deg);
av2 = avma;
L = R->L0; l = lg(L);
for (i=1; i<l; i++) an_set0(an,L[i],n,deg);
L = R->L2; l = lg(L);
for (i=1; i<l; i++, avma = av2)
{
p = L[i];
if (condZ == 1) chi = C.val[0];
else chi = CHI_eval(&C, gel(R->rayZ, p%condZ));
chi1 = chi;
for (q=p;;)
{
an_set0_coprime(an, p,q,n,deg);
if (! (q = umuluu_le(q,p, n)) ) break;
an_mul(an,p,q,n,deg,chi,reduc);
if (! (q = umuluu_le(q,p, n)) ) break;
chi = gmul(chi, chi1);
}
}
L = R->L1; l = lg(L);
for (i=1; i<l; i++, avma = av2)
{
p = L[i];
chi = CHI_eval(&C, gel(R->L1ray,i));
chi1 = chi;
for(q=p;;)
{
an_mul(an,p,q,n,deg,chi,reduc);
if (! (q = umuluu_le(q,p, n)) ) break;
chi = gmul(chi, chi1);
}
}
L = R->L11; l = lg(L);
for (i=1; i<l; i++, avma = av2)
{
GEN ray1, ray2, chi11, chi12, chi2;
p = L[i]; ray1 = gel(R->L11ray,i);
if (condZ == 1)
ray2 = ZC_neg(ray1);
else
ray2 = ZC_sub(gel(R->rayZ, p%condZ), ray1);
chi11 = CHI_eval(&C, ray1);
chi12 = CHI_eval(&C, ray2);
chi1 = gadd(chi11, chi12);
chi2 = chi12;
for(q=p;;)
{
an_mul(an,p,q,n,deg,chi1,reduc);
if (! (q = umuluu_le(q,p, n)) ) break;
chi2 = gmul(chi2, chi12);
chi1 = gadd(chi2, gmul(chi1, chi11));
}
}
CorrectCoeff(dtcr, an, reduc, n, deg);
FreeMat(reduc, deg-1);
avma = av; return an;
}
static GEN
mpvecpowdiv(GEN A, long n)
{
pari_sp av = avma;
long i;
GEN v = powersr(A, n);
GEN w = cgetg(n+1, t_VEC);
gel(w,1) = rcopy(gel(v,2));
for (i=2; i<=n; i++) gel(w,i) = divru(gel(v,i+1), i);
return gerepileupto(av, w);
}
static void GetST0(GEN bnr, GEN *pS, GEN *pT, GEN dataCR, GEN vChar, long prec);
static void
QuadGetST(GEN bnr, GEN *pS, GEN *pT, GEN dataCR, GEN vChar, long prec)
{
pari_sp av = avma, av1, av2;
long ncond, n, j, k, n0;
GEN N0, C, T = *pT, S = *pS, an, degs, cs;
LISTray LIST;
degs = GetDeg(dataCR);
ncond = lg(vChar)-1;
C = cgetg(ncond+1, t_VEC);
N0 = cgetg(ncond+1, t_VECSMALL);
cs = cgetg(ncond+1, t_VECSMALL);
n0 = 0;
for (j = 1; j <= ncond; j++)
{
long r1, r2, q;
GEN dtcr = gel(dataCR, mael(vChar,j,1)), p1 = ch_4(dtcr), c = ch_C(dtcr);
gel(C,j) = c;
q = p1[1];
nf_get_sign(bnr_get_nf(ch_bnr(dtcr)), &r1, &r2);
if (r1 == 2)
{
cs[j] = 2 + q;
N0[j] = (long)prec2nbits_mul(prec, 0.35 * gtodouble(c));
if (cs[j] == 2 || cs[j] == 4)
{
GetST0(bnr, pS, pT, dataCR, vChar, prec);
return;
}
}
else
{
cs[j] = 1;
N0[j] = (long)prec2nbits_mul(prec, 0.7 * gtodouble(c));
}
if (n0 < N0[j]) n0 = N0[j];
}
if (DEBUGLEVEL>1) err_printf("N0 = %ld\n", n0);
InitPrimesQuad(bnr, n0, &LIST);
av1 = avma;
for (j = 1; j <= ncond; j++)
{
GEN c0 = gel(C,j), c1 = divur(1, c0), c2 = divur(2, c0);
GEN ec1 = mpexp(c1), ec2 = mpexp(c2), LChar = gel(vChar,j);
GEN vf0, vf1, cf0, cf1;
const long nChar = lg(LChar)-1, NN = N0[j];
if (DEBUGLEVEL>1)
err_printf("* conductor no %ld/%ld (N = %ld)\n\tInit: ", j,ncond,NN);
if (realprec(ec1) > prec) ec1 = rtor(ec1, prec);
if (realprec(ec2) > prec) ec2 = rtor(ec2, prec);
switch(cs[j])
{
case 1:
cf0 = gen_1;
cf1 = c0;
vf0 = mpveceint1(rtor(c1, prec), ec1, NN);
vf1 = mpvecpowdiv(invr(ec1), NN); break;
case 3:
cf0 = sqrtr(mppi(prec));
cf1 = gmul2n(cf0, 1);
cf0 = gmul(cf0, c0);
vf0 = mpvecpowdiv(invr(ec2), NN);
vf1 = mpveceint1(rtor(c2, prec), ec2, NN); break;
default:
cf0 = cf1 = NULL;
vf0 = vf1 = NULL;
}
for (k = 1; k <= nChar; k++)
{
const long t = LChar[k], d = degs[t];
const GEN dtcr = gel(dataCR, t), z = gel(ch_CHI(dtcr), 2);
GEN p1 = gen_0, p2 = gen_0;
int **matan;
long c = 0;
if (DEBUGLEVEL>1)
err_printf("\tcharacter no: %ld (%ld/%ld)\n", t,k,nChar);
if (isintzero( ch_comp(gel(dataCR, t)) ))
{
if (DEBUGLEVEL>1) err_printf("\t no need to compute this character\n");
continue;
}
av2 = avma;
matan = computean(gel(dataCR,t), &LIST, NN, d);
for (n = 1; n <= NN; n++)
if ((an = EvalCoeff(z, matan[n], d)))
{
p1 = gadd(p1, gmul(an, gel(vf0,n)));
p2 = gadd(p2, gmul(an, gel(vf1,n)));
if (++c == 256) { gerepileall(av2,2, &p1,&p2); c = 0; }
}
gaffect(gmul(cf0, p1), gel(S,t));
gaffect(gmul(cf1, conj_i(p2)), gel(T,t));
FreeMat(matan,NN); avma = av2;
}
if (DEBUGLEVEL>1) err_printf("\n");
avma = av1;
}
avma = av;
}
static GEN
_addmulrr(GEN s, GEN t, GEN u)
{
if (u)
{
GEN v = mulrr(t, u);
return s? addrr(s, v): v;
}
return s;
}
static GEN
_addrr(GEN s, GEN t)
{ return t? (s? addrr(s, t): t) : s; }
static void
get_cS_cT(ST_t *T, long n)
{
pari_sp av;
GEN csurn, nsurc, lncsurn, A, B, s, t, Z, aij, bij;
long i, j, r, i0;
if (T->cS[n]) return;
av = avma;
aij = T->aij; i0= T->i0;
bij = T->bij; r = T->r;
Z = cgetg(r+1, t_VEC);
gel(Z,1) = NULL;
csurn = divru(T->c1, n);
nsurc = invr(csurn);
lncsurn = logr_abs(csurn);
if (r > 1)
{
gel(Z,2) = lncsurn;
for (i = 3; i <= r; i++)
gel(Z,i) = divru(mulrr(gel(Z,i-1), lncsurn), i-1);
}
A = gel(aij,i0); t = _addrr(NULL, gel(A,1));
B = gel(bij,i0); s = _addrr(NULL, gel(B,1));
for (j = 2; j <= r; j++)
{
s = _addmulrr(s, gel(Z,j),gel(B,j));
t = _addmulrr(t, gel(Z,j),gel(A,j));
}
for (i = i0 - 1; i > 1; i--)
{
A = gel(aij,i); if (t) t = mulrr(t, nsurc);
B = gel(bij,i); if (s) s = mulrr(s, nsurc);
for (j = odd(i)? T->rc2: T->rc1; j > 1; j--)
{
s = _addmulrr(s, gel(Z,j),gel(B,j));
t = _addmulrr(t, gel(Z,j),gel(A,j));
}
s = _addrr(s, gel(B,1));
t = _addrr(t, gel(A,1));
}
A = gel(aij,1); if (t) t = mulrr(t, nsurc);
B = gel(bij,1); if (s) s = mulrr(s, nsurc);
s = _addrr(s, gel(B,1));
t = _addrr(t, gel(A,1));
for (j = 2; j <= r; j++)
{
s = _addmulrr(s, gel(Z,j),gel(B,j));
t = _addmulrr(t, gel(Z,j),gel(A,j));
}
s = _addrr(s, T->b? mulrr(csurn, gel(T->powracpi,T->b+1)): csurn);
if (!s) s = gen_0;
if (!t) t = gen_0;
gel(T->cS,n) = gclone(s);
gel(T->cT,n) = gclone(t); avma = av;
}
static void
clear_cScT(ST_t *T, long N)
{
GEN cS = T->cS, cT = T->cT;
long i;
for (i=1; i<=N; i++)
if (cS[i]) {
gunclone(gel(cS,i));
gunclone(gel(cT,i)); gel(cS,i) = gel(cT,i) = NULL;
}
}
static void
init_cScT(ST_t *T, GEN dtcr, long N, long prec)
{
GEN p1 = ch_4(dtcr);
T->a = p1[1];
T->b = p1[2];
T->c = p1[3];
T->rc1 = T->a + T->c;
T->rc2 = T->b + T->c;
T->r = maxss(T->rc2+1, T->rc1);
ppgamma(T, prec);
clear_cScT(T, N);
}
static GEN
zeta_get_limx(long r1, long r2, long bit)
{
pari_sp av = avma;
GEN p1, p2, c0, c1, A0;
long r = r1 + r2, N = r + r2;
c1 = mulrs(powrfrac(real2n(1, DEFAULTPREC), -2*r2, N), N);
p1 = powru(Pi2n(1, DEFAULTPREC), r - 1);
p2 = mulir(powuu(N,r), p1); shiftr_inplace(p2, -r2);
c0 = sqrtr( divrr(p2, powru(c1, r+1)) );
A0 = logr_abs( gmul2n(c0, bit) ); p2 = divrr(A0, c1);
p1 = divrr(mulur(N*(r+1), logr_abs(p2)), addsr(2*(r+1), gmul2n(A0,2)));
return gerepileuptoleaf(av, divrr(addrs(p1, 1), powruhalf(p2, N)));
}
static long
zeta_get_N0(GEN C, GEN limx)
{
long e;
pari_sp av = avma;
GEN z = gcvtoi(gdiv(C, limx), &e);
if (e >= 0 || is_bigint(z))
pari_err_OVERFLOW("zeta_get_N0 [need too many primes]");
if (DEBUGLEVEL>1) err_printf("\ninitzeta: N0 = %Ps\n", z);
avma = av; return itos(z);
}
static GEN
eval_i(long r1, long r2, GEN limx, long i)
{
GEN t = powru(limx, i);
if (!r1) t = mulrr(t, powru(mpfactr(i , DEFAULTPREC), r2));
else if (!r2) t = mulrr(t, powru(mpfactr(i/2, DEFAULTPREC), r1));
else {
GEN u1 = mpfactr(i/2, DEFAULTPREC);
GEN u2 = mpfactr(i, DEFAULTPREC);
if (r1 == r2) t = mulrr(t, powru(mulrr(u1,u2), r1));
else t = mulrr(t, mulrr(powru(u1,r1), powru(u2,r2)));
}
return t;
}
static long
get_i0(long r1, long r2, GEN B, GEN limx)
{
long imin = 1, imax = 1400;
while (mpcmp(eval_i(r1,r2,limx, imax), B) < 0) { imin = imax; imax *= 2; }
while(imax - imin >= 4)
{
long m = (imax + imin) >> 1;
if (mpcmp(eval_i(r1,r2,limx, m), B) >= 0) imax = m; else imin = m;
}
return imax & ~1;
}
static long
zeta_get_i0(long r1, long r2, long bit, GEN limx)
{
pari_sp av = avma;
GEN B = gmul(sqrtr( divrr(powrs(mppi(DEFAULTPREC), r2-3), limx) ),
gmul2n(powuu(5, r1), bit + r2));
long i0 = get_i0(r1, r2, B, limx);
if (DEBUGLEVEL>1) { err_printf("i0 = %ld\n",i0); err_flush(); }
avma = av; return i0;
}
static void
GetST0(GEN bnr, GEN *pS, GEN *pT, GEN dataCR, GEN vChar, long prec)
{
pari_sp av = avma, av1, av2;
long ncond, n, j, k, jc, n0, prec2, i0, r1, r2;
GEN nf = checknf(bnr), T = *pT, S = *pS;
GEN N0, C, an, degs, limx;
LISTray LIST;
ST_t cScT;
degs = GetDeg(dataCR);
ncond = lg(vChar)-1;
nf_get_sign(nf,&r1,&r2);
C = cgetg(ncond+1, t_VEC);
N0 = cgetg(ncond+1, t_VECSMALL);
n0 = 0;
limx = zeta_get_limx(r1, r2, prec2nbits(prec));
for (j = 1; j <= ncond; j++)
{
GEN dtcr = gel(dataCR, mael(vChar,j,1)), c = ch_C(dtcr);
gel(C,j) = c;
N0[j] = zeta_get_N0(c, limx);
if (n0 < N0[j]) n0 = N0[j];
}
i0 = zeta_get_i0(r1, r2, prec2nbits(prec), limx);
InitPrimes(bnr, n0, &LIST);
prec2 = precdbl(prec) + EXTRA_PREC;
cScT.powracpi = powersr(sqrtr(mppi(prec2)), r1);
cScT.cS = cgetg(n0+1, t_VEC);
cScT.cT = cgetg(n0+1, t_VEC);
for (j=1; j<=n0; j++) gel(cScT.cS,j) = gel(cScT.cT,j) = NULL;
cScT.i0 = i0;
av1 = avma;
for (jc = 1; jc <= ncond; jc++)
{
const GEN LChar = gel(vChar,jc);
const long nChar = lg(LChar)-1, NN = N0[jc];
if (DEBUGLEVEL>1)
err_printf("* conductor no %ld/%ld (N = %ld)\n\tInit: ", jc,ncond,NN);
cScT.c1 = gel(C,jc);
init_cScT(&cScT, gel(dataCR, LChar[1]), NN, prec2);
av2 = avma;
for (k = 1; k <= nChar; k++)
{
const long t = LChar[k];
if (DEBUGLEVEL>1)
err_printf("\tcharacter no: %ld (%ld/%ld)\n", t,k,nChar);
if (!isintzero( ch_comp(gel(dataCR, t)) ))
{
const long d = degs[t];
const GEN dtcr = gel(dataCR, t), z = gel(ch_CHI(dtcr), 2);
GEN p1 = gen_0, p2 = gen_0;
long c = 0;
int **matan = ComputeCoeff(gel(dataCR,t), &LIST, NN, d);
for (n = 1; n <= NN; n++)
if ((an = EvalCoeff(z, matan[n], d)))
{
get_cS_cT(&cScT, n);
p1 = gadd(p1, gmul(an, gel(cScT.cS,n)));
p2 = gadd(p2, gmul(an, gel(cScT.cT,n)));
if (++c == 256) { gerepileall(av2,2, &p1,&p2); c = 0; }
}
gaffect(p1, gel(S,t));
gaffect(conj_i(p2), gel(T,t));
FreeMat(matan, NN); avma = av2;
}
else if (DEBUGLEVEL>1)
err_printf("\t no need to compute this character\n");
}
if (DEBUGLEVEL>1) err_printf("\n");
avma = av1;
}
clear_cScT(&cScT, n0);
avma = av;
}
static void
GetST(GEN bnr, GEN *pS, GEN *pT, GEN dataCR, GEN vChar, long prec)
{
const long cl = lg(dataCR) - 1;
GEN S, T, nf = checknf(bnr);
long j;
*pS = S = cgetg(cl+1, t_VEC);
*pT = T = cgetg(cl+1, t_VEC);
for (j = 1; j <= cl; j++)
{
gel(S,j) = cgetc(prec);
gel(T,j) = cgetc(prec);
}
if (nf_get_degree(nf) == 2)
QuadGetST(bnr, pS, pT, dataCR, vChar, prec);
else
GetST0(bnr, pS, pT, dataCR, vChar, prec);
}
static GEN
GenusFieldQuadReal(GEN disc)
{
long i, i0 = 0, l;
pari_sp av = avma;
GEN T = NULL, p0 = NULL, P;
P = gel(Z_factor(disc), 1);
l = lg(P);
for (i = 1; i < l; i++)
{
GEN p = gel(P,i);
if (mod4(p) == 3) { p0 = p; i0 = i; break; }
}
l--;
if (i0 == l) l--;
for (i = 1; i < l; i++)
{
GEN p = gel(P,i), d, t;
if (i == i0) continue;
if (absequaliu(p, 2))
switch (mod32(disc))
{
case 8: d = gen_2; break;
case 24: d = shifti(p0, 1); break;
default: d = p0; break;
}
else
d = (mod4(p) == 1)? p: mulii(p0, p);
t = mkpoln(3, gen_1, gen_0, negi(d));
T = T? ZX_compositum_disjoint(T, t): t;
}
return gerepileupto(av, polredbest(T, 0));
}
static GEN
GenusFieldQuadImag(GEN disc)
{
long i, l;
pari_sp av = avma;
GEN T = NULL, P;
P = gel(absZ_factor(disc), 1);
l = lg(P);
l--;
for (i = 1; i < l; i++)
{
GEN p = gel(P,i), d, t;
if (absequaliu(p, 2))
switch (mod32(disc))
{
case 24: d = gen_2; break;
case 8: d = gen_m2; break;
default: d = gen_m1; break;
}
else
d = (mod4(p) == 1)? p: negi(p);
t = mkpoln(3, gen_1, gen_0, negi(d));
T = T? ZX_compositum_disjoint(T, t): t;
}
return gerepileupto(av, polredbest(T, 0));
}
static GEN
AllStark(GEN data, GEN nf, long flag, long newprec)
{
const long BND = 300;
long cl, i, j, cpt = 0, N, h, v, n, r1, r2, den;
pari_sp av, av2;
int **matan;
GEN bnr = gel(data,1), p1, p2, S, T, polrelnum, polrel, Lp, W, veczeta;
GEN vChar, degs, C, dataCR, cond1, L1, an;
LISTray LIST;
pari_timer ti;
nf_get_sign(nf, &r1,&r2);
N = nf_get_degree(nf);
cond1 = gel(bnr_get_mod(bnr), 2);
dataCR = gel(data,5);
vChar = sortChars(dataCR);
v = 1;
while (gequal1(gel(cond1,v))) v++;
cl = lg(dataCR)-1;
degs = GetDeg(dataCR);
h = itos(ZM_det_triangular(gel(data,2))) >> 1;
LABDOUB:
if (DEBUGLEVEL) timer_start(&ti);
av = avma;
for (i = 1; i <= cl; i++)
{
GEN chi = gel(dataCR, i);
if (L_vanishes_at_0(chi)) ch_comp(chi) = gen_0;
}
W = ComputeAllArtinNumbers(dataCR, vChar, (flag >= 0), newprec);
if (DEBUGLEVEL) timer_printf(&ti,"Compute W");
Lp = cgetg(cl + 1, t_VEC);
if (!flag)
{
GetST(bnr, &S, &T, dataCR, vChar, newprec);
if (DEBUGLEVEL) timer_printf(&ti, "S&T");
for (i = 1; i <= cl; i++)
{
GEN chi = gel(dataCR, i), v = gen_0;
if (!isintzero( ch_comp(chi) ))
v = gel(GetValue(chi, gel(W,i), gel(S,i), gel(T,i), 2, newprec), 2);
gel(Lp, i) = v;
}
}
else
{
C = cgetg(cl + 1, t_VEC);
for (i = 1; i <= cl; i++) gel(C,i) = ch_C(gel(dataCR, i));
n = zeta_get_N0(vecmax(C), zeta_get_limx(r1, r2, prec2nbits(newprec)));
if (n > BND) n = BND;
if (DEBUGLEVEL) err_printf("N0 in QuickPol: %ld \n", n);
InitPrimes(bnr, n, &LIST);
L1 = cgetg(cl+1, t_VEC);
for (i = 1; i <= cl; i++)
{
GEN dtcr = gel(dataCR,i);
matan = ComputeCoeff(dtcr, &LIST, n, degs[i]);
av2 = avma;
p1 = real_0(newprec); p2 = gel(ch_CHI(dtcr), 2);
for (j = 1; j <= n; j++)
if ( (an = EvalCoeff(p2, matan[j], degs[i])) )
p1 = gadd(p1, gdivgs(an, j));
gel(L1,i) = gerepileupto(av2, p1);
FreeMat(matan, n);
}
p1 = gmul2n(powruhalf(mppi(newprec), N-2), 1);
for (i = 1; i <= cl; i++)
{
long r;
GEN WW, A = ComputeAChi(gel(dataCR,i), &r, 0, newprec);
WW = gmul(gel(C,i), gmul(A, gel(W,i)));
gel(Lp,i) = gdiv(gmul(WW, conj_i(gel(L1,i))), p1);
}
}
p1 = ComputeLift(gel(data,4));
den = flag ? h: 2*h;
veczeta = cgetg(h + 1, t_VEC);
for (i = 1; i <= h; i++)
{
GEN z = gen_0, sig = gel(p1,i);
for (j = 1; j <= cl; j++)
{
GEN dtcr = gel(dataCR,j), CHI = ch_CHI(dtcr);
GEN t = mulreal(gel(Lp,j), CharEval(CHI, sig));
if (chi_get_deg(CHI) != 2) t = gmul2n(t, 1);
z = gadd(z, t);
}
gel(veczeta,i) = gdivgs(z, den);
}
for (j = 1; j <= h; j++)
gel(veczeta,j) = gmul2n(gcosh(gel(veczeta,j), newprec), 1);
polrelnum = roots_to_pol(veczeta, 0);
if (DEBUGLEVEL)
{
if (DEBUGLEVEL>1) {
err_printf("polrelnum = %Ps\n", polrelnum);
err_printf("zetavalues = %Ps\n", veczeta);
if (!flag)
err_printf("Checking the square-root of the Stark unit...\n");
}
timer_printf(&ti, "Compute %s", flag? "quickpol": "polrelnum");
}
if (flag)
return gerepilecopy(av, polrelnum);
polrel = RecCoeff(nf, polrelnum, v, newprec);
if (!polrel)
{
for (j = 1; j <= h; j++)
gel(veczeta,j) = gsubgs(gsqr(gel(veczeta,j)), 2);
polrelnum = roots_to_pol(veczeta, 0);
if (DEBUGLEVEL)
{
if (DEBUGLEVEL>1) {
err_printf("It's not a square...\n");
err_printf("polrelnum = %Ps\n", polrelnum);
}
timer_printf(&ti, "Compute polrelnum");
}
polrel = RecCoeff(nf, polrelnum, v, newprec);
}
if (!polrel)
{
const long EXTRA_BITS = 64;
long incr_pr;
if (++cpt >= 3) pari_err_PREC( "stark (computation impossible)");
incr_pr = prec2nbits(gprecision(polrelnum))- gexpo(polrelnum);
if (incr_pr < 0) incr_pr = -incr_pr + EXTRA_BITS;
newprec += nbits2extraprec(maxss(3*EXTRA_BITS, cpt*incr_pr));
if (DEBUGLEVEL) pari_warn(warnprec, "AllStark", newprec);
nf = nfnewprec_shallow(nf, newprec);
dataCR = CharNewPrec(dataCR, nf, newprec);
gerepileall(av, 2, &nf, &dataCR);
goto LABDOUB;
}
if (DEBUGLEVEL) {
if (DEBUGLEVEL>1) err_printf("polrel = %Ps\n", polrel);
timer_printf(&ti, "Recpolnum");
}
return gerepilecopy(av, polrel);
}
static GEN
get_subgroup(GEN H, GEN cyc, const char *s)
{
if (!H || gequal0(H)) return diagonal_shallow(cyc);
if (typ(H) != t_MAT) pari_err_TYPE(stack_strcat(s," [subgroup]"), H);
RgM_check_ZM(H, s);
return ZM_hnfmodid(H, cyc);
}
GEN
bnrstark(GEN bnr, GEN subgrp, long prec)
{
long N, newprec;
pari_sp av = avma;
GEN bnf, p1, cycbnr, nf, data, dtQ;
checkbnr(bnr);
bnf = checkbnf(bnr);
nf = bnf_get_nf(bnf);
N = nf_get_degree(nf);
if (N == 1) return galoissubcyclo(bnr, subgrp, 0, 0);
if (!nf_get_varn(nf))
pari_err_PRIORITY("bnrstark", nf_get_pol(nf), "=", 0);
if (nf_get_r2(nf)) pari_err_DOMAIN("bnrstark", "r2", "!=", gen_0, nf);
subgrp = get_subgroup(subgrp,bnr_get_cyc(bnr),"bnrstark");
p1 = bnrconductor_i(bnr, subgrp, 2);
bnr = gel(p1,2); cycbnr = bnr_get_cyc(bnr);
subgrp = gel(p1,3);
if (gequal1( ZM_det_triangular(subgrp) )) { avma = av; return pol_x(0); }
if (!gequal0(gel(bnr_get_mod(bnr), 2)))
pari_err_DOMAIN("bnrstark", "r2(class field)", "!=", gen_0, bnr);
dtQ = InitQuotient(subgrp);
data = FindModulus(bnr, dtQ, &newprec);
if (!data)
{
GEN vec, H, cyc = gel(dtQ,2), U = gel(dtQ,3), M = RgM_inv(U);
long i, j = 1, l = lg(M);
vec = cgetg(l, t_VEC);
for (i = 1; i < l; i++)
{
if (is_pm1(gel(cyc,i))) continue;
H = ZM_hnfmodid(vecsplice(M,i), cycbnr);
gel(vec,j++) = bnrstark(bnr, H, prec);
}
setlg(vec, j); return gerepilecopy(av, vec);
}
if (newprec > prec)
{
if (DEBUGLEVEL>1) err_printf("new precision: %ld\n", newprec);
nf = nfnewprec_shallow(nf, newprec);
}
return gerepileupto(av, AllStark(data, nf, 0, newprec));
}
GEN
bnrL1(GEN bnr, GEN subgp, long flag, long prec)
{
GEN cyc, L1, allCR, listCR;
GEN indCR, invCR, Qt;
long cl, i, nc;
pari_sp av = avma;
checkbnr(bnr);
if (flag < 0 || flag > 8) pari_err_FLAG("bnrL1");
cyc = bnr_get_cyc(bnr);
subgp = get_subgroup(subgp, cyc, "bnrL1");
Qt = InitQuotient(subgp);
cl = itou(gel(Qt,1));
allCR = EltsOfGroup(cl, gel(Qt,2));
listCR = cgetg(cl, t_VEC);
indCR = cgetg(cl, t_VECSMALL);
invCR = cgetg(cl, t_VECSMALL); nc = 0;
for (i = 1; i < cl; i++)
{
GEN lchi = LiftChar(Qt, cyc, gel(allCR,i));
GEN clchi = charconj(cyc, lchi);
long j, a = 0;
for (j = 1; j <= nc; j++)
if (ZV_equal(gmael(listCR, j, 1), clchi)) { a = j; break; }
if (!a)
{
nc++;
gel(listCR,nc) = mkvec2(lchi, bnrconductorofchar(bnr, lchi));
indCR[i] = nc;
invCR[nc] = i;
}
else
indCR[i] = -invCR[a];
gel(allCR,i) = lchi;
}
settyp(allCR[cl], t_VEC);
setlg(listCR, nc + 1);
L1 = cgetg((flag&1)? cl: cl+1, t_VEC);
if (nc)
{
GEN dataCR = InitChar(bnr, listCR, prec);
GEN W, S, T, vChar = sortChars(dataCR);
GetST(bnr, &S, &T, dataCR, vChar, prec);
W = ComputeAllArtinNumbers(dataCR, vChar, 1, prec);
for (i = 1; i < cl; i++)
{
long a = indCR[i];
if (a > 0)
gel(L1,i) = GetValue(gel(dataCR,a), gel(W,a), gel(S,a), gel(T,a),
flag, prec);
else
gel(L1,i) = conj_i(gel(L1,-a));
}
}
if (!(flag & 1))
gel(L1,cl) = GetValue1(bnr, flag & 2, prec);
else
cl--;
if (flag & 4) {
for (i = 1; i <= cl; i++) gel(L1,i) = mkvec2(gel(allCR,i), gel(L1,i));
}
return gerepilecopy(av, L1);
}
static void
split_pol_quad(GEN P, GEN *gP0, GEN *gP1)
{
long i, l = lg(P);
GEN P0 = cgetg(l, t_POL), P1 = cgetg(l, t_POL);
P0[1] = P1[1] = P[1];
for (i = 2; i < l; i++)
{
GEN c = gel(P,i), c0 = c, c1 = gen_0;
if (typ(c) == t_POL)
switch(degpol(c))
{
case -1: c0 = gen_0; break;
default: c1 = gel(c,3);
case 0: c0 = gel(c,2); break;
}
gel(P0,i) = c0; gel(P1,i) = c1;
}
*gP0 = normalizepol_lg(P0, l);
*gP1 = normalizepol_lg(P1, l);
}
static GEN
makescind(GEN nf, GEN P)
{
GEN Pp, p, pol, G, L, a, roo, P0,P1, Ny,Try, nfpol = nf_get_pol(nf);
long i, is_P;
P = lift_shallow(P);
split_pol_quad(P, &P0, &P1);
Ny = gel(nfpol, 2);
Try = negi(gel(nfpol, 3));
pol = RgX_add(RgX_sqr(P0), RgX_Rg_mul(RgX_sqr(P1), Ny));
if (signe(Try)) pol = RgX_add(pol, RgX_Rg_mul(RgX_mul(P0,P1), Try));
G = galoisinit(pol, NULL);
L = gal_get_group(G);
p = gal_get_p(G);
a = FpX_oneroot(nfpol, p);
Pp = FpXY_evalx(P, a, p);
roo = gal_get_roots(G);
is_P = gequal0( FpX_eval(Pp, remii(gel(roo,1),p), p) );
for (i = 1; i < lg(L); i++)
{
GEN perm = gel(L,i);
long k = perm[1]; if (k == 1) continue;
k = gequal0( FpX_eval(Pp, remii(gel(roo,k),p), p) );
if (k != is_P)
{
long o = perm_order(perm);
if (o != 2) perm = perm_pow(perm, o >> 1);
return galoisfixedfield(G, perm, 1, varn(P));
}
}
pari_err_BUG("makescind");
return NULL;
}
static void
quadray_init(GEN *pD, GEN f, GEN *pbnf, long prec)
{
GEN D = *pD, nf, bnf = NULL;
if (typ(D) == t_INT)
{
int isfund;
if (pbnf) {
long v = f? gvar(f): NO_VARIABLE;
if (v == NO_VARIABLE) v = 1;
bnf = Buchall(quadpoly0(D, v), nf_FORCE, prec);
nf = bnf_get_nf(bnf);
isfund = equalii(D, nf_get_disc(nf));
}
else
isfund = Z_isfundamental(D);
if (!isfund) pari_err_DOMAIN("quadray", "isfundamental(D)", "=",gen_0, D);
}
else
{
bnf = checkbnf(D);
nf = bnf_get_nf(bnf);
if (nf_get_degree(nf) != 2)
pari_err_DOMAIN("quadray", "degree", "!=", gen_2, nf_get_pol(nf));
D = nf_get_disc(nf);
}
if (pbnf) *pbnf = bnf;
*pD = D;
}
static GEN
quadhilbertreal(GEN D, long prec)
{
pari_sp av = avma;
long newprec;
GEN bnf;
VOLATILE GEN bnr, dtQ, data, nf, cyc, M;
pari_timer ti;
if (DEBUGLEVEL) timer_start(&ti);
(void)≺
(void)&bnf;
quadray_init(&D, NULL, &bnf, prec);
cyc = bnf_get_cyc(bnf);
if (lg(cyc) == 1) { avma = av; return pol_x(0); }
if (absequaliu(gel(cyc,1), 2)) return gerepileupto(av, GenusFieldQuadReal(D));
bnr = Buchray(bnf, gen_1, nf_INIT);
M = diagonal_shallow(bnr_get_cyc(bnr));
dtQ = InitQuotient(M);
nf = bnf_get_nf(bnf);
for(;;) {
VOLATILE GEN pol = NULL;
pari_CATCH(e_PREC) {
prec += EXTRA_PREC;
if (DEBUGLEVEL) pari_warn(warnprec, "quadhilbertreal", prec);
bnr = bnrnewprec_shallow(bnr, prec);
bnf = bnr_get_bnf(bnr);
nf = bnf_get_nf(bnf);
} pari_TRY {
pari_timer T;
if (DEBUGLEVEL) timer_start(&T);
data = FindModulus(bnr, dtQ, &newprec);
if (DEBUGLEVEL) timer_printf(&T,"FindModulus");
if (!data)
{
long i, l = lg(M);
GEN vec = cgetg(l, t_VEC);
for (i = 1; i < l; i++)
{
GEN t = gcoeff(M,i,i);
gcoeff(M,i,i) = gen_1;
gel(vec,i) = bnrstark(bnr, M, prec);
gcoeff(M,i,i) = t;
}
return gerepileupto(av, vec);
}
if (newprec > prec)
{
if (DEBUGLEVEL>1) err_printf("new precision: %ld\n", newprec);
nf = nfnewprec_shallow(nf, newprec);
}
pol = AllStark(data, nf, 0, newprec);
} pari_ENDCATCH;
if (pol) {
pol = makescind(nf, pol);
return gerepileupto(av, polredbest(pol, 0));
}
}
}
static int
hasexp2(GEN form)
{
GEN a = gel(form,1), b = gel(form,2), c = gel(form,3);
return !signe(b) || absequalii(a,b) || equalii(a,c);
}
static int
uhasexp2(GEN form)
{
long a = form[1], b = form[2], c = form[3];
return !b || a == labs(b) || a == c;
}
GEN
qfbforms(GEN D)
{
ulong d = itou(D), dover3 = d/3, t, b2, a, b, c, h;
GEN L = cgetg((long)(sqrt((double)d) * log2(d)), t_VEC);
b2 = b = (d&1); h = 0;
if (!b)
{
t = d >> 2;
for (a=1; a*a<=t; a++)
if (c = t/a, t == c*a) gel(L,++h) = mkvecsmall3(a,0,c);
b = 2; b2 = 4;
}
for ( ; b2 <= dover3; b += 2, b2 = b*b)
{
t = (b2 + d) >> 2;
if (c = t/b, t == c*b) gel(L,++h) = mkvecsmall3(b,b,c);
for (a = b+1; a*a < t; a++)
if (c = t/a, t == c*a)
{
gel(L,++h) = mkvecsmall3(a, b,c);
gel(L,++h) = mkvecsmall3(a,-b,c);
}
if (a * a == t) gel(L,++h) = mkvecsmall3(a,b,a);
}
setlg(L,h+1); return L;
}
static long
GCD24(long n)
{
switch(n % 24)
{
case 0: return 24;
case 1: return 1;
case 2: return 2;
case 3: return 3;
case 4: return 4;
case 5: return 1;
case 6: return 6;
case 7: return 1;
case 8: return 8;
case 9: return 3;
case 10: return 2;
case 11: return 1;
case 12: return 12;
case 13: return 1;
case 14: return 2;
case 15: return 3;
case 16: return 8;
case 17: return 1;
case 18: return 6;
case 19: return 1;
case 20: return 4;
case 21: return 3;
case 22: return 2;
case 23: return 1;
default: return 0;
}
}
struct gpq_data {
long p, q;
GEN sqd;
GEN u, D;
GEN pq, pq2;
GEN qfpq ;
};
static void
init_pq(GEN D, struct gpq_data *T)
{
const long Np = 6547;
const ulong maxq = 50000;
GEN listp = cgetg(Np + 1, t_VECSMALL);
GEN listP = cgetg(Np + 1, t_VEC);
GEN gcd24 = cgetg(Np + 1, t_VECSMALL);
forprime_t S;
long l = 1;
double best = 0.;
ulong q;
u_forprime_init(&S, 2, ULONG_MAX);
T->D = D;
T->p = T->q = 0;
for(;;)
{
GEN Q;
long i, gcdq, mod;
int order2, store;
double t;
q = u_forprime_next(&S);
if (best > 0 && q >= maxq)
{
if (DEBUGLEVEL)
pari_warn(warner,"possibly suboptimal (p,q) for D = %Ps", D);
break;
}
if (kroiu(D, q) < 0) continue;
Q = redimag(primeform_u(D, q));
if (is_pm1(gel(Q,1))) continue;
store = 1;
order2 = hasexp2(Q);
gcd24[l] = gcdq = GCD24(q-1);
mod = 24 / gcdq;
listp[l] = q;
gel(listP,l) = order2 ? Q : NULL;
t = (q+1)/(double)(q-1);
for (i = 1; i < l; i++)
{
long p = listp[i], gcdp = gcd24[i];
double b;
if (order2 && gel(listP,i) && !gequal(gel(listP,i), Q)) continue;
if (gcdp % gcdq == 0) store = 0;
if ((p-1) % mod) continue;
b = (t*(p+1)) / (p-1);
if (b > best) {
store = 0;
best = b; T->q = q; T->p = p;
if (DEBUGLEVEL>2) err_printf("p,q = %ld,%ld\n", p, q);
}
if (best > 0) break;
}
if (store && t*t > best)
if (++l >= Np) pari_err_BUG("quadhilbert (not enough primes)");
if (!best)
{
if (gcdq >= 12 && umodiu(D, q))
{
double b = (t*q) / (q-1);
if (b > best) {
best = b; T->q = T->p = q;
if (DEBUGLEVEL>2) err_printf("p,q = %ld,%ld\n", q, q);
}
}
}
if ((listp[1]+1)*t <= (listp[1]-1)*best) break;
}
if (DEBUGLEVEL>1)
err_printf("(p, q) = %ld, %ld; gain = %f\n", T->p, T->q, 12*best);
}
static GEN
gpq(GEN form, struct gpq_data *T)
{
pari_sp av = avma;
long a = form[1], b = form[2], c = form[3];
long p = T->p, q = T->q;
GEN form2, w, z;
int fl, real = 0;
form2 = qficomp(T->qfpq, mkvec3s(a, -b, c));
fl = cmpis(gel(form2,1), a);
if (fl <= 0)
{
if (fl < 0) return NULL;
fl = cmpis(gel(form2,2), b);
if (fl <= 0)
{
if (fl < 0) return NULL;
real = 1;
}
}
if (p == 2) {
if (a % q == 0 && (a & b & 1) && !(c & 1))
{
lswap(a,c); b = -b;
}
}
if (a % p == 0 || a % q == 0)
{
while (c % p == 0 || c % q == 0)
{
c += a + b;
b += a << 1;
}
lswap(a, c); b = -b;
}
w = Z_chinese(T->u, stoi(-b), T->pq2, utoipos(a << 1));
z = double_eta_quotient(utoipos(a), w, T->D, T->p, T->q, T->pq, T->sqd);
if (real && typ(z) == t_COMPLEX) z = gcopy(gel(z, 1));
return gerepileupto(av, z);
}
static GEN
quadhilbertimag(GEN D)
{
GEN L, P, Pi, Pr, qfp, u;
pari_sp av = avma;
long h, i, prec;
struct gpq_data T;
pari_timer ti;
if (DEBUGLEVEL>1) timer_start(&ti);
if (lgefint(D) == 3)
switch (D[2]) {
case 3:
case 4:
case 7:
case 8:
case 11:
case 19:
case 43:
case 67:
case 163: return pol_x(0);
}
L = qfbforms(D);
h = lg(L)-1;
if ((1L << vals(h)) == h)
{
long lim = (h>>1) + 1;
for (i=1; i <= lim; i++)
if (!uhasexp2(gel(L,i))) break;
if (i > lim) return GenusFieldQuadImag(D);
}
if (DEBUGLEVEL>1) timer_printf(&ti,"class number = %ld",h);
init_pq(D, &T);
qfp = primeform_u(D, T.p);
T.pq = muluu(T.p, T.q);
T.pq2 = shifti(T.pq,1);
if (T.p == T.q)
{
GEN qfbp2 = qficompraw(qfp, qfp);
u = gel(qfbp2,2);
T.u = modii(u, T.pq2);
T.qfpq = redimag(qfbp2);
}
else
{
GEN qfq = primeform_u(D, T.q), bp = gel(qfp,2), bq = gel(qfq,2);
T.u = Z_chinese(bp, bq, utoipos(T.p << 1), utoipos(T.q << 1));
T.qfpq = qficomp(qfp, qfq);
}
prec = LOWDEFAULTPREC;
Pr = cgetg(h+1,t_VEC);
Pi = cgetg(h+1,t_VEC);
for(;;)
{
long ex, exmax = 0, r1 = 0, r2 = 0;
pari_sp av0 = avma;
T.sqd = sqrtr_abs(itor(D, prec));
for (i=1; i<=h; i++)
{
GEN s = gpq(gel(L,i), &T);
if (DEBUGLEVEL>3) err_printf("%ld ", i);
if (!s) continue;
if (typ(s) != t_COMPLEX) gel(Pr, ++r1) = s;
else gel(Pi, ++r2) = s;
ex = gexpo(s); if (ex > 0) exmax += ex;
}
if (DEBUGLEVEL>1) timer_printf(&ti,"roots");
setlg(Pr, r1+1);
setlg(Pi, r2+1);
P = roots_to_pol_r1(shallowconcat(Pr,Pi), 0, r1);
P = grndtoi(P,&exmax);
if (DEBUGLEVEL>1) timer_printf(&ti,"product, error bits = %ld",exmax);
if (exmax <= -10) break;
avma = av0; prec += nbits2extraprec(prec2nbits(DEFAULTPREC)+exmax);
if (DEBUGLEVEL) pari_warn(warnprec,"quadhilbertimag",prec);
}
return gerepileupto(av,P);
}
GEN
quadhilbert(GEN D, long prec)
{
GEN d = D;
quadray_init(&d, NULL, NULL, 0);
return (signe(d)>0)? quadhilbertreal(D,prec)
: quadhilbertimag(d);
}
static GEN
getallrootsof1(GEN bnf)
{
GEN T, u, nf = bnf_get_nf(bnf), tu;
long i, n = bnf_get_tuN(bnf);
if (n == 2) {
long N = nf_get_degree(nf);
return mkvec2(scalarcol_shallow(gen_m1, N),
scalarcol_shallow(gen_1, N));
}
tu = poltobasis(nf, bnf_get_tuU(bnf));
T = zk_multable(nf, tu);
u = cgetg(n+1, t_VEC); gel(u,1) = tu;
for (i=2; i <= n; i++) gel(u,i) = ZM_ZC_mul(T, gel(u,i-1));
return u;
}
static GEN
get_lambda(GEN bnr)
{
GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf), pol = nf_get_pol(nf);
GEN f = gel(bnr_get_mod(bnr), 1), labas, lamodf, u;
long a, b, f2, i, lu, v = varn(pol);
f2 = 2 * itos(gcoeff(f,1,1));
u = getallrootsof1(bnf); lu = lg(u);
for (i=1; i<lu; i++)
gel(u,i) = ZC_hnfrem(gel(u,i), f);
if (DEBUGLEVEL>1)
err_printf("quadray: looking for [a,b] != unit mod 2f\n[a,b] = ");
for (a=0; a<f2; a++)
for (b=0; b<f2; b++)
{
GEN la = deg1pol_shallow(stoi(a), stoi(b), v);
if (umodiu(gnorm(mkpolmod(la, pol)), f2) != 1) continue;
if (DEBUGLEVEL>1) err_printf("[%ld,%ld] ",a,b);
labas = poltobasis(nf, la);
lamodf = ZC_hnfrem(labas, f);
for (i=1; i<lu; i++)
if (ZV_equal(lamodf, gel(u,i))) break;
if (i < lu) continue;
if (DEBUGLEVEL)
{
if (DEBUGLEVEL>1) err_printf("\n");
err_printf("lambda = %Ps\n",la);
}
return labas;
}
pari_err_BUG("get_lambda");
return NULL;
}
static GEN
to_approx(GEN nf, GEN a)
{
GEN M = nf_get_M(nf);
return gadd(gel(a,1), gmul(gcoeff(M,1,2),gel(a,2)));
}
static GEN
get_om(GEN nf, GEN a) {
return mkvec2(to_approx(nf,gel(a,2)),
to_approx(nf,gel(a,1)));
}
static GEN
getallelts(GEN bnr)
{
GEN nf, C, c, g, list, pows, gk;
long lc, i, j, no;
nf = bnr_get_nf(bnr);
no = itos( bnr_get_no(bnr) );
c = bnr_get_cyc(bnr);
g = bnr_get_gen_nocheck(bnr); lc = lg(c)-1;
list = cgetg(no+1,t_VEC);
gel(list,1) = matid(nf_get_degree(nf));
if (!no) return list;
pows = cgetg(lc+1,t_VEC);
c = leafcopy(c); settyp(c, t_VECSMALL);
for (i=1; i<=lc; i++)
{
long k = itos(gel(c,i));
c[i] = k;
gk = cgetg(k, t_VEC); gel(gk,1) = gel(g,i);
for (j=2; j<k; j++)
gel(gk,j) = idealmoddivisor(bnr, idealmul(nf, gel(gk,j-1), gel(gk,1)));
gel(pows,i) = gk;
}
C = cgetg(lc+1, t_VECSMALL); C[1] = c[lc];
for (i=2; i<=lc; i++) C[i] = C[i-1] * c[lc-i+1];
i = 1;
for (j=1; j < C[1]; j++)
gel(list, j+1) = gmael(pows,lc,j);
while(j<no)
{
long k;
GEN a;
if (j == C[i+1]) i++;
a = gmael(pows,lc-i,j/C[i]);
k = j%C[i] + 1;
if (k > 1) a = idealmoddivisor(bnr, idealmul(nf, a, gel(list,k)));
gel(list, ++j) = a;
}
return list;
}
static GEN
findbezk(GEN nf, GEN x)
{
GEN a,b, M = nf_get_M(nf), u = gcoeff(M,1,2);
long ea, eb;
b = grndtoi(mpdiv(imag_i(x), gel(u,2)), &eb);
if (eb > -20) return NULL;
a = grndtoi(mpsub(real_i(x), mpmul(b,gel(u,1))), &ea);
if (ea > -20) return NULL;
return signe(b)? coltoalg(nf, mkcol2(a,b)): a;
}
static GEN
findbezk_pol(GEN nf, GEN x)
{
long i, lx = lg(x);
GEN y = cgetg(lx,t_POL);
for (i=2; i<lx; i++)
if (! (gel(y,i) = findbezk(nf,gel(x,i))) ) return NULL;
y[1] = x[1]; return y;
}
static long
get_prec(GEN P, long prec)
{
long k = gprecision(P);
if (k == 3) return precdbl(prec);
k = prec - k;
if (k < 0) k = 0;
k += nbits2prec(gexpo(P) + 128);
if (k <= prec) k = precdbl(prec);
return k;
}
static GEN
ellphistinit(GEN om, long prec)
{
GEN res,om1b,om2b, om1 = gel(om,1), om2 = gel(om,2);
if (gsigne(imag_i(gdiv(om1,om2))) < 0) { swap(om1,om2); om = mkvec2(om1,om2); }
om1b = conj_i(om1);
om2b = conj_i(om2); res = cgetg(4,t_VEC);
gel(res,1) = gdivgs(elleisnum(om,2,0,prec),12);
gel(res,2) = gdiv(PiI2(prec), gmul(om2, imag_i(gmul(om1b,om2))));
gel(res,3) = om2b; return res;
}
static GEN
ellphist(GEN om, GEN res, GEN z, long prec)
{
GEN u = imag_i(gmul(z, gel(res,3)));
GEN zst = gsub(gmul(u, gel(res,2)), gmul(z,gel(res,1)));
return gsub(ellsigma(om,z,1,prec),gmul2n(gmul(z,zst),-1));
}
static GEN
computeth2(GEN om, GEN la, long prec)
{
GEN p1,p2,res = ellphistinit(om,prec);
p1 = gsub(ellphist(om,res,la,prec), ellphist(om,res,gen_1,prec));
p2 = imag_i(p1);
if (gexpo(real_i(p1))>20 || gexpo(p2)> prec2nbits(minss(prec,realprec(p2)))-10)
return NULL;
return gexp(p1,prec);
}
static GEN
computeP2(GEN bnr, long prec)
{
long clrayno, i, first = 1;
pari_sp av=avma, av2;
GEN listray, P0, P, lanum, la = get_lambda(bnr);
GEN nf = bnr_get_nf(bnr), f = gel(bnr_get_mod(bnr), 1);
listray = getallelts(bnr);
clrayno = lg(listray)-1; av2 = avma;
PRECPB:
if (!first)
{
if (DEBUGLEVEL) pari_warn(warnprec,"computeP2",prec);
nf = gerepilecopy(av2, nfnewprec_shallow(checknf(bnr),prec));
}
first = 0; lanum = to_approx(nf,la);
P = cgetg(clrayno+1,t_VEC);
for (i=1; i<=clrayno; i++)
{
GEN om = get_om(nf, idealdiv(nf,f,gel(listray,i)));
GEN s = computeth2(om,lanum,prec);
if (!s) { prec = precdbl(prec); goto PRECPB; }
gel(P,i) = s;
}
P0 = roots_to_pol(P, 0);
P = findbezk_pol(nf, P0);
if (!P) { prec = get_prec(P0, prec); goto PRECPB; }
return gerepilecopy(av, P);
}
#define nexta(a) (a>0 ? -a : 1-a)
static GEN
do_compo(GEN A0, GEN B)
{
long a, i, l = lg(B), v = fetch_var_higher();
GEN A, z;
B = leafcopy(B); setvarn(B, v);
for (i = 2; i < l; i++) gel(B,i) = monomial(gel(B,i), l-i-1, 0);
A = A0 = leafcopy(A0); setvarn(A0, v);
for (a = 0;; a = nexta(a))
{
if (a) A = RgX_translate(A0, stoi(a));
z = resultant(A,B);
if (issquarefree(z)) break;
}
(void)delete_var(); return z;
}
#undef nexta
static GEN
galoisapplypol(GEN nf, GEN s, GEN x)
{
long i, lx = lg(x);
GEN y = cgetg(lx,t_POL);
for (i=2; i<lx; i++) gel(y,i) = galoisapply(nf,s,gel(x,i));
y[1] = x[1]; return y;
}
static GEN
findquad(GEN a, GEN x, GEN p)
{
long tu, tv;
pari_sp av = avma;
GEN u,v;
if (typ(x) == t_POLMOD) x = gel(x,2);
if (typ(a) == t_POLMOD) a = gel(a,2);
u = poldivrem(x, a, &v);
u = simplify_shallow(u); tu = typ(u);
v = simplify_shallow(v); tv = typ(v);
if (!is_scalar_t(tu)) pari_err_TYPE("findquad", u);
if (!is_scalar_t(tv)) pari_err_TYPE("findquad", v);
x = deg1pol(u, v, varn(a));
if (typ(x) == t_POL) x = gmodulo(x,p);
return gerepileupto(av, x);
}
static GEN
findquad_pol(GEN p, GEN a, GEN x)
{
long i, lx = lg(x);
GEN y = cgetg(lx,t_POL);
for (i=2; i<lx; i++) gel(y,i) = findquad(a, gel(x,i), p);
y[1] = x[1]; return y;
}
static GEN
compocyclo(GEN nf, long m, long d)
{
GEN sb,a,b,s,p1,p2,p3,res,polL,polLK,nfL, D = nf_get_disc(nf);
long ell,vx;
p1 = quadhilbertimag(D);
p2 = polcyclo(m,0);
if (d==1) return do_compo(p1,p2);
ell = m&1 ? m : (m>>2);
if (absequalui(ell,D))
{
p2 = gcoeff(nffactor(nf,p2),1,1);
return do_compo(p1,p2);
}
if (ell%4 == 3) ell = -ell;
polLK = quadpoly(stoi(ell));
res = rnfequation2(nf, polLK);
vx = nf_get_varn(nf);
polL = gsubst(gel(res,1),0,pol_x(vx));
a = gsubst(lift_shallow(gel(res,2)), 0,pol_x(vx));
b = gsub(pol_x(vx), gmul(gel(res,3), a));
nfL = nfinit(polL, DEFAULTPREC);
p1 = gcoeff(nffactor(nfL,p1),1,1);
p2 = gcoeff(nffactor(nfL,p2),1,1);
p3 = do_compo(p1,p2);
sb= gneg(gadd(b, RgX_coeff(polLK,1)));
s = gadd(pol_x(vx), gsub(sb, b));
p3 = gmul(p3, galoisapplypol(nfL, s, p3));
return findquad_pol(nf_get_pol(nf), a, p3);
}
static long
isZ(GEN I)
{
GEN x = gcoeff(I,1,1);
if (signe(gcoeff(I,1,2)) || !equalii(x, gcoeff(I,2,2))) return 0;
return is_bigint(x)? -1: itos(x);
}
static GEN
treatspecialsigma(GEN bnr)
{
GEN bnf = bnr_get_bnf(bnr), nf = bnf_get_nf(bnf);
GEN f = gel(bnr_get_mod(bnr), 1), D = nf_get_disc(nf);
GEN p1, p2;
long Ds, fl, tryf, i = isZ(f);
if (i == 1) return quadhilbertimag(D);
if (absequaliu(D,3))
{
if (i == 4 || i == 5 || i == 7) return polcyclo(i,0);
if (!absequaliu(gcoeff(f,1,1),9) || !absequaliu(Z_content(f),3)) return NULL;
p1 = mkpolmod(bnf_get_tuU(bnf), nf_get_pol(nf));
return gadd(pol_xn(3,0), p1);
}
if (absequaliu(D,4))
{
if (i == 3 || i == 5) return polcyclo(i,0);
if (i != 4) return NULL;
p1 = mkpolmod(bnf_get_tuU(bnf), nf_get_pol(nf));
return gadd(pol_xn(2,0), p1);
}
Ds = smodis(D,48);
if (i)
{
if (i==2 && Ds%16== 8) return compocyclo(nf, 4,1);
if (i==3 && Ds% 3== 1) return compocyclo(nf, 3,1);
if (i==4 && Ds% 8== 1) return compocyclo(nf, 4,1);
if (i==6 && Ds ==40) return compocyclo(nf,12,1);
return NULL;
}
p1 = gcoeff(f,1,1);
tryf = itou_or_0(p1); if (!tryf) return NULL;
p2 = gcoeff(f,2,2);
if (is_pm1(p2)) fl = 0;
else {
if (Ds % 16 != 8 || !absequaliu(Z_content(f),2)) return NULL;
fl = 1; tryf >>= 1;
}
if (tryf <= 3 || umodiu(D, tryf) || !uisprime(tryf)) return NULL;
if (fl) tryf <<= 2;
return compocyclo(nf,tryf,2);
}
GEN
quadray(GEN D, GEN f, long prec)
{
GEN bnr, y, bnf;
pari_sp av = avma;
if (isint1(f)) return quadhilbert(D, prec);
quadray_init(&D, f, &bnf, prec);
bnr = Buchray(bnf, f, nf_INIT|nf_GEN);
if (is_pm1(bnr_get_no(bnr))) { avma = av; return pol_x(0); }
if (signe(D) > 0)
y = bnrstark(bnr,NULL,prec);
else
{
bnr = gel(bnrconductor_i(bnr,NULL,2), 2);
y = treatspecialsigma(bnr);
if (!y) y = computeP2(bnr, prec);
}
return gerepileupto(av, y);
}