1 /* Copyright (C) 2018  The PARI group.
2 
3 This file is part of the PARI/GP package.
4 
5 PARI/GP is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 2 of the License, or (at your option) any later
8 version. It is distributed in the hope that it will be useful, but WITHOUT
9 ANY WARRANTY WHATSOEVER.
10 
11 Check the License for details. You should have received a copy of it, along
12 with the package; see the file 'COPYING'. If not, write to the Free Software
13 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 
15 /********************************************************************/
16 /**       L-functions: values at integers of L-functions           **/
17 /**             of primitive quadratic characters                  **/
18 /********************************************************************/
19 #include "pari.h"
20 #include "paripriv.h"
21 
22 static GEN
RCpol(long k,long t,GEN c)23 RCpol(long k, long t, GEN c)
24 {
25   GEN P = cgetg(k+3, t_POL);
26   long l;
27 
28   gel(P,k+2) = c;
29   for(l = 0; l < k; l++)
30   {
31     c = diviiexact(mulii(c, muluu(2*k-1 - 2*l, k-l)), mulss(l+1, 2*l-t));
32     gel(P,k-l+1) = c;
33   }
34   P[1] = evalsigne(1) | evalvarn(0); return P;
35 }
36 static GEN
vecRCpol(long r,long d)37 vecRCpol(long r, long d)
38 {
39   long k, K = d - 1, t = 2*r - 3;
40   GEN v = cgetg(d + 1, t_VEC), c = int2n(2*K);
41   for (k = 0; k <= K; k++)
42   { /* c = 2^(2K) binomial(n/2,k), an integer */
43     gel(v,k+1) = RCpol(k, t, c);
44     if (k == K) break;
45     c = diviuexact(muliu(c, t - 2*k), 2*k + 2);
46   }
47   return v;
48 }
49 /* D a t_INT */
50 static GEN
RgXV_rescale(GEN v,GEN D)51 RgXV_rescale(GEN v, GEN D)
52 {
53   long j, l;
54   GEN w;
55   if (equali1(D)) return v;
56   w = cgetg_copy(v, &l);
57   for (j = 1; j < l; j++) gel(w,j) = RgX_rescale(gel(v,j), D);
58   return w;
59 }
60 static GEN
euler_sumdiv(GEN q,long v)61 euler_sumdiv(GEN q, long v)
62 {
63   GEN u = addui(1, q);
64   for (; v > 1; v--) u = addui(1, mulii(q, u));
65   return u;
66 }
67 
68 /* [p^{k-1},p^{k-3},...,p^{k-2(d-1)-1}] * (s/p), s = 1 or -1 */
69 static GEN
vpowp(long k,long d,long p,long s)70 vpowp(long k, long d, long p, long s)
71 {
72   GEN v = cgetg(d + 1, t_VEC), p2 = sqru(p);
73   long j;
74   gel(v, d) = powuu(p, k - 2*d + 1);
75   if (s == -1 && (p & 3L) == 3) togglesign_safe(&gel(v,d));
76   for (j = d-1; j >= 1; j--) gel(v, j) = mulii(p2, gel(v, j+1));
77   return v;
78 }
79 static GEN
usumdivk_0_all(long k,long d)80 usumdivk_0_all(long k, long d)
81 {
82   GEN v = cgetg(d + 1, t_COL);
83   long j;
84   constbern(k >> 1);
85   for (j = 1; j <= d; j++)
86   {
87     long n = k + 2 - 2*j;
88     gel(v,j) = gdivgs(bernfrac(n), - (n << 1));
89   }
90   return v;
91 }
92 static GEN
usumdivk_fact_all(GEN fa,long k,long d)93 usumdivk_fact_all(GEN fa, long k, long d)
94 {
95   GEN res, P, E, pow;
96   long i, j, l;
97   res = cgetg(d + 1, t_COL);
98   P = gel(fa, 1); l = lg(P);
99   E = gel(fa, 2); pow = cgetg(l, t_VEC);
100   for (i = 1; i < l; i++) gel(pow, i) = vpowp(k, d, P[i], 1);
101   for (j = 1; j <= d; j++)
102   {
103     GEN v = cgetg(l, t_VEC);
104     for (i = 1; i < l; i++) gel(v,i) = euler_sumdiv(gmael(pow,i,j), E[i]);
105     gel(res, j) = ZV_prod(v);
106   }
107   return res;
108 }
109 
110 /* Hadamard product */
111 static GEN
RgV_mul(GEN a,GEN b)112 RgV_mul(GEN a, GEN b)
113 {
114   long j, l = lg(a);
115   GEN v = cgetg(l, t_COL);
116   for (j = 1; j < l; j++) gel(v,j) = gmul(gel(a,j), gel(b,j));
117   return v;
118 }
119 static GEN
RgV_multwist(GEN a,GEN P,long k,long dim,long d,long v2,long N4)120 RgV_multwist(GEN a, GEN P, long k, long dim, long d, long v2, long N4)
121 {
122   GEN v = cgetg(dim+1, t_COL);
123   long j;
124   for (j = 1; j <= d; j++)
125   {
126     GEN z;
127     gel(v,j) = z = gmul(gel(a,j), gel(P,j));
128     if (j + d <= dim)
129     {
130       if (N4 == 3) z = negi(z);
131       if (v2) z = shifti(z, (k - 2*j + 1)*v2);
132       gel(v, j + d) = z;
133     }
134   }
135   return v;
136 }
137 
138 /* r = k - 2*j, 0<=j<d, factor s=an+b, 0<=s<lim. Check if n starts at 0 or 1
139  * P(D,(an+b)^2), (D-s^2)/N = (D-b^2)/N - 2abn/N - a^2n^2/N and guarantee
140  *  N | D-b^2, N | 2ab, and N | a^2 (except N=8, D odd):
141  * N=4: a=2, b=0,1\equiv D: D = 0,1 mod 4.
142  * N=8: a=4, b=2 if D/4 odd, 0 if D/4 even: D = 0 mod 4 or 1 mod 8
143  * N=12: a=6, b=3 if D odd, 0 if D even: D = 0,1 mod 4
144  * N=-12: a=6, b=5,1 if D odd, 4,2 if D even: D = 0,1 mod 4
145  * N=16: a=8, b=7,1 if D = 1 mod 16, 5,3 if D = 9 mod 16: D = 1 mod 8 */
146 /* Cost: O( sqrt(D)/a d^3 log(D) ) */
147 static GEN
sigsum(long k,long d,long a,long b,long D,long N,GEN vs,GEN vP)148 sigsum(long k, long d, long a, long b, long D, long N, GEN vs, GEN vP)
149 {
150   pari_sp av;
151   GEN S, keep0 = NULL, vPD = RgXV_rescale(vP, stoi(D));
152   long D2, n, c1, c2, s, lim = usqrt(labs(D));
153 
154   D2 = (D - b*b)/N; c1 = (2*a*b)/N; c2 = (a*a)/N;
155   av = avma; S = zerocol(d);
156   for (s = b, n = 0; s <= lim; s += a, n++)
157   {
158     long Ds = c2 ? D2 - n*(c2*n + c1) : D2 - ((n*(n+1)) >> 1);
159     GEN v, P = gsubst(vPD, 0, utoi(s*s));
160     if (vs)
161       v = gel(vs, Ds+1);
162     else
163       v = Ds? usumdivk_fact_all(factoru(Ds), k, d)
164             : usumdivk_0_all(k,d);
165     v = RgV_mul(v, P);
166     if (!s) keep0 = gclone(v); else S = gadd(S, v);
167     if (gc_needed(av, 1)) S = gerepileupto(av, S);
168   }
169   S = gmul2n(S, 1);
170   if (keep0) { S = gadd(S, keep0); gunclone(keep0); }
171   return S;
172 }
173 
174 static GEN
sigsum4(long k,long d,long D,GEN vs,GEN vP)175 sigsum4(long k, long d, long D, GEN vs, GEN vP)
176 { return sigsum(k, d, 2, odd(D), D, 4, vs, vP); }
177 
178 /* D != 5 (mod 8) */
179 static GEN
sigsum8(long k,long d,long D,GEN vs,GEN vP)180 sigsum8(long k, long d, long D, GEN vs, GEN vP)
181 {
182   if (D&1L) return gmul2n(sigsum(k, d, 2, 1, D, 8, vs, vP), -1);
183   return sigsum(k, d, 4, 2*odd(D >> 2), D, 8, vs, vP);
184 }
185 
186 /* D = 0 (mod 3) */
187 static GEN
sigsum12(long k,long d,long D,GEN vs,GEN vP)188 sigsum12(long k, long d, long D, GEN vs, GEN vP)
189 { return sigsum(k, d, 6, 3*odd(D), D, 12, vs, vP); }
190 
191 /* D = 1 (mod 3) */
192 static GEN
sigsumm12(long k,long d,long D,GEN vs,GEN vP)193 sigsumm12(long k, long d, long D, GEN vs, GEN vP)
194 {
195   long fl = odd(D);
196   GEN res = sigsum(k, d, 6, 4 + fl, D, 12, vs, vP);
197   res = gadd(res, sigsum(k, d, 6, 2 - fl, D, 12, vs, vP));
198   return gmul2n(res, -1);
199 }
200 
201 /* D = 1 (mod 8) */
202 static GEN
sigsum16(long k,long d,long D,GEN vs,GEN vP)203 sigsum16(long k, long d, long D, GEN vs, GEN vP)
204 {
205   long fl = (D&15L) == 1;
206   GEN res = sigsum(k, d, 8, 5 + 2*fl, D, 16, vs, vP);
207   return gadd(res, sigsum(k, d, 8, 3 - 2*fl, D, 16, vs, vP));
208 }
209 
210 /* N = 4 (as above), 8 (factor (1+(D/2))), 12 (factor (1+(D/3))),
211    16 (only D=1 mod 8). */
212 static GEN
Dpos(long d,long N,long B)213 Dpos(long d, long N, long B)
214 {
215   GEN vD = cgetg(maxss(B, d) + 1, t_VECSMALL);
216   long D, step, c;
217   switch(N)
218   {
219     case 4:  D = 5;  step = 1; break;
220     case 8:  D = 8;  step = 4; break;
221     case 12: D = 12; step = 3; break;
222     case 16: D = 17; step = 8; break;
223     default: D = 13; step = 3; break; /* -12 */
224   }
225   for (c = 1; c <= d || D <= B; D += step)
226     if (sisfundamental(D)) vD[c++] = D;
227   setlg(vD, c); return vD;
228 }
229 
230 typedef GEN (*SIGMA_F)(long,long,long,GEN,GEN);
231 static SIGMA_F
get_S_even(long N)232 get_S_even(long N)
233 {
234   switch(N) {
235     case 4: return sigsum4;
236     case 8: return sigsum8;
237     case 12:return sigsum12;
238     case 16:return sigsum16;
239     default:return sigsumm12; /* -12 */
240   }
241 }
242 
243 static GEN Lfeq(long D, long k);
244 /* Euler numbers: 1, 0, -1, 0, 5, 0, -61,... */
245 GEN
eulerfrac(long n)246 eulerfrac(long n)
247 {
248   pari_sp av = avma;
249   if (n < 0) pari_err_DOMAIN("eulerfrac", "index", "<", gen_0, stoi(n));
250   if (odd(n)) return gen_0;
251   switch(n)
252   {
253     case 0: return gen_1;
254     case 2: return gen_m1;
255     case 4: return utoipos(5);
256     case 6: return utoineg(61);
257     case 8: return utoipos(1385);
258     case 10:return utoineg(50521);
259     case 12:return utoipos(2702765);
260     case 14:return utoineg(199360981);
261   }
262   return gerepileuptoint(av, gmul2n(Lfeq(-4, n+1), 1));
263 }
264 
265 static GEN
mfDcoefs(GEN F,GEN vD,long d)266 mfDcoefs(GEN F, GEN vD, long d)
267 {
268   long l = lg(vD), i;
269   GEN v = mfcoefs(F, vD[l-1], d), w = cgetg(l, t_COL);
270   if (d == 4)
271     for (i = 1; i < l; i++) gel(w, i) = gel(v, (vD[i]>>2)+1);
272   else
273     for (i = 1; i < l; i++) gel(w, i) = gel(v, vD[i]+1);
274   return w;
275 }
276 
277 static GEN
myinverseimage(GEN M,GEN R,GEN * pden)278 myinverseimage(GEN M, GEN R, GEN *pden)
279 {
280   GEN c = Q_remove_denom(QM_gauss_i(M, R, 1), pden);/* M*res / den = R */
281   if (!c) pari_err_BUG("theta brackets");
282   return c;
283 }
284 
285 static GEN
Hcol(GEN k,long r,GEN vD,long d,long N2)286 Hcol(GEN k, long r, GEN vD, long d, long N2)
287 {
288   long i, l = lg(vD);
289   GEN v;
290   if (r < 5)
291   {
292     v = mfDcoefs(mfEH(k),vD,d);
293     for (i = 1; i < l; i++)
294       if (N2 != 1 && vD[i] % N2) gel(v,i) = gmul2n(gel(v,i), 1);
295     return v;
296   }
297   v = cgetg(l, t_COL);
298   for (i = 1; i < l; i++)
299   {
300     pari_sp av = avma;
301     GEN c = Lfeq(odd(r)? -vD[i]: vD[i], r); /* fundamental */
302     if (N2 != 1 && vD[i] % N2) c = gmul2n(c, 1);
303     gel(v, i) = gerepileupto(av, c);
304   }
305   return v;
306 }
307 
308 /***********************************************************/
309 /*   Modular form method using Half-Integral Weight forms  */
310 /*                      Case D > 0                         */
311 /***********************************************************/
312 static long
dimeven(long r,long N)313 dimeven(long r, long N)
314 {
315   switch(N)
316   {
317     case 4:  return r / 6 + 1;
318     case 12: return r / 3 + 1;
319     default: return r / 4 + 1;
320   }
321 }
322 static long
muleven(long N)323 muleven(long N) { return (N == 4)? 1: 2; }
324 
325 /* L(\chi_D, 1-r) for D > 0 and r > 0 even. */
326 static GEN
modulareven(long D,long r,long N0)327 modulareven(long D, long r, long N0)
328 {
329   long B, d, i, l, N = labs(N0);
330   GEN V, vs, R, M, C, den, L, vP, vD, k = sstoQ(2*r+1, 2);
331   SIGMA_F S = get_S_even(N0);
332 
333   d = dimeven(r, N);
334   B = muleven(N) * mfsturmNgk(N, k);
335   vD = Dpos(d, N0, B);
336   vP = vecRCpol(r, d);
337   l = lg(vD); B = vD[l-1] / N; V = vecfactoru(1, B);
338   vs = cgetg(B+2, t_VEC); gel(vs,1) = usumdivk_0_all(r, d);
339   for (i = 1; i <= B; i++) gel(vs, i+1) = usumdivk_fact_all(gel(V,i), r, d);
340   M = cgetg(l, t_MAT);
341   for (i = 1; i < l; i++)
342   {
343     pari_sp av = avma;
344     gel(M,i) = gerepileupto(av, S(r, d, vD[i], vs, vP));
345   }
346   M = shallowtrans(M);
347   if (r == 2*d)
348   { /* r = 2 or (r = 4 and N = 4) */
349     GEN v = mfDcoefs(mfderiv(mfTheta(NULL), d+1), vD, 1);
350     gel(M, d) = gadd(gel(M, d), gdivgs(v, N*(2*d - 1)));
351   }
352   R = Hcol(k, r, vD, 1, (N == 8 || N0 == 12)? N >> 2: 1);
353   /* Cost is O(d^2) * bitsize(result) ~ O(d^3.8) [heuristic] */
354   C = myinverseimage(M, R, &den);
355 
356   /* Cost: O( sqrt(D)/c d^3 log(D) ), c from findNeven */
357   L = RgV_dotproduct(C, S(r, lg(C)-1, D, NULL, vP));
358   return den? gdiv(L, den): L;
359 }
360 
361 /***********************************************************/
362 /*   Modular form method using Half-Integral Weight forms  */
363 /*                      Case D < 0                         */
364 /***********************************************************/
365 
366 static long
dimodd(long r,long kro,long N)367 dimodd(long r, long kro, long N)
368 {
369   switch(N)
370   {
371     case 1: switch (kro)
372     {
373       case -1:return (r + 3) >> 2;
374       case 0: return (r + 2)/3;
375       case 1: return (r + 1) >> 2;
376     }
377     case 3: return kro? (r + 1) >> 1: ((r << 1) + 2)/3;
378     case 5: switch (kro)
379     {
380       case -1:return (3*r + 2) >> 2;
381       case 0: return r;
382       case 1: return (3*r - 1) >> 2;
383     }
384     case 6: return kro == 1 ? (r + 1) >> 1 : r;
385     default: return r;
386   }
387 }
388 
389 static GEN
Dneg(long n,long kro,long d,long N)390 Dneg(long n, long kro, long d, long N)
391 {
392   GEN vD = cgetg(maxss(n, d) + 1, t_VECSMALL);
393   long D, c, step, N2 = odd(N)? N: N>> 1;
394   switch(kro)
395   {
396     case -1: D = -3; step = 8; break;
397     case 1:  D = -7; step = 8; break;
398     default: D = -8; step = 4; break;
399   }
400   for (c = 1; D >= -n || c <= d; D -= step)
401     if (kross(-D, N2) != -1 && sisfundamental(D)) vD[c++] = -D;
402   setlg(vD, c); return vD;
403 }
404 
405 static GEN
div4(GEN V)406 div4(GEN V)
407 {
408   long l = lg(V), i;
409   GEN W = cgetg(l, t_VECSMALL);
410   for (i = 1; i < l; i++) W[i] = V[i] >> 2;
411   return W;
412 }
413 
414 static GEN
usumdivktwist_fact_all(GEN fa,long k,long d)415 usumdivktwist_fact_all(GEN fa, long k, long d)
416 {
417   GEN V, P, E, pow, res = cgetg(d + 1, t_VEC);
418   long i, j, l;
419 
420   P = gel(fa, 1); l = lg(P);
421   E = gel(fa, 2);
422   if (l > 1 && P[1] == 2) { l--; P++; E++; } /* odd part */
423   pow = cgetg(l, t_VEC);
424   for (i = 1; i < l; i++) gel(pow, i) = vpowp(k, d, P[i], -1);
425   V = cgetg(l, t_VEC);
426   for (j = 1; j <= d; j++)
427   {
428     for (i = 1; i < l; i++) gel(V,i) = euler_sumdiv(gmael(pow,i,j), E[i]);
429     gel(res, j) = ZV_prod(V);
430   }
431   return res;
432 }
433 
434 static long
mulodd(long N,long kro)435 mulodd(long N, long kro)
436 {
437   if (N == 1 || N == 2) return 1;
438   if (kro != 1) return kro? 5: 7;
439   if (N == 3) return 4;
440   if (N == 5) return 5;
441   return 2;
442 }
443 
444 /* Cost: O( sqrt(D)/a d^3 log(D) ) */
445 static GEN
sigsumtwist(long k,long dim,long a,long b,long Da,long N,GEN vs,GEN vP)446 sigsumtwist(long k, long dim, long a, long b, long Da, long N, GEN vs, GEN vP)
447 {
448   GEN vPD, S = zerocol(dim), keep0 = NULL;
449   long D2, n, c1, c2, s, lim = usqrt(Da), d;
450   pari_sp av;
451 
452   if (N > 2 && kross(Da, N == 6 ? 3 : N) == -1) return S;
453   d = (dim + 1) >> 1;
454   vPD = RgXV_rescale(vP, stoi(Da));
455   D2 = (Da - b*b)/N; c1 = (2*a*b)/N; c2 = (a*a)/N;
456   av = avma;
457   for (s = b, n = 0; s <= lim; s += a, n++)
458   {
459     long v2, D4, Ds2, Ds = D2 - n*(c2*n + c1); /* (Da - s^2) / N */
460     GEN v, P;
461     if (!Ds) continue;
462     v2 = vals(Ds); Ds2 = Ds >> v2; D4 = Ds2 & 3L; /* (Ds/2^oo) mod 4 */
463     if (vs)
464       v = gel(vs, Ds+1);
465     else
466       v = usumdivktwist_fact_all(factoru(Ds2), k, d);
467     P = gsubst(vPD, 0, utoi(s*s));
468     v = RgV_multwist(v, P, k, dim, d, v2, D4);
469     if (!s) keep0 = gclone(v); else S = gadd(S, v);
470     if (gc_needed(av, 1)) S = gerepileupto(av, S);
471   }
472   S = gmul2n(S, 1);
473   if (keep0) { S = gadd(S, keep0); gunclone(keep0); }
474   return gmul2n(S, -2*(d-1));
475 }
476 
477 /* Da = |D|; [sum sigma_r^(1)(Da-s^2), sum sigma_r^(2)(Da-s^2)], N = 1 */
478 static GEN
sigsumtwist11(long k,long dim,long Da,long N,GEN vs,GEN vP)479 sigsumtwist11(long k, long dim, long Da, long N, GEN vs, GEN vP)
480 { return sigsumtwist(k, dim, 1, 0, Da, N, vs, vP); }
481 
482 /* Da = |D| or |D|/4 */
483 /* [sum sigma_r^(1)((Da-s^2)/N), sum sigma_r^(2)((Da-s^2)/N)] */
484 /* Case N|Da; N not necessarily prime. */
485 static GEN
sigsumtwist12p0(long k,long dim,long Da,long N,GEN vs,GEN vP)486 sigsumtwist12p0(long k, long dim, long Da, long N, GEN vs, GEN vP)
487 { return sigsumtwist(k, dim, N, 0, Da, N, vs, vP); }
488 
489 /* [sum sigma_r^(1)((Da-s^2)/p), sum sigma_r^(2)((Da-s^2)/p)] */
490 /* Case p\nmid Da */
491 /* p = 3: s = +-1 mod 3;
492  * p = 5: s = +-1 mod 5 if Da = 1 mod 5, s = +-2 mod 5 if Da = 2 mod 5;
493  * p = 7: s=+-1, +-2, +-3 if Da=1,4,2 mod 7;
494  * p = 6: s=+-1, +-2, +-3 if Da=1,4,3 mod 6 */
495 static GEN
sigsumtwist12pt(long k,long dim,long Da,long N,GEN vs,GEN vP)496 sigsumtwist12pt(long k, long dim, long Da, long N, GEN vs, GEN vP)
497 {
498   long t = Da%N, e = 0;
499   GEN res;
500   if (t == 1) e = 1;
501   else if (t == 4) e = 2;
502   else if (t == 2 || t == 3) e = 3;
503   res = sigsumtwist(k, dim, N, N-e, Da, N, vs, vP);
504   if (N-e != e) res = gadd(res, sigsumtwist(k, dim, N, e, Da, N, vs, vP));
505   return res;
506 }
507 
508 static GEN
sigsumtwist12_6(long r,long dim,long Da,long N,GEN vs,GEN vP)509 sigsumtwist12_6(long r, long dim, long Da, long N, GEN vs, GEN vP)
510 {
511   if (Da%12 == 6) return sigsumtwist12p0(r, dim, Da, N, vs, vP);
512   return sigsumtwist12pt(r, dim, Da, N, vs, vP);
513 }
514 static GEN
sigsumtwist12_N(long r,long dim,long Da,long N,GEN vs,GEN vP)515 sigsumtwist12_N(long r, long dim, long Da, long N, GEN vs, GEN vP)
516 {
517   if (Da%N == 0) return sigsumtwist12p0(r, dim, Da, N, vs, vP);
518   return sigsumtwist12pt(r, dim, Da, N, vs, vP);
519 }
520 
521 typedef GEN (*SIGMA_Fodd)(long,long,long,long,GEN,GEN);
522 static SIGMA_Fodd
get_S_odd(long N)523 get_S_odd(long N)
524 {
525   if (N == 1) return sigsumtwist11;
526   if (N == 6) return sigsumtwist12_6;
527   return sigsumtwist12_N;
528 }
529 
530 /* L(\chi_D, 1-r) for D < 0 and r > 0 odd. */
531 static GEN
modularodd(long D,long r,long N0)532 modularodd(long D, long r, long N0)
533 {
534   long B, d, i, l, dim, kro = kross(D, 2), Da = labs(D), N = labs(N0);
535   GEN V, vs, R, M, C, den, L, vP, vD, vD4, k = sstoQ(2*r+1, 2);
536   SIGMA_Fodd S = get_S_odd(N);
537 
538   dim = dimodd(r, kro, N); d = (dim + 1) >> 1;
539   vP = vecRCpol(r, d);
540   B = mulodd(N, kro) * mfsturmNgk(4*N, k);
541   vD = Dneg(B, kro, dim + 5, N);
542   vD4 = kro ? vD : div4(vD);
543   l = lg(vD); B = vD4[l-1] / N; V = vecfactoru(1, B);
544   vs = cgetg(B+2, t_VEC); gel(vs,1) = NULL; /* unused */
545   for (i = 1; i <= B; i++) gel(vs,i+1) = usumdivktwist_fact_all(gel(V,i), r, d);
546   M = cgetg(l, t_MAT);
547   for (i = 1; i < l; i++)
548   {
549     pari_sp av = avma;
550     gel(M,i) = gerepileupto(av, S(r, dim, vD4[i], N, vs, vP));
551   }
552   M = shallowtrans(M);
553   R = Hcol(k, r, vD, kro? 1: 4, odd(N)? N: N >>1);
554   /* Cost O(d^2) * bitsize(result) ~ O(d^3.7) [heuristic] */
555   C = myinverseimage(M, R, &den);
556 
557   if (!kro) Da >>= 2;
558   /* Cost: O( sqrt(D)/c d^3 log(D) ), c from findNodd */
559   L = RgV_dotproduct(C, S(r, lg(C)-1, Da, N, NULL, vP));
560   if (N0 < 0 && (N0 != -6 || Da%3)) den = den? shifti(den,1): gen_2;
561   return den? gdiv(L, den): L;
562 }
563 
564 /********************************************************/
565 /*        Using the Full Functional Equation            */
566 /********************************************************/
567 /* prod_p (1 - (D/p)p^(-k))
568  * Cost O( D/log(D) (k log(kD))^mu ), mu = multiplication exponent */
569 static GEN
Linv(long D,long k,ulong den)570 Linv(long D, long k, ulong den)
571 {
572   pari_sp av;
573   long s, bit, lim, Da = labs(D), prec;
574   double km = k - 1, B = (k-0.5) * log(km*Da/17.079) + 12; /* 17.079 ~ 2Pi e */
575   forprime_t iter;
576   ulong p;
577   GEN P, Q;
578   if (den) B += log((double)den);
579   bit = maxss((long)(B * k)/(M_LN2 * km), 32) + 32;
580   prec = nbits2prec(bit);
581   lim = (long)exp( (B-log(km)) / km ); /* ~ D / (2Pi e) */
582   u_forprime_init(&iter, 3, lim); av = avma;
583   s = kross(D, 2);
584   if (!s) P = real_1(prec);
585   else
586   {
587     Q = real2n(-k, nbits2prec(bit - k));
588     P = (s == 1)? subir(gen_1, Q): addir(gen_1, Q);
589   }
590   while ((p = u_forprime_next(&iter)))
591   {
592     long bitnew;
593     GEN Q;
594     s = kross(D, p); if (!s) continue;
595     bitnew = (long)(bit - k * log2(p));
596     Q = divrr(P, rpowuu(p, k, nbits2prec(maxss(64, bitnew))));
597     P = s == 1? subrr(P, Q): addrr(P, Q);
598     if (gc_needed(av,1)) P = gerepileuptoleaf(av, P);
599   }
600   return P;
601 }
602 
603 static GEN
myround(GEN z,ulong d)604 myround(GEN z, ulong d)
605 {
606   long e;
607   if (d) z = mulru(z, d);
608   z = grndtoi(z, &e); if (e >= -4) pari_err_BUG("lfunquad");
609   return d? Qdiviu(z, d): z;
610 }
611 
612 /* D != 1, k > 2; L(\chi_D, 1-k) using func. eq. */
613 static GEN
Lfeq(long D,long k)614 Lfeq(long D, long k)
615 {
616   GEN z, res;
617   long Da, prec, den = 0;
618 
619   if ((D > 0 && odd(k)) || (D < 0 && !odd(k))) return gen_0;
620   Da = labs(D);
621   if (Da & 3)
622   {
623     long d = (Da - 1) >> 1, kd = k / d;
624     if (odd(kd) && !(k % d) && uisprime(Da)) den = kd * Da;
625   }
626   else if (Da == 4) den = 2;
627   z = Linv(D, k, den); prec = lg(z);
628   z = mulrr(z, powrs(divru(Pi2n(1, prec), Da), k));
629   if (Da != 4) { z = mulrr(z, sqrtr_abs(utor(Da,prec))); shiftr_inplace(z,-1); }
630   res = divrr(mpfactr(k-1, prec), z);
631   if (odd(k/2)) togglesign(res);
632   return myround(res, den);
633 }
634 
635 /* heuristic */
636 static long
usefeq(long D,long k,double c)637 usefeq(long D, long k, double c)
638 {
639   if (k == 2) return 0;
640   if (D < 0) { k = 2*k; D = -D; }
641   return sqrt(D*c) <= k;
642 }
643 
644 static long
findNeven(long D,double * c)645 findNeven(long D, double *c)
646 {
647   long r = D%3;
648   if (!r) { *c = 3; return 12; }
649   if ((D&7L) == 1) { *c = 2; return 16; }
650   if (!odd(D)) { *c = 2; return 8; }
651   if (r == 1) { *c = 1.5; return -12; }
652   *c = 1; return 4;
653 }
654 static long
findNodd(long D,long k,double * c)655 findNodd(long D, long k, double *c)
656 {
657   long Dmod8 = D&7L, r;
658   if (log(k) > 0.7 * log((double)-D)) { *c = 1; return odd(D)? 2: 1; }
659   if (D%7 == 0 && Dmod8 == 5) { *c = 3.5; return 7; }
660   if (D%6 == 0) { *c = 3; return 6; }
661   if (D%5 == 0) { *c = 2.5; return 5; }
662   if (D%3 == 0) { *c = 1.5; return 3; }
663   if (Dmod8 == 5)
664   {
665     r = smodss(D, 7);
666     if (r!=1 && r!=2 && r!=4) { *c = 7./6; return -7; }
667   }
668   if (smodss(D, 3) != 1 && !odd(D)) { *c = 1.5; return -6; }
669   r = smodss(D, 5); if (r != 2 && r != 3) { *c = 5./4; return -5; }
670   *c = 1; return 2;
671 }
672 
673 /* k <= 0 */
674 static GEN
lfunquadneg_i(long D,long k)675 lfunquadneg_i(long D, long k)
676 {
677   double c;
678   long N;
679 
680   if (D == 1) return k == 0 ? gneg(ghalf) : gdivgs(bernfrac(1-k), k-1);
681   if (!sisfundamental(D)) pari_err_TYPE("lfunquad [D not fundamental]",stoi(D));
682   if (k == 0) return D < 0? hclassno(stoi(-D)): gen_0;
683   if ((D > 0 && !odd(k)) || (D < 0 && odd(k))) return gen_0;
684   if (D == -4) return gmul2n(eulerfrac(-k), -1);
685   k = 1 - k;
686   N = D < 0? findNodd(D, k, &c): findNeven(D, &c);
687   if (usefeq(D, k, c)) return Lfeq(D, k);
688   return D < 0? modularodd(D,k,N): modulareven(D,k,N);
689 }
690 /* need k <= 0 and D fundamental */
691 GEN
lfunquadneg(long D,long k)692 lfunquadneg(long D, long k)
693 { pari_sp av = avma; return gerepileupto(av, lfunquadneg_i(D, k)); }
694