Line data Source code
1 : /* Copyright (C) 2000 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. It is distributed in the hope that it will be useful, but WITHOUT
8 : ANY WARRANTY WHATSOEVER.
9 :
10 : Check the License for details. You should have received a copy of it, along
11 : with the package; see the file 'COPYING'. If not, write to the Free Software
12 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
13 :
14 : /*********************************************************************/
15 : /** **/
16 : /** ARITHMETIC FUNCTIONS **/
17 : /** (first part) **/
18 : /** **/
19 : /*********************************************************************/
20 : #include "pari.h"
21 : #include "paripriv.h"
22 :
23 : /******************************************************************/
24 : /* */
25 : /* GENERATOR of (Z/mZ)* */
26 : /* */
27 : /******************************************************************/
28 : static GEN
29 50 : remove2(GEN q) { long v = vali(q); return v? shifti(q, -v): q; }
30 : static ulong
31 58533 : u_remove2(ulong q) { return q >> vals(q); }
32 : GEN
33 50 : odd_prime_divisors(GEN q) { return gel(Z_factor(remove2(q)), 1); }
34 : static GEN
35 58533 : u_odd_prime_divisors(ulong q) { return gel(factoru(u_remove2(q)), 1); }
36 : /* p odd prime, q=(p-1)/2; L0 list of (some) divisors of q = (p-1)/2 or NULL
37 : * (all prime divisors of q); return the q/l, l in L0 */
38 : static GEN
39 251 : is_gener_expo(GEN p, GEN L0)
40 : {
41 251 : GEN L, q = shifti(p,-1);
42 : long i, l;
43 251 : if (L0) {
44 224 : l = lg(L0);
45 224 : L = cgetg(l, t_VEC);
46 : } else {
47 27 : L0 = L = odd_prime_divisors(q);
48 27 : l = lg(L);
49 : }
50 251 : for (i=1; i<l; i++) gel(L,i) = diviiexact(q, gel(L0,i));
51 251 : return L;
52 : }
53 : static GEN
54 58245 : u_is_gener_expo(ulong p, GEN L0)
55 : {
56 58245 : const ulong q = p >> 1;
57 : long i;
58 : GEN L;
59 58245 : if (!L0) L0 = u_odd_prime_divisors(q);
60 58245 : L = cgetg_copy(L0,&i);
61 58245 : while (--i) L[i] = q / uel(L0,i);
62 58245 : return L;
63 : }
64 :
65 : int
66 149789 : is_gener_Fl(ulong x, ulong p, ulong p_1, GEN L)
67 : {
68 : long i;
69 149789 : if (krouu(x, p) >= 0) return 0;
70 163596 : for (i=lg(L)-1; i; i--)
71 : {
72 101398 : ulong t = Fl_powu(x, uel(L,i), p);
73 101398 : if (t == p_1 || t == 1) return 0;
74 : }
75 62198 : return 1;
76 : }
77 : /* assume p prime */
78 : ulong
79 198185 : pgener_Fl_local(ulong p, GEN L0)
80 : {
81 198185 : const pari_sp av = avma;
82 198185 : const ulong p_1 = p-1;
83 : long x;
84 : GEN L;
85 198185 : if (p <= 19) switch(p)
86 : { /* quick trivial cases */
87 21 : case 2: return 1;
88 : case 7:
89 26317 : case 17: return 3;
90 113632 : default: return 2;
91 : }
92 58215 : L = u_is_gener_expo(p,L0);
93 144166 : for (x = 2;; x++)
94 230117 : if (is_gener_Fl(x,p,p_1,L)) return gc_ulong(av, x);
95 : }
96 : ulong
97 156136 : pgener_Fl(ulong p) { return pgener_Fl_local(p, NULL); }
98 :
99 : /* L[i] = set of (p-1)/2l, l ODD prime divisor of p-1 (l=2 can be included,
100 : * but wasteful) */
101 : int
102 533 : is_gener_Fp(GEN x, GEN p, GEN p_1, GEN L)
103 : {
104 533 : long i, t = lgefint(x)==3? kroui(x[2], p): kronecker(x, p);
105 533 : if (t >= 0) return 0;
106 495 : for (i = lg(L)-1; i; i--)
107 : {
108 193 : GEN t = Fp_pow(x, gel(L,i), p);
109 193 : if (equalii(t, p_1) || equali1(t)) return 0;
110 : }
111 302 : return 1;
112 : }
113 :
114 : /* assume p prime, return a generator of all L[i]-Sylows in F_p^*. */
115 : GEN
116 43904 : pgener_Fp_local(GEN p, GEN L0)
117 : {
118 43904 : pari_sp av0 = avma;
119 : GEN x, p_1, L;
120 43904 : if (lgefint(p) == 3)
121 : {
122 : ulong z;
123 43658 : if (p[2] == 2) return gen_1;
124 33991 : if (L0) L0 = ZV_to_nv(L0);
125 33991 : z = pgener_Fl_local(uel(p,2), L0);
126 33991 : set_avma(av0); return utoipos(z);
127 : }
128 246 : p_1 = subiu(p,1); L = is_gener_expo(p, L0);
129 246 : x = utoipos(2);
130 459 : for (;; x[2]++) { if (is_gener_Fp(x, p, p_1, L)) break; }
131 246 : set_avma(av0); return utoipos(uel(x,2));
132 : }
133 :
134 : GEN
135 41832 : pgener_Fp(GEN p) { return pgener_Fp_local(p, NULL); }
136 :
137 : ulong
138 112345 : pgener_Zl(ulong p)
139 : {
140 112345 : if (p == 2) pari_err_DOMAIN("pgener_Zl","p","=",gen_2,gen_2);
141 : /* only p < 2^32 such that znprimroot(p) != znprimroot(p^2) */
142 112345 : if (p == 40487) return 10;
143 : #ifndef LONG_IS_64BIT
144 16045 : return pgener_Fl(p);
145 : #else
146 96300 : if (p < (1UL<<32)) return pgener_Fl(p);
147 : else
148 : {
149 30 : const pari_sp av = avma;
150 30 : const ulong p_1 = p-1;
151 : long x ;
152 30 : GEN p2 = sqru(p), L = u_is_gener_expo(p, NULL);
153 102 : for (x=2;;x++)
154 174 : if (is_gener_Fl(x,p,p_1,L) && !is_pm1(Fp_powu(utoipos(x),p_1,p2)))
155 30 : return gc_ulong(av, x);
156 : }
157 : #endif
158 : }
159 :
160 : /* p prime. Return a primitive root modulo p^e, e > 1 */
161 : GEN
162 112350 : pgener_Zp(GEN p)
163 : {
164 112350 : if (lgefint(p) == 3) return utoipos(pgener_Zl(p[2]));
165 : else
166 : {
167 5 : const pari_sp av = avma;
168 5 : GEN p_1 = subiu(p,1), p2 = sqri(p), L = is_gener_expo(p,NULL);
169 5 : GEN x = utoipos(2);
170 12 : for (;; x[2]++)
171 29 : if (is_gener_Fp(x,p,p_1,L) && !equali1(Fp_pow(x,p_1,p2))) break;
172 5 : set_avma(av); return utoipos(uel(x,2));
173 : }
174 : }
175 :
176 : static GEN
177 231 : gener_Zp(GEN q, GEN F)
178 : {
179 231 : GEN p = NULL;
180 231 : long e = 0;
181 231 : if (F)
182 : {
183 14 : GEN P = gel(F,1), E = gel(F,2);
184 14 : long i, l = lg(P);
185 42 : for (i = 1; i < l; i++)
186 : {
187 28 : p = gel(P,i);
188 28 : if (absequaliu(p, 2)) continue;
189 14 : if (i < l-1) pari_err_DOMAIN("znprimroot", "argument","=",F,F);
190 14 : e = itos(gel(E,i));
191 : }
192 14 : if (!p) pari_err_DOMAIN("znprimroot", "argument","=",F,F);
193 : }
194 : else
195 217 : e = Z_isanypower(q, &p);
196 231 : return e > 1? pgener_Zp(p): pgener_Fp(q);
197 : }
198 :
199 : GEN
200 301 : znprimroot(GEN N)
201 : {
202 301 : pari_sp av = avma;
203 : GEN x, n, F;
204 :
205 301 : if ((F = check_arith_non0(N,"znprimroot")))
206 : {
207 14 : F = clean_Z_factor(F);
208 14 : N = typ(N) == t_VEC? gel(N,1): factorback(F);
209 : }
210 294 : N = absi_shallow(N);
211 294 : if (abscmpiu(N, 4) <= 0) { set_avma(av); return mkintmodu(N[2]-1,N[2]); }
212 245 : switch(mod4(N))
213 : {
214 : case 0: /* N = 0 mod 4 */
215 14 : pari_err_DOMAIN("znprimroot", "argument","=",N,N);
216 0 : x = NULL; break;
217 : case 2: /* N = 2 mod 4 */
218 21 : n = shifti(N,-1); /* becomes odd */
219 21 : x = gener_Zp(n,F); if (!mod2(x)) x = addii(x,n);
220 21 : break;
221 : default: /* N odd */
222 210 : x = gener_Zp(N,F);
223 210 : break;
224 : }
225 231 : return gerepilecopy(av, mkintmod(x, N));
226 : }
227 :
228 : /* n | (p-1), returns a primitive n-th root of 1 in F_p^* */
229 : GEN
230 0 : rootsof1_Fp(GEN n, GEN p)
231 : {
232 0 : pari_sp av = avma;
233 0 : GEN L = odd_prime_divisors(n); /* 2 implicit in pgener_Fp_local */
234 0 : GEN z = pgener_Fp_local(p, L);
235 0 : z = Fp_pow(z, diviiexact(subiu(p,1), n), p); /* prim. n-th root of 1 */
236 0 : return gerepileuptoint(av, z);
237 : }
238 :
239 : GEN
240 217 : rootsof1u_Fp(ulong n, GEN p)
241 : {
242 217 : pari_sp av = avma;
243 217 : GEN z, L = u_odd_prime_divisors(n); /* 2 implicit in pgener_Fp_local */
244 217 : z = pgener_Fp_local(p, Flv_to_ZV(L));
245 217 : z = Fp_pow(z, diviuexact(subiu(p,1), n), p); /* prim. n-th root of 1 */
246 217 : return gerepileuptoint(av, z);
247 : }
248 :
249 : ulong
250 6098 : rootsof1_Fl(ulong n, ulong p)
251 : {
252 6098 : pari_sp av = avma;
253 6098 : GEN L = u_odd_prime_divisors(n); /* 2 implicit in pgener_Fl_local */
254 6098 : ulong z = pgener_Fl_local(p, L);
255 6098 : z = Fl_powu(z, (p-1) / n, p); /* prim. n-th root of 1 */
256 6098 : return gc_ulong(av,z);
257 : }
258 :
259 : /*********************************************************************/
260 : /** **/
261 : /** INVERSE TOTIENT FUNCTION **/
262 : /** **/
263 : /*********************************************************************/
264 : /* N t_INT, L a ZV containing all prime divisors of N, and possibly other
265 : * primes. Return factor(N) */
266 : GEN
267 350651 : Z_factor_listP(GEN N, GEN L)
268 : {
269 350651 : long i, k, l = lg(L);
270 350651 : GEN P = cgetg(l, t_COL), E = cgetg(l, t_COL);
271 1346688 : for (i = k = 1; i < l; i++)
272 : {
273 996037 : GEN p = gel(L,i);
274 996037 : long v = Z_pvalrem(N, p, &N);
275 996037 : if (v)
276 : {
277 792176 : gel(P,k) = p;
278 792176 : gel(E,k) = utoipos(v);
279 792176 : k++;
280 : }
281 : }
282 350651 : setlg(P, k);
283 350651 : setlg(E, k); return mkmat2(P,E);
284 : }
285 :
286 : /* look for x such that phi(x) = n, p | x => p > m (if m = NULL: no condition).
287 : * L is a list of primes containing all prime divisors of n. */
288 : static long
289 621565 : istotient_i(GEN n, GEN m, GEN L, GEN *px)
290 : {
291 621565 : pari_sp av = avma, av2;
292 : GEN k, D;
293 : long i, v;
294 621565 : if (m && mod2(n))
295 : {
296 270914 : if (!equali1(n)) return 0;
297 69986 : if (px) *px = gen_1;
298 69986 : return 1;
299 : }
300 350651 : D = divisors(Z_factor_listP(shifti(n, -1), L));
301 : /* loop through primes p > m, d = p-1 | n */
302 350651 : av2 = avma;
303 350651 : if (!m)
304 : { /* special case p = 2, d = 1 */
305 69986 : k = n;
306 69986 : for (v = 1;; v++) {
307 69986 : if (istotient_i(k, gen_2, L, px)) {
308 69986 : if (px) *px = shifti(*px, v);
309 69986 : return 1;
310 : }
311 0 : if (mod2(k)) break;
312 0 : k = shifti(k,-1);
313 : }
314 0 : set_avma(av2);
315 : }
316 1099462 : for (i = 1; i < lg(D); ++i)
317 : {
318 1001588 : GEN p, d = shifti(gel(D, i), 1); /* even divisors of n */
319 1001588 : if (m && cmpii(d, m) < 0) continue;
320 677782 : p = addiu(d, 1);
321 677782 : if (!isprime(p)) continue;
322 442064 : k = diviiexact(n, d);
323 481593 : for (v = 1;; v++) {
324 : GEN r;
325 481593 : if (istotient_i(k, p, L, px)) {
326 182791 : if (px) *px = mulii(*px, powiu(p, v));
327 182791 : return 1;
328 : }
329 298802 : k = dvmdii(k, p, &r);
330 298802 : if (r != gen_0) break;
331 : }
332 259273 : set_avma(av2);
333 : }
334 97874 : return gc_long(av,0);
335 : }
336 :
337 : /* find x such that phi(x) = n */
338 : long
339 70000 : istotient(GEN n, GEN *px)
340 : {
341 70000 : pari_sp av = avma;
342 70000 : if (typ(n) != t_INT) pari_err_TYPE("istotient", n);
343 70000 : if (signe(n) < 1) return 0;
344 70000 : if (mod2(n))
345 : {
346 14 : if (!equali1(n)) return 0;
347 14 : if (px) *px = gen_1;
348 14 : return 1;
349 : }
350 69986 : if (istotient_i(n, NULL, gel(Z_factor(n), 1), px))
351 : {
352 69986 : if (!px) set_avma(av);
353 : else
354 69986 : *px = gerepileuptoint(av, *px);
355 69986 : return 1;
356 : }
357 0 : return gc_long(av,0);
358 : }
359 :
360 : /*********************************************************************/
361 : /** **/
362 : /** INTEGRAL LOGARITHM **/
363 : /** **/
364 : /*********************************************************************/
365 :
366 : /* y > 1 and B > 0 integers. Return e such that y^e <= B < y^(e+1), i.e
367 : * e = floor(log_y B). Set *ptq = y^e if non-NULL */
368 : long
369 306663 : ulogintall(ulong B, ulong y, ulong *ptq)
370 : {
371 : ulong r, r2;
372 : long e;
373 :
374 306663 : if (y == 2)
375 : {
376 7708 : long eB = expu(B); /* 2^eB <= B < 2^(eB + 1) */
377 7708 : if (ptq) *ptq = 1UL << eB;
378 7708 : return eB;
379 : }
380 298955 : r = y, r2 = 1UL;
381 1015371 : for (e=1;; e++)
382 : { /* here, r = y^e, r2 = y^(e-1) */
383 1731787 : if (r >= B)
384 : {
385 298769 : if (r != B) { e--; r = r2; }
386 298769 : if (ptq) *ptq = r;
387 298769 : return e;
388 : }
389 716602 : r2 = r;
390 716602 : r = umuluu_or_0(y, r);
391 716602 : if (!r)
392 : {
393 186 : if (ptq) *ptq = r2;
394 186 : return e;
395 : }
396 : }
397 : }
398 :
399 : /* y > 1 and B > 0 integers. Return e such that y^e <= B < y^(e+1), i.e
400 : * e = floor(log_y B). Set *ptq = y^e if non-NULL */
401 : long
402 318787 : logintall(GEN B, GEN y, GEN *ptq)
403 : {
404 : pari_sp av;
405 318787 : long ey, e, emax, i, eB = expi(B); /* 2^eB <= B < 2^(eB + 1) */
406 : GEN q, pow2;
407 :
408 318787 : if (lgefint(B) == 3)
409 : {
410 : ulong q;
411 306663 : if (lgefint(y) > 3)
412 : {
413 0 : if (ptq) *ptq = gen_1;
414 0 : return 0;
415 : }
416 306663 : if (!ptq) return ulogintall(B[2], y[2], NULL);
417 50571 : e = ulogintall(B[2], y[2], &q);
418 50571 : *ptq = utoi(q); return e;
419 : }
420 12124 : if (equaliu(y,2))
421 : {
422 166 : if (ptq) *ptq = int2n(eB);
423 166 : return eB;
424 : }
425 11958 : av = avma;
426 11958 : ey = expi(y);
427 : /* eB/(ey+1) - 1 < e <= eB/ey */
428 11958 : emax = eB/ey;
429 11958 : if (emax <= 13) /* e small, be naive */
430 : {
431 1960 : GEN r = y, r2 = gen_1;
432 21138 : for (e=1;; e++)
433 19178 : { /* here, r = y^e, r2 = y^(e-1) */
434 21138 : long fl = cmpii(r, B);
435 21138 : if (fl >= 0)
436 : {
437 1960 : if (fl) { e--; cgiv(r); r = r2; }
438 1960 : if (ptq) *ptq = gerepileuptoint(av, r); else set_avma(av);
439 1960 : return e;
440 : }
441 19178 : r2 = r; r = mulii(r,y);
442 : }
443 : }
444 : /* e >= 13 ey / (ey+1) >= 6.5 */
445 :
446 : /* binary splitting: compute bits of e one by one */
447 : /* compute pow2[i] = y^(2^i) [i < crude upper bound for log_2 log_y(B)] */
448 9998 : pow2 = new_chunk((long)log2(eB)+2);
449 9998 : gel(pow2,0) = y;
450 9998 : for (i=0, q=y;; )
451 49635 : {
452 59633 : GEN r = gel(pow2,i); /* r = y^2^i */
453 59633 : long fl = cmpii(r,B);
454 59633 : if (!fl)
455 : {
456 0 : e = 1L<<i;
457 0 : if (ptq) *ptq = gerepileuptoint(av, r); else set_avma(av);
458 0 : return e;
459 : }
460 59633 : if (fl > 0) { i--; break; }
461 56279 : q = r;
462 56279 : if (1L<<(i+1) > emax) break;
463 49635 : gel(pow2,++i) = sqri(q);
464 : }
465 :
466 9998 : for (e = 1L<<i;;)
467 46260 : { /* y^e = q < B < r = q * y^(2^i) */
468 56258 : pari_sp av2 = avma;
469 : long fl;
470 : GEN r;
471 56258 : if (--i < 0) break;
472 46267 : r = mulii(q, gel(pow2,i));
473 46267 : fl = cmpii(r, B);
474 46267 : if (fl > 0) set_avma(av2);
475 : else
476 : {
477 22337 : e += (1L<<i);
478 22337 : q = r;
479 22337 : if (!fl) break; /* B = r */
480 : }
481 : }
482 9998 : if (ptq) *ptq = gerepileuptoint(av, q); else set_avma(av);
483 9998 : return e;
484 : }
485 :
486 : long
487 56 : logint0(GEN B, GEN y, GEN *ptq)
488 : {
489 56 : if (typ(B) != t_INT) pari_err_TYPE("logint",B);
490 56 : if (signe(B) <= 0) pari_err_DOMAIN("logint", "x" ,"<=", gen_0, B);
491 56 : if (typ(y) != t_INT) pari_err_TYPE("logint",y);
492 56 : if (cmpis(y, 2) < 0) pari_err_DOMAIN("logint", "b" ,"<=", gen_1, y);
493 56 : return logintall(B,y,ptq);
494 : }
495 :
496 : /*********************************************************************/
497 : /** **/
498 : /** INTEGRAL SQUARE ROOT **/
499 : /** **/
500 : /*********************************************************************/
501 : GEN
502 30472 : sqrtint(GEN a)
503 : {
504 30472 : if (typ(a) != t_INT) pari_err_TYPE("sqrtint",a);
505 30472 : switch (signe(a))
506 : {
507 30458 : case 1: return sqrti(a);
508 7 : case 0: return gen_0;
509 7 : default: pari_err_DOMAIN("sqrtint", "argument", "<", gen_0,a);
510 : }
511 : return NULL; /* LCOV_EXCL_LINE */
512 : }
513 :
514 : /*********************************************************************/
515 : /** **/
516 : /** PERFECT SQUARE **/
517 : /** **/
518 : /*********************************************************************/
519 : static int
520 14939108 : carremod(ulong A)
521 : {
522 14939108 : const int carresmod64[]={
523 : 1,1,0,0,1,0,0,0,0,1, 0,0,0,0,0,0,1,1,0,0, 0,0,0,0,0,1,0,0,0,0,
524 : 0,0,0,1,0,0,1,0,0,0, 0,1,0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,1,0,0, 0,0,0,0};
525 14939108 : const int carresmod63[]={
526 : 1,1,0,0,1,0,0,1,0,1, 0,0,0,0,0,0,1,0,1,0, 0,0,1,0,0,1,0,0,1,0,
527 : 0,0,0,0,0,0,1,1,0,0, 0,0,0,1,0,0,1,0,0,1, 0,0,0,0,0,0,0,0,1,0, 0,0,0};
528 14939108 : const int carresmod65[]={
529 : 1,1,0,0,1,0,0,0,0,1, 1,0,0,0,1,0,1,0,0,0, 0,0,0,0,0,1,1,0,0,1,
530 : 1,0,0,0,0,1,1,0,0,1, 1,0,0,0,0,0,0,0,0,1, 0,1,0,0,0,1,1,0,0,0, 0,1,0,0,1};
531 14939108 : const int carresmod11[]={1,1,0,1,1,1,0,0,0,1, 0};
532 14939108 : return (carresmod64[A & 0x3fUL]
533 5483650 : && carresmod63[A % 63UL]
534 3229420 : && carresmod65[A % 65UL]
535 17615342 : && carresmod11[A % 11UL]);
536 : }
537 :
538 : /* emulate Z_issquareall on single-word integers */
539 : long
540 13444516 : uissquareall(ulong A, ulong *sqrtA)
541 : {
542 13444516 : if (!A) { *sqrtA = 0; return 1; }
543 13444516 : if (carremod(A))
544 : {
545 1828943 : ulong a = usqrt(A);
546 1828933 : if (a * a == A) { *sqrtA = a; return 1; }
547 : }
548 11707298 : return 0;
549 : }
550 : long
551 122288 : uissquare(ulong A)
552 : {
553 122288 : if (!A) return 1;
554 122288 : if (carremod(A))
555 : {
556 3553 : ulong a = usqrt(A);
557 3553 : if (a * a == A) return 1;
558 : }
559 118759 : return 0;
560 : }
561 :
562 : long
563 6384307 : Z_issquareall(GEN x, GEN *pt)
564 : {
565 : pari_sp av;
566 : GEN y, r;
567 :
568 6384307 : switch(signe(x))
569 : {
570 2208484 : case -1: return 0;
571 420 : case 0: if (pt) *pt=gen_0; return 1;
572 : }
573 4175403 : if (lgefint(x) == 3)
574 : {
575 2803141 : ulong u = uel(x,2), a;
576 2803141 : if (!pt) return uissquare(u);
577 2680853 : if (!uissquareall(u, &a)) return 0;
578 1377988 : *pt = utoipos(a); return 1;
579 : }
580 1372262 : if (!carremod(umodiu(x, 64*63*65*11))) return 0;
581 609981 : av = avma; y = sqrtremi(x, &r);
582 609981 : if (r != gen_0) return gc_long(av,0);
583 18586 : if (pt) { *pt = y; set_avma((pari_sp)y); } else set_avma(av);
584 18586 : return 1;
585 : }
586 :
587 : /* a t_INT, p prime */
588 : long
589 0 : Zp_issquare(GEN a, GEN p)
590 : {
591 : long v;
592 : GEN ap;
593 :
594 0 : if (!signe(a) || gequal1(a)) return 1;
595 0 : v = Z_pvalrem(a, p, &ap);
596 0 : if (v&1) return 0;
597 0 : return absequaliu(p, 2)? umodiu(ap, 8) == 1
598 0 : : kronecker(ap,p) == 1;
599 : }
600 :
601 : static long
602 3262 : polissquareall(GEN x, GEN *pt)
603 : {
604 : pari_sp av;
605 : long v;
606 : GEN y, a, b, p;
607 :
608 3262 : if (!signe(x))
609 : {
610 7 : if (pt) *pt = gcopy(x);
611 7 : return 1;
612 : }
613 3255 : if (odd(degpol(x))) return 0; /* odd degree */
614 2387 : av = avma;
615 2387 : v = RgX_valrem(x, &x);
616 2387 : if (v & 1) return gc_long(av,0);
617 2380 : a = gel(x,2); /* test constant coeff */
618 2380 : if (!pt)
619 70 : { if (!issquare(a)) return gc_long(av,0); }
620 : else
621 2310 : { if (!issquareall(a,&b)) return gc_long(av,0); }
622 2380 : if (!degpol(x)) { /* constant polynomial */
623 77 : if (!pt) return gc_long(av,1);
624 35 : y = scalarpol(b, varn(x)); goto END;
625 : }
626 2303 : p = characteristic(x);
627 2303 : if (signe(p) && !mod2(p))
628 : {
629 : long i, lx;
630 35 : if (!absequaliu(p,2)) pari_err_IMPL("issquare for even characteristic != 2");
631 28 : x = gmul(x, mkintmod(gen_1, gen_2));
632 28 : lx = lg(x);
633 28 : if ((lx-3) & 1) return gc_long(av,0);
634 49 : for (i = 3; i < lx; i+=2)
635 28 : if (!gequal0(gel(x,i))) return gc_long(av,0);
636 21 : if (pt) {
637 14 : y = cgetg((lx+3) / 2, t_POL);
638 49 : for (i = 2; i < lx; i+=2)
639 35 : if (!issquareall(gel(x,i), &gel(y, (i+2)>>1))) return gc_long(av,0);
640 14 : y[1] = evalsigne(1) | evalvarn(varn(x));
641 14 : goto END;
642 : } else {
643 21 : for (i = 2; i < lx; i+=2)
644 14 : if (!issquare(gel(x,i))) return gc_long(av,0);
645 7 : return gc_long(av,1);
646 : }
647 : }
648 : else
649 : {
650 2268 : long m = 1;
651 2268 : x = RgX_Rg_div(x,a);
652 : /* a(x^m) = B^2 => B = b(x^m) provided a(0) != 0 */
653 2268 : if (!signe(p)) x = RgX_deflate_max(x,&m);
654 2268 : y = ser2rfrac_i(gsqrt(RgX_to_ser(x,lg(x)-1),0));
655 3647 : if (!RgX_equal(RgX_sqr(y), x)) return gc_long(av,0);
656 896 : if (!pt) return gc_long(av,1);
657 889 : if (!gequal1(a)) y = gmul(b, y);
658 889 : if (m != 1) y = RgX_inflate(y,m);
659 : }
660 : END:
661 938 : if (v) y = RgX_shift_shallow(y, v>>1);
662 938 : *pt = gerepilecopy(av, y); return 1;
663 : }
664 :
665 : /* b unit mod p */
666 : static int
667 287 : Up_ispower(GEN b, GEN K, GEN p, long d, GEN *pt)
668 : {
669 287 : if (d == 1)
670 : { /* mod p: faster */
671 203 : if (!Fp_ispower(b, K, p)) return 0;
672 203 : if (pt) *pt = Fp_sqrtn(b, K, p, NULL);
673 : }
674 : else
675 : { /* mod p^{2 +} */
676 84 : if (!ispower(cvtop(b, p, d), K, pt)) return 0;
677 63 : if (pt) *pt = gtrunc(*pt);
678 : }
679 266 : return 1;
680 : }
681 :
682 : /* We're studying whether a mod (q*p^e) is a K-th power, (q,p) = 1.
683 : * Decide mod p^e, then reduce a mod q unless q = NULL. */
684 : static int
685 427 : handle_pe(GEN *pa, GEN q, GEN L, GEN K, GEN p, long e)
686 : {
687 : GEN t, A;
688 427 : long v = Z_pvalrem(*pa, p, &A), d = e - v;
689 427 : if (d <= 0) t = gen_0;
690 : else
691 : {
692 : ulong r;
693 371 : v = uabsdivui_rem(v, K, &r);
694 371 : if (r || !Up_ispower(A, K, p, d, L? &t: NULL)) return 0;
695 266 : if (L && v) t = mulii(t, powiu(p, v));
696 : }
697 322 : if (q) *pa = modii(*pa, q);
698 322 : if (L) vectrunc_append(L, mkintmod(t, powiu(p, e)));
699 322 : return 1;
700 : }
701 : long
702 329 : Zn_ispower(GEN a, GEN q, GEN K, GEN *pt)
703 : {
704 : GEN L, N;
705 : pari_sp av;
706 : long e, i, l;
707 : ulong pp;
708 : forprime_t S;
709 :
710 329 : if (!signe(a))
711 : {
712 21 : if (pt) {
713 21 : GEN t = cgetg(3, t_INTMOD);
714 21 : gel(t,1) = icopy(q); gel(t,2) = gen_0; *pt = t;
715 : }
716 21 : return 1;
717 : }
718 : /* a != 0 */
719 308 : av = avma;
720 :
721 308 : if (typ(q) != t_INT) /* integer factorization */
722 : {
723 0 : GEN P = gel(q,1), E = gel(q,2);
724 0 : l = lg(P);
725 0 : L = pt? vectrunc_init(l): NULL;
726 0 : for (i = 1; i < l; i++)
727 : {
728 0 : GEN p = gel(P,i);
729 0 : long e = itos(gel(E,i));
730 0 : if (!handle_pe(&a, NULL, L, K, p, e)) return gc_long(av,0);
731 : }
732 0 : goto END;
733 : }
734 308 : if (!mod2(K)
735 189 : && kronecker(a, shifti(q,-vali(q))) == -1) return gc_long(av,0);
736 301 : L = pt? vectrunc_init(expi(q)+1): NULL;
737 301 : u_forprime_init(&S, 2, tridiv_bound(q));
738 301 : while ((pp = u_forprime_next(&S)))
739 : {
740 : int stop;
741 883407 : e = Z_lvalrem_stop(&q, pp, &stop);
742 883407 : if (!e) continue;
743 203 : if (!handle_pe(&a, q, L, K, utoipos(pp), e)) return gc_long(av,0);
744 161 : if (stop)
745 : {
746 126 : if (!is_pm1(q) && !handle_pe(&a, q, L, K, q, 1)) return gc_long(av,0);
747 126 : goto END;
748 : }
749 : }
750 154 : l = lg(primetab);
751 154 : for (i = 1; i < l; i++)
752 : {
753 0 : GEN p = gel(primetab,i);
754 0 : e = Z_pvalrem(q, p, &q);
755 0 : if (!e) continue;
756 0 : if (!handle_pe(&a, q, L, K, p, e)) return gc_long(av,0);
757 0 : if (is_pm1(q)) goto END;
758 : }
759 154 : N = gcdii(a,q);
760 154 : if (!is_pm1(N))
761 : {
762 112 : if (ifac_isprime(N))
763 : {
764 70 : e = Z_pvalrem(q, N, &q);
765 70 : if (!handle_pe(&a, q, L, K, N, e)) return gc_long(av,0);
766 : }
767 : else
768 : {
769 42 : GEN part = ifac_start(N, 0);
770 : for(;;)
771 42 : {
772 : long e;
773 : GEN p;
774 84 : if (!ifac_next(&part, &p, &e)) break;
775 42 : e = Z_pvalrem(q, p, &q);
776 42 : if (!handle_pe(&a, q, L, K, p, e)) return gc_long(av,0);
777 : }
778 : }
779 : }
780 84 : if (!is_pm1(q))
781 : {
782 84 : if (ifac_isprime(q))
783 : {
784 28 : if (!handle_pe(&a, q, L, K, q, 1)) return gc_long(av,0);
785 : }
786 : else
787 : {
788 56 : GEN part = ifac_start(q, 0);
789 : for(;;)
790 84 : {
791 : long e;
792 : GEN p;
793 140 : if (!ifac_next(&part, &p, &e)) break;
794 98 : if (!handle_pe(&a, q, L, K, p, e)) return gc_long(av,0);
795 : }
796 : }
797 : }
798 : END:
799 196 : if (pt) *pt = gerepileupto(av, chinese1_coprime_Z(L));
800 196 : return 1;
801 : }
802 :
803 : static long
804 56 : polmodispower(GEN x, GEN K, GEN *pt)
805 : {
806 56 : pari_sp av = avma;
807 56 : GEN p = NULL, T = NULL;
808 56 : if (Rg_is_FpXQ(x, &T,&p) && p)
809 : {
810 42 : x = liftall_shallow(x);
811 42 : if (T) T = liftall_shallow(T);
812 42 : if (!Fq_ispower(x, K, T, p)) return gc_long(av,0);
813 28 : if (!pt) return gc_long(av,1);
814 21 : x = Fq_sqrtn(x, K, T,p, NULL);
815 21 : if (typ(x) == t_INT)
816 7 : x = Fp_to_mod(x,p);
817 : else
818 14 : x = mkpolmod(FpX_to_mod(x,p), FpX_to_mod(T,p));
819 21 : *pt = gerepilecopy(av, x); return 1;
820 : }
821 14 : pari_err_IMPL("ispower for general t_POLMOD");
822 0 : return 0;
823 : }
824 :
825 : long
826 164221 : issquareall(GEN x, GEN *pt)
827 : {
828 164221 : long tx = typ(x);
829 : GEN F;
830 : pari_sp av;
831 :
832 164221 : if (!pt) return issquare(x);
833 20867 : switch(tx)
834 : {
835 2611 : case t_INT: return Z_issquareall(x, pt);
836 161 : case t_FRAC: av = avma;
837 161 : F = cgetg(3, t_FRAC);
838 161 : if ( !Z_issquareall(gel(x,1), &gel(F,1))
839 105 : || !Z_issquareall(gel(x,2), &gel(F,2))) return gc_long(av,0);
840 105 : *pt = F; return 1;
841 :
842 : case t_POLMOD:
843 21 : return polmodispower(x, gen_2, pt);
844 3171 : case t_POL: return polissquareall(x,pt);
845 14 : case t_RFRAC: av = avma;
846 14 : F = cgetg(3, t_RFRAC);
847 14 : if ( !issquareall(gel(x,1), &gel(F,1))
848 14 : || !polissquareall(gel(x,2), &gel(F,2))) return gc_long(av,0);
849 7 : *pt = F; return 1;
850 :
851 : case t_REAL: case t_COMPLEX: case t_PADIC: case t_SER:
852 14784 : if (!issquare(x)) return 0;
853 14784 : *pt = gsqrt(x, DEFAULTPREC); return 1;
854 :
855 : case t_INTMOD:
856 63 : return Zn_ispower(gel(x,2), gel(x,1), gen_2, pt);
857 :
858 42 : case t_FFELT: return FF_issquareall(x, pt);
859 :
860 : }
861 0 : pari_err_TYPE("issquareall",x);
862 : return 0; /* LCOV_EXCL_LINE */
863 : }
864 :
865 : long
866 158439 : issquare(GEN x)
867 : {
868 : pari_sp av;
869 : GEN a, p;
870 : long v;
871 :
872 158439 : switch(typ(x))
873 : {
874 : case t_INT:
875 143284 : return Z_issquare(x);
876 :
877 : case t_REAL:
878 14714 : return (signe(x)>=0);
879 :
880 : case t_INTMOD:
881 77 : return Zn_ispower(gel(x,2), gel(x,1), gen_2, NULL);
882 :
883 : case t_FRAC:
884 21 : return Z_issquare(gel(x,1)) && Z_issquare(gel(x,2));
885 :
886 7 : case t_FFELT: return FF_issquareall(x, NULL);
887 :
888 : case t_COMPLEX:
889 56 : return 1;
890 :
891 : case t_PADIC:
892 126 : a = gel(x,4); if (!signe(a)) return 1;
893 126 : if (valp(x)&1) return 0;
894 112 : p = gel(x,2);
895 112 : if (!absequaliu(p, 2)) return (kronecker(a,p) != -1);
896 :
897 42 : v = precp(x); /* here p=2, a is odd */
898 42 : if ((v>=3 && mod8(a) != 1 ) ||
899 0 : (v==2 && mod4(a) != 1)) return 0;
900 21 : return 1;
901 :
902 : case t_POLMOD:
903 21 : return polmodispower(x, gen_2, NULL);
904 :
905 : case t_POL:
906 77 : return polissquareall(x,NULL);
907 :
908 : case t_SER:
909 49 : if (!signe(x)) return 1;
910 42 : if (valp(x)&1) return 0;
911 35 : return issquare(gel(x,2));
912 :
913 : case t_RFRAC:
914 7 : av = avma; return gc_long(av, issquare(gmul(gel(x,1),gel(x,2))));
915 : }
916 0 : pari_err_TYPE("issquare",x);
917 : return 0; /* LCOV_EXCL_LINE */
918 : }
919 0 : GEN gissquare(GEN x) { return issquare(x)? gen_1: gen_0; }
920 0 : GEN gissquareall(GEN x, GEN *pt) { return issquareall(x,pt)? gen_1: gen_0; }
921 :
922 : long
923 1386 : ispolygonal(GEN x, GEN S, GEN *N)
924 : {
925 1386 : pari_sp av = avma;
926 : GEN D, d, n;
927 1386 : if (typ(x) != t_INT) pari_err_TYPE("ispolygonal", x);
928 1386 : if (typ(S) != t_INT) pari_err_TYPE("ispolygonal", S);
929 1386 : if (abscmpiu(S,3) < 0) pari_err_DOMAIN("ispolygonal","s","<", utoipos(3),S);
930 1386 : if (signe(x) < 0) return 0;
931 1386 : if (signe(x) == 0) { if (N) *N = gen_0; return 1; }
932 1260 : if (is_pm1(x)) { if (N) *N = gen_1; return 1; }
933 : /* n = (sqrt( (8s - 16) x + (s-4)^2 ) + s - 4) / 2(s - 2) */
934 1134 : if (abscmpiu(S, 1<<16) < 0) /* common case ! */
935 : {
936 441 : ulong s = S[2], r;
937 504 : if (s == 4) return Z_issquareall(x, N);
938 378 : if (s == 3)
939 0 : D = addiu(shifti(x, 3), 1);
940 : else
941 378 : D = addiu(mului(8*s - 16, x), (s-4)*(s-4));
942 378 : if (!Z_issquareall(D, &d)) return gc_long(av,0);
943 378 : if (s == 3)
944 0 : d = subiu(d, 1);
945 : else
946 378 : d = addiu(d, s - 4);
947 378 : n = absdiviu_rem(d, 2*s - 4, &r);
948 378 : if (r) return gc_long(av,0);
949 : }
950 : else
951 : {
952 693 : GEN r, S_2 = subiu(S,2), S_4 = subiu(S,4);
953 693 : D = addii(mulii(shifti(S_2,3), x), sqri(S_4));
954 693 : if (!Z_issquareall(D, &d)) return gc_long(av,0);
955 693 : d = addii(d, S_4);
956 693 : n = dvmdii(shifti(d,-1), S_2, &r);
957 693 : if (r != gen_0) return gc_long(av,0);
958 : }
959 1071 : if (N) *N = gerepileuptoint(av, n); else set_avma(av);
960 1071 : return 1;
961 : }
962 :
963 : /*********************************************************************/
964 : /** **/
965 : /** PERFECT POWER **/
966 : /** **/
967 : /*********************************************************************/
968 : static long
969 721 : polispower(GEN x, GEN K, GEN *pt)
970 : {
971 : pari_sp av;
972 721 : long v, d, k = itos(K);
973 : GEN y, a, b;
974 721 : GEN T = NULL, p = NULL;
975 :
976 721 : if (!signe(x))
977 : {
978 7 : if (pt) *pt = gcopy(x);
979 7 : return 1;
980 : }
981 714 : d = degpol(x);
982 714 : if (d % k) return 0; /* degree not multiple of k */
983 707 : av = avma;
984 707 : if (RgX_is_FpXQX(x, &T, &p) && p)
985 : { /* over Fq */
986 336 : if (T && typ(T) == t_FFELT)
987 : {
988 126 : if (!FFX_ispower(x, k, T, pt)) return gc_long(av,0);
989 105 : return 1;
990 : }
991 210 : x = RgX_to_FqX(x,T,p);
992 210 : if (!FqX_ispower(x, k, T,p, pt)) return gc_long(av,0);
993 175 : if (pt) *pt = gerepileupto(av, FqX_to_mod(*pt, T, p));
994 175 : return 1;
995 : }
996 371 : v = RgX_valrem(x, &x);
997 371 : if (v % k) return 0;
998 364 : v /= k;
999 364 : a = gel(x,2); b = NULL;
1000 364 : if (!ispower(a, K, &b)) return gc_long(av,0);
1001 350 : if (d)
1002 : {
1003 343 : GEN p = characteristic(x);
1004 343 : a = leading_coeff(x);
1005 343 : if (!ispower(a, K, &b)) return gc_long(av,0);
1006 343 : x = RgX_normalize(x);
1007 343 : if (signe(p) && cmpii(p,K) <= 0)
1008 0 : pari_err_IMPL("ispower(general t_POL) in small characteristic");
1009 343 : y = gtrunc(gsqrtn(RgX_to_ser(x,lg(x)), K, NULL, 0));
1010 343 : if (!RgX_equal(powgi(y, K), x)) return gc_long(av,0);
1011 : }
1012 : else
1013 7 : y = pol_1(varn(x));
1014 350 : if (pt)
1015 : {
1016 350 : if (!gequal1(a))
1017 : {
1018 14 : if (!b) b = gsqrtn(a, K, NULL, DEFAULTPREC);
1019 14 : y = gmul(b,y);
1020 : }
1021 350 : if (v) y = RgX_shift_shallow(y, v);
1022 350 : *pt = gerepilecopy(av, y);
1023 : }
1024 0 : else set_avma(av);
1025 350 : return 1;
1026 : }
1027 :
1028 : long
1029 98949 : Z_ispowerall(GEN x, ulong k, GEN *pt)
1030 : {
1031 98949 : long s = signe(x);
1032 : ulong mask;
1033 98949 : if (!s) { if (pt) *pt = gen_0; return 1; }
1034 98949 : if (s > 0) {
1035 98809 : if (k == 2) return Z_issquareall(x, pt);
1036 18661 : if (k == 3) { mask = 1; return !!is_357_power(x, pt, &mask); }
1037 3583 : if (k == 5) { mask = 2; return !!is_357_power(x, pt, &mask); }
1038 3205 : if (k == 7) { mask = 4; return !!is_357_power(x, pt, &mask); }
1039 3198 : return is_kth_power(x, k, pt);
1040 : }
1041 140 : if (!odd(k)) return 0;
1042 126 : if (Z_ispowerall(absi_shallow(x), k, pt))
1043 : {
1044 112 : if (pt) *pt = negi(*pt);
1045 112 : return 1;
1046 : };
1047 14 : return 0;
1048 : }
1049 :
1050 : /* is x a K-th power mod p ? Assume p prime. */
1051 : int
1052 203 : Fp_ispower(GEN x, GEN K, GEN p)
1053 : {
1054 203 : pari_sp av = avma;
1055 : GEN p_1;
1056 203 : x = modii(x, p);
1057 203 : if (!signe(x) || equali1(x)) return gc_bool(av,1);
1058 : /* implies p > 2 */
1059 112 : p_1 = subiu(p,1);
1060 112 : K = gcdii(K, p_1);
1061 112 : if (absequaliu(K, 2)) return gc_bool(av, kronecker(x,p) > 0);
1062 49 : x = Fp_pow(x, diviiexact(p_1,K), p);
1063 49 : return gc_bool(av, equali1(x));
1064 : }
1065 :
1066 : /* x unit defined modulo 2^e, e > 0, p prime */
1067 : static int
1068 2373 : U2_issquare(GEN x, long e)
1069 : {
1070 2373 : long r = signe(x)>=0?mod8(x):8-mod8(x);
1071 2373 : if (e==1) return 1;
1072 2373 : if (e==2) return (r&3L) == 1;
1073 2009 : return r == 1;
1074 : }
1075 : /* x unit defined modulo p^e, e > 0, p prime */
1076 : static int
1077 4690 : Up_issquare(GEN x, GEN p, long e)
1078 4690 : { return (absequaliu(p,2))? U2_issquare(x, e): kronecker(x,p)==1; }
1079 :
1080 : long
1081 2548 : Zn_issquare(GEN d, GEN fn)
1082 : {
1083 : long j, np;
1084 2548 : if (typ(d) != t_INT) pari_err_TYPE("Zn_issquare",d);
1085 2548 : if (typ(fn) == t_INT) return Zn_ispower(d, fn, gen_2, NULL);
1086 : /* integer factorization */
1087 2548 : np = nbrows(fn);
1088 5320 : for (j = 1; j <= np; ++j)
1089 : {
1090 4970 : GEN r, p = gcoeff(fn, j, 1);
1091 4970 : long e = itos(gcoeff(fn, j, 2));
1092 4970 : long v = Z_pvalrem(d,p,&r);
1093 4970 : if (v < e && (odd(v) || !Up_issquare(r, p, e-v))) return 0;
1094 : }
1095 350 : return 1;
1096 : }
1097 :
1098 : /* return [N',v]; v contains all x mod N' s.t. x^2 + B x + C = 0 modulo N */
1099 : GEN
1100 2742845 : Zn_quad_roots(GEN N, GEN B, GEN C)
1101 : {
1102 2742845 : pari_sp av = avma;
1103 2742845 : GEN fa = NULL, D, w, v, P, E, F0, Q0, F, mF, A, Q, T, R, Np, N4;
1104 : long l, i, j, ct;
1105 :
1106 2742845 : if ((fa = check_arith_non0(N,"Zn_quad_roots")))
1107 21 : N = typ(N) == t_VEC? gel(N,1): factorback(N);
1108 2742845 : N = absi_shallow(N);
1109 2742845 : N4 = shifti(N,2);
1110 2742845 : D = modii(subii(sqri(B), shifti(C,2)), N4);
1111 2742845 : if (!signe(D))
1112 : { /* (x + B/2)^2 = 0 (mod N), D = B^2-4C = 0 (4N) => B even */
1113 630 : if (!fa) fa = Z_factor(N);
1114 630 : P = gel(fa,1);
1115 630 : E = ZV_to_zv(gel(fa,2));
1116 630 : l = lg(P);
1117 630 : for (i = 1; i < l; i++) E[i] = (E[i]+1) >> 1;
1118 630 : Np = factorback2(P, E); /* x = -B mod N' */
1119 630 : B = shifti(B,-1);
1120 630 : return gerepilecopy(av, mkvec2(Np, mkvec(Fp_neg(B,Np))));
1121 : }
1122 2742215 : if (!fa)
1123 2742194 : fa = Z_factor(N4);
1124 : else /* convert to factorization of N4 = 4*N */
1125 21 : fa = famat_reduce(famat_mulpows_shallow(fa, gen_2, 2));
1126 2742215 : P = gel(fa,1); l = lg(P);
1127 2742215 : E = ZV_to_zv(gel(fa,2));
1128 2742215 : F = cgetg(l, t_VEC);
1129 2742215 : mF= cgetg(l, t_VEC); F0 = gen_0;
1130 2742215 : Q = cgetg(l, t_VEC); Q0 = gen_1;
1131 6592061 : for (i = j = 1, ct = 0; i < l; i++)
1132 : {
1133 5979960 : GEN p = gel(P,i), q, f, mf, D0;
1134 5979960 : long t2, s = E[i], t = Z_pvalrem(D, p, &D0), d = s - t;
1135 5979960 : if (d <= 0)
1136 : {
1137 1355151 : q = powiu(p, (s+1)>>1);
1138 3567172 : Q0 = mulii(Q0, q); continue;
1139 : }
1140 : /* d > 0 */
1141 6754923 : if (odd(t)) return NULL;
1142 4439309 : t2 = t >> 1;
1143 4439309 : if (i > 1)
1144 : { /* p > 2 */
1145 2796766 : if (kronecker(D0, p) == -1) return NULL;
1146 1350993 : q = powiu(p,s-t2);
1147 1350993 : f = Zp_sqrt(D0, p, d);
1148 1350993 : if (!f) return NULL; /* p was not actually prime... */
1149 1350986 : if (t2) f = mulii(powiu(p,t2), f);
1150 1350986 : mf = Fp_neg(f, q);
1151 : }
1152 : else
1153 : { /* p = 2 */
1154 1642543 : if (d == 1) { Q0 = int2n(1+t2); F0 = NULL; continue; }
1155 1468943 : if (d == 2)
1156 : {
1157 734132 : if (Mod4(D0) != 1) return NULL;
1158 683270 : Q0 = int2n(1+t2); F0 = NULL; continue;
1159 : }
1160 : /* d > 2 */
1161 734811 : if (Mod8(D0) != 1) return NULL;
1162 286839 : q = int2n(d-1+t2);
1163 286839 : f = shifti(Z2_sqrt(D0, d), t2);
1164 286839 : mf = Fp_neg(f, q);
1165 : }
1166 1637825 : gel(Q,j) = q;
1167 1637825 : gel(F,j) = f;
1168 1637825 : gel(mF,j)= mf; j++;
1169 : }
1170 612101 : setlg(Q,j);
1171 612101 : setlg(F,j);
1172 612101 : setlg(mF,j);
1173 612101 : if (is_pm1(Q0)) A = leafcopy(F);
1174 : else
1175 : { /* append the fixed congruence (F0 mod Q0) */
1176 545062 : if (!F0) F0 = shifti(Q0,-1);
1177 545062 : A = shallowconcat(F, F0);
1178 545062 : Q = shallowconcat(Q, Q0);
1179 : }
1180 612101 : ct = 1 << (j-1);
1181 612101 : T = ZV_producttree(Q);
1182 612101 : R = ZV_chinesetree(Q,T);
1183 612101 : Np = gmael(T, lg(T)-1, 1);
1184 612101 : B = modii(B, Np);
1185 612101 : if (!signe(B)) B = NULL;
1186 612101 : Np = shifti(Np, -1); /* N' = (\prod_i Q[i]) / 2 */
1187 612101 : w = cgetg(3, t_VEC);
1188 612101 : gel(w,1) = icopy(Np);
1189 612101 : gel(w,2) = v = cgetg(ct+1, t_VEC);
1190 612101 : l = lg(F);
1191 2786700 : for (j = 1; j <= ct; j++)
1192 : {
1193 2174599 : pari_sp av2 = avma;
1194 2174599 : long m = j - 1;
1195 : GEN u;
1196 6605585 : for (i = 1; i < l; i++)
1197 : {
1198 4430986 : gel(A,i) = (m&1L)? gel(mF,i): gel(F,i);
1199 4430986 : m >>= 1;
1200 : }
1201 2174599 : u = ZV_chinese_tree(A,Q,T,R); /* u mod N' st u^2 = B^2-4C modulo 4N */
1202 2174599 : if (B) u = subii(u,B);
1203 2174599 : gel(v,j) = gerepileuptoint(av2, modii(shifti(u,-1), Np));
1204 : }
1205 612101 : return gerepileupto(av, w);
1206 : }
1207 :
1208 : static long
1209 1113 : Qp_ispower(GEN x, GEN K, GEN *pt)
1210 : {
1211 1113 : pari_sp av = avma;
1212 1113 : GEN z = Qp_sqrtn(x, K, NULL);
1213 1113 : if (!z) return gc_long(av,0);
1214 819 : if (pt) *pt = z;
1215 819 : return 1;
1216 : }
1217 :
1218 : long
1219 7097592 : ispower(GEN x, GEN K, GEN *pt)
1220 : {
1221 : GEN z;
1222 :
1223 7097592 : if (!K) return gisanypower(x, pt);
1224 97410 : if (typ(K) != t_INT) pari_err_TYPE("ispower",K);
1225 97410 : if (signe(K) <= 0) pari_err_DOMAIN("ispower","exponent","<=",gen_0,K);
1226 97410 : if (equali1(K)) { if (pt) *pt = gcopy(x); return 1; }
1227 97361 : switch(typ(x)) {
1228 : case t_INT:
1229 25567 : if (lgefint(K) != 3) return 0;
1230 25559 : return Z_ispowerall(x, itou(K), pt);
1231 : case t_FRAC:
1232 : {
1233 69708 : GEN a = gel(x,1), b = gel(x,2);
1234 : ulong k;
1235 69708 : if (lgefint(K) != 3) return 0;
1236 69701 : k = itou(K);
1237 69701 : if (pt) {
1238 69694 : z = cgetg(3, t_FRAC);
1239 69694 : if (Z_ispowerall(a, k, &a) && Z_ispowerall(b, k, &b)) {
1240 1386 : *pt = z; gel(z,1) = a; gel(z,2) = b; return 1;
1241 : }
1242 68308 : set_avma((pari_sp)(z + 3)); return 0;
1243 : }
1244 7 : return Z_ispower(a, k) && Z_ispower(b, k);
1245 : }
1246 : case t_INTMOD:
1247 189 : return Zn_ispower(gel(x,2), gel(x,1), K, pt);
1248 : case t_FFELT:
1249 28 : return FF_ispower(x, K, pt);
1250 :
1251 : case t_PADIC:
1252 1113 : return Qp_ispower(x, K, pt);
1253 : case t_POLMOD:
1254 14 : return polmodispower(x, K, pt);
1255 : case t_POL:
1256 714 : return polispower(x, K, pt);
1257 : case t_RFRAC: {
1258 7 : GEN a = gel(x,1), b = gel(x,2);
1259 7 : if (pt) {
1260 7 : z = cgetg(3, t_RFRAC);
1261 7 : if (ispower(a, K, &a) && polispower(b, K, &b)) {
1262 7 : *pt = z; gel(z,1) = a; gel(z,2) = b; return 1;
1263 : }
1264 0 : set_avma((pari_sp)(z + 3)); return 0;
1265 : }
1266 0 : return (ispower(a, K, NULL) && polispower(b, K, NULL));
1267 : }
1268 : case t_REAL:
1269 7 : if (signe(x) < 0 && !mpodd(K)) return 0;
1270 : case t_COMPLEX:
1271 14 : if (pt) *pt = gsqrtn(x, K, NULL, DEFAULTPREC);
1272 14 : return 1;
1273 :
1274 : case t_SER:
1275 7 : if (signe(x) && (!dvdsi(valp(x), K) || !ispower(gel(x,2), K, NULL)))
1276 0 : return 0;
1277 7 : if (pt) *pt = gsqrtn(x, K, NULL, DEFAULTPREC);
1278 7 : return 1;
1279 : }
1280 0 : pari_err_TYPE("ispower",x);
1281 : return 0; /* LCOV_EXCL_LINE */
1282 : }
1283 :
1284 : long
1285 7000182 : gisanypower(GEN x, GEN *pty)
1286 : {
1287 7000182 : long tx = typ(x);
1288 : ulong k, h;
1289 7000182 : if (tx == t_INT) return Z_isanypower(x, pty);
1290 14 : if (tx == t_FRAC)
1291 : {
1292 14 : pari_sp av = avma;
1293 14 : GEN fa, P, E, a = gel(x,1), b = gel(x,2);
1294 : long i, j, p, e;
1295 14 : int sw = (abscmpii(a, b) > 0);
1296 :
1297 14 : if (sw) swap(a, b);
1298 14 : k = Z_isanypower(a, pty? &a: NULL);
1299 14 : if (!k)
1300 : { /* a = -1,1 or not a pure power */
1301 7 : if (!is_pm1(a)) return gc_long(av,0);
1302 7 : if (signe(a) < 0) b = negi(b);
1303 7 : k = Z_isanypower(b, pty? &b: NULL);
1304 7 : if (!k || !pty) return gc_long(av,k);
1305 7 : *pty = gerepileupto(av, ginv(b));
1306 7 : return k;
1307 : }
1308 7 : fa = factoru(k);
1309 7 : P = gel(fa,1);
1310 7 : E = gel(fa,2); h = k;
1311 14 : for (i = lg(P) - 1; i > 0; i--)
1312 : {
1313 7 : p = P[i];
1314 7 : e = E[i];
1315 21 : for (j = 0; j < e; j++)
1316 14 : if (!is_kth_power(b, p, &b)) break;
1317 7 : if (j < e) k /= upowuu(p, e - j);
1318 : }
1319 7 : if (k == 1) return gc_long(av,0);
1320 7 : if (!pty) return gc_long(av,k);
1321 0 : if (k != h) a = powiu(a, h/k);
1322 0 : *pty = gerepilecopy(av, mkfrac(a, b));
1323 0 : return k;
1324 : }
1325 0 : pari_err_TYPE("gisanypower", x);
1326 : return 0; /* LCOV_EXCL_LINE */
1327 : }
1328 :
1329 : /* v_p(x) = e != 0 for some p; return ispower(x,,&x), updating x.
1330 : * No need to optimize for 2,3,5,7 powers (done before) */
1331 : static long
1332 505715 : split_exponent(ulong e, GEN *x)
1333 : {
1334 : GEN fa, P, E;
1335 505715 : long i, j, l, k = 1;
1336 505715 : if (e == 1) return 1;
1337 14 : fa = factoru(e);
1338 14 : P = gel(fa,1);
1339 14 : E = gel(fa,2); l = lg(P);
1340 28 : for (i = 1; i < l; i++)
1341 : {
1342 14 : ulong p = P[i];
1343 28 : for (j = 0; j < E[i]; j++)
1344 : {
1345 : GEN y;
1346 14 : if (!is_kth_power(*x, p, &y)) break;
1347 14 : k *= p; *x = y;
1348 : }
1349 : }
1350 14 : return k;
1351 : }
1352 :
1353 : static long
1354 864738 : Z_isanypower_nosmalldiv(GEN *px)
1355 : { /* any prime divisor of x is > 102 */
1356 864738 : const double LOG2_103 = 6.6865; /* lower bound for log_2(103) */
1357 864738 : const double LOG103 = 4.6347; /* lower bound for log(103) */
1358 : forprime_t T;
1359 864738 : ulong mask = 7, e2;
1360 : long k, ex;
1361 864738 : GEN y, x = *px;
1362 :
1363 864738 : k = 1;
1364 864738 : while (Z_issquareall(x, &y)) { k <<= 1; x = y; }
1365 864738 : while ( (ex = is_357_power(x, &y, &mask)) ) { k *= ex; x = y; }
1366 864738 : e2 = (ulong)((expi(x) + 1) / LOG2_103); /* >= log_103 (x) */
1367 864738 : if (u_forprime_init(&T, 11, e2))
1368 : {
1369 16982 : GEN logx = NULL;
1370 16982 : const ulong Q = 30011; /* prime */
1371 : ulong p, xmodQ;
1372 16982 : double dlogx = 0;
1373 : /* cut off at x^(1/p) ~ 2^30 bits which seems to be about optimum;
1374 : * for large p the modular checks are no longer competitively fast */
1375 34006 : while ( (ex = is_pth_power(x, &y, &T, 30)) )
1376 : {
1377 42 : k *= ex; x = y;
1378 42 : e2 = (ulong)((expi(x) + 1) / LOG2_103);
1379 42 : u_forprime_restrict(&T, e2);
1380 : }
1381 16982 : if (DEBUGLEVEL>4)
1382 0 : err_printf("Z_isanypower: now k=%ld, x=%ld-bit\n", k, expi(x)+1);
1383 16982 : xmodQ = umodiu(x, Q);
1384 : /* test Q | x, just in case */
1385 16982 : if (!xmodQ) { *px = x; return k * split_exponent(Z_lval(x,Q), px); }
1386 : /* x^(1/p) < 2^31 */
1387 16968 : p = T.p;
1388 16968 : if (p <= e2)
1389 : {
1390 16954 : logx = logr_abs( itor(x, DEFAULTPREC) );
1391 16954 : dlogx = rtodbl(logx);
1392 16954 : e2 = (ulong)(dlogx / LOG103); /* >= log_103(x) */
1393 : }
1394 154189 : while (p && p <= e2)
1395 : { /* is x a p-th power ? By computing y = round(x^(1/p)).
1396 : * Check whether y^p = x, first mod Q, then exactly. */
1397 120253 : pari_sp av = avma;
1398 : long e;
1399 120253 : GEN logy = divru(logx, p), y = grndtoi(mpexp(logy), &e);
1400 120253 : ulong ymodQ = umodiu(y,Q);
1401 120253 : if (e >= -10 || Fl_powu(ymodQ, p % (Q-1), Q) != xmodQ
1402 21 : || !equalii(powiu(y, p), x)) set_avma(av);
1403 : else
1404 : {
1405 21 : k *= p; x = y; xmodQ = ymodQ; logx = logy; dlogx /= p;
1406 21 : e2 = (ulong)(dlogx / LOG103); /* >= log_103(x) */
1407 21 : u_forprime_restrict(&T, e2);
1408 21 : continue; /* if success, retry same p */
1409 : }
1410 120232 : p = u_forprime_next(&T);
1411 : }
1412 : }
1413 864724 : *px = x; return k;
1414 : }
1415 :
1416 : static ulong tinyprimes[] = {
1417 : 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
1418 : 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
1419 : 157, 163, 167, 173, 179, 181, 191, 193, 197, 199
1420 : };
1421 :
1422 : /* disregard the sign of x, caller will take care of x < 0 */
1423 : static long
1424 7000896 : Z_isanypower_aux(GEN x, GEN *pty)
1425 : {
1426 : long ex, v, i, l, k;
1427 : GEN y, P, E;
1428 7000896 : ulong mask, e = 0;
1429 :
1430 7000896 : if (abscmpii(x, gen_2) < 0) return 0; /* -1,0,1 */
1431 :
1432 7000882 : if (signe(x) < 0) x = negi(x);
1433 7000882 : k = l = 1;
1434 7000882 : P = cgetg(26 + 1, t_VECSMALL);
1435 7000882 : E = cgetg(26 + 1, t_VECSMALL);
1436 : /* trial division */
1437 122945228 : for(i = 0; i < 26; i++)
1438 : {
1439 60138057 : ulong p = tinyprimes[i];
1440 : int stop;
1441 60138057 : v = Z_lvalrem_stop(&x, p, &stop);
1442 60138057 : if (v)
1443 : {
1444 7922348 : P[l] = p;
1445 7922348 : E[l] = v; l++;
1446 13588673 : e = ugcd(e, v); if (e == 1) goto END;
1447 : }
1448 54719770 : if (stop) {
1449 248038 : if (is_pm1(x)) k = e;
1450 248038 : goto END;
1451 : }
1452 : }
1453 :
1454 1334557 : if (e)
1455 : { /* Bingo. Result divides e */
1456 : long v3, v5, v7;
1457 505701 : ulong e2 = e;
1458 505701 : v = u_lvalrem(e2, 2, &e2);
1459 505701 : if (v)
1460 : {
1461 375249 : for (i = 0; i < v; i++)
1462 : {
1463 374171 : if (!Z_issquareall(x, &y)) break;
1464 1288 : k <<= 1; x = y;
1465 : }
1466 : }
1467 505701 : mask = 0;
1468 505701 : v3 = u_lvalrem(e2, 3, &e2); if (v3) mask = 1;
1469 505701 : v5 = u_lvalrem(e2, 5, &e2); if (v5) mask |= 2;
1470 505701 : v7 = u_lvalrem(e2, 7, &e2); if (v7) mask |= 4;
1471 1011479 : while ( (ex = is_357_power(x, &y, &mask)) ) {
1472 77 : x = y;
1473 77 : switch(ex)
1474 : {
1475 28 : case 3: k *= 3; if (--v3 == 0) mask &= ~1; break;
1476 28 : case 5: k *= 5; if (--v5 == 0) mask &= ~2; break;
1477 21 : case 7: k *= 7; if (--v7 == 0) mask &= ~4; break;
1478 : }
1479 : }
1480 505701 : k *= split_exponent(e2, &x);
1481 : }
1482 : else
1483 828856 : k = Z_isanypower_nosmalldiv(&x);
1484 : END:
1485 7000882 : if (pty && k != 1)
1486 : {
1487 8134 : if (e)
1488 : { /* add missing small factors */
1489 6867 : y = powuu(P[1], E[1] / k);
1490 6867 : for (i = 2; i < l; i++) y = mulii(y, powuu(P[i], E[i] / k));
1491 6867 : x = equali1(x)? y: mulii(x,y);
1492 : }
1493 8134 : *pty = x;
1494 : }
1495 7000882 : return k == 1? 0: k;
1496 : }
1497 :
1498 : long
1499 7000896 : Z_isanypower(GEN x, GEN *pty)
1500 : {
1501 7000896 : pari_sp av = avma;
1502 7000896 : long k = Z_isanypower_aux(x, pty);
1503 7000896 : if (!k) return gc_long(av,0);
1504 8197 : if (signe(x) < 0)
1505 : {
1506 42 : long v = vals(k);
1507 42 : if (v)
1508 : {
1509 : GEN y;
1510 28 : k >>= v;
1511 28 : if (k == 1) return gc_long(av,0);
1512 21 : if (!pty) return gc_long(av,k);
1513 14 : y = *pty;
1514 14 : y = powiu(y, 1<<v);
1515 14 : togglesign(y);
1516 14 : *pty = gerepileuptoint(av, y);
1517 14 : return k;
1518 : }
1519 14 : if (pty) togglesign_safe(pty);
1520 : }
1521 8169 : if (pty) *pty = gerepilecopy(av, *pty); else set_avma(av);
1522 8169 : return k;
1523 : }
1524 :
1525 : /* Faster than */
1526 : /* !cmpii(n, int2n(vali(n))) */
1527 : /* !cmpis(shifti(n, -vali(n)), 1) */
1528 : /* expi(n) == vali(n) */
1529 : /* hamming(n) == 1 */
1530 : /* even for single-word values, and much faster for multiword values. */
1531 : /* If all you have is a word, you can just use n & !(n & (n-1)). */
1532 : long
1533 101791 : Z_ispow2(GEN n)
1534 : {
1535 : GEN xp;
1536 : long i, lx;
1537 : ulong u;
1538 101791 : if (signe(n) != 1) return 0;
1539 101784 : xp = int_LSW(n);
1540 101784 : lx = lgefint(n);
1541 101784 : u = *xp;
1542 102068 : for (i = 3; i < lx; ++i)
1543 : {
1544 98913 : if (u) return 0;
1545 284 : xp = int_nextW(xp);
1546 284 : u = *xp;
1547 : }
1548 3155 : return !(u & (u-1));
1549 : }
1550 :
1551 : static long
1552 841903 : isprimepower_i(GEN n, GEN *pt, long flag)
1553 : {
1554 841903 : pari_sp av = avma;
1555 : long i, v;
1556 :
1557 841903 : if (typ(n) != t_INT) pari_err_TYPE("isprimepower", n);
1558 841903 : if (signe(n) <= 0) return 0;
1559 :
1560 841903 : if (lgefint(n) == 3)
1561 : {
1562 : ulong p;
1563 541183 : v = uisprimepower(n[2], &p);
1564 541183 : if (v)
1565 : {
1566 54971 : if (pt) *pt = utoipos(p);
1567 54971 : return v;
1568 : }
1569 486212 : return 0;
1570 : }
1571 1663329 : for (i = 0; i < 26; i++)
1572 : {
1573 1627447 : ulong p = tinyprimes[i];
1574 1627447 : v = Z_lvalrem(n, p, &n);
1575 1627447 : if (v)
1576 : {
1577 264838 : set_avma(av);
1578 264838 : if (!is_pm1(n)) return 0;
1579 442 : if (pt) *pt = utoipos(p);
1580 442 : return v;
1581 : }
1582 : }
1583 : /* p | n => p >= 103 */
1584 35882 : v = Z_isanypower_nosmalldiv(&n); /* expensive */
1585 35882 : if (!(flag? isprime(n): BPSW_psp(n))) return gc_long(av,0);
1586 5570 : if (pt) *pt = gerepilecopy(av, n); else set_avma(av);
1587 5570 : return v;
1588 : }
1589 : long
1590 840098 : isprimepower(GEN n, GEN *pt) { return isprimepower_i(n,pt,1); }
1591 : long
1592 1805 : ispseudoprimepower(GEN n, GEN *pt) { return isprimepower_i(n,pt,0); }
1593 :
1594 : long
1595 547112 : uisprimepower(ulong n, ulong *pp)
1596 : { /* We must have CUTOFF^11 >= ULONG_MAX and CUTOFF^3 < ULONG_MAX.
1597 : * Tests suggest that 200-300 is the best range for 64-bit platforms. */
1598 547112 : const ulong CUTOFF = 200UL;
1599 547112 : const long TINYCUTOFF = 46; /* tinyprimes[45] = 199 */
1600 547112 : const ulong CUTOFF3 = CUTOFF*CUTOFF*CUTOFF;
1601 : #ifdef LONG_IS_64BIT
1602 : /* primes preceeding the appropriate root of ULONG_MAX. */
1603 486108 : const ulong ROOT9 = 137;
1604 486108 : const ulong ROOT8 = 251;
1605 486108 : const ulong ROOT7 = 563;
1606 486108 : const ulong ROOT5 = 7129;
1607 486108 : const ulong ROOT4 = 65521;
1608 : #else
1609 61004 : const ulong ROOT9 = 11;
1610 61004 : const ulong ROOT8 = 13;
1611 61004 : const ulong ROOT7 = 23;
1612 61004 : const ulong ROOT5 = 83;
1613 61004 : const ulong ROOT4 = 251;
1614 : #endif
1615 : ulong mask;
1616 : long v, i;
1617 : int e;
1618 547112 : if (n < 2) return 0;
1619 547098 : if (!odd(n)) {
1620 274729 : if (n & (n-1)) return 0;
1621 4001 : *pp = 2; return vals(n);
1622 : }
1623 272369 : if (n < 8) { *pp = n; return 1; } /* 3,5,7 */
1624 3654361 : for (i = 1/*skip p=2*/; i < TINYCUTOFF; i++)
1625 : {
1626 3595286 : ulong p = tinyprimes[i];
1627 3595286 : if (n % p == 0)
1628 : {
1629 211705 : v = u_lvalrem(n, p, &n);
1630 211705 : if (n == 1) { *pp = p; return v; }
1631 209466 : return 0;
1632 : }
1633 : }
1634 : /* p | n => p >= CUTOFF */
1635 :
1636 59075 : if (n < CUTOFF3)
1637 : {
1638 46354 : if (n < CUTOFF*CUTOFF || uisprime_101(n)) { *pp = n; return 1; }
1639 0 : if (uissquareall(n, &n)) { *pp = n; return 2; }
1640 0 : return 0;
1641 : }
1642 :
1643 : /* Check for squares, fourth powers, and eighth powers as appropriate. */
1644 12721 : v = 1;
1645 12721 : if (uissquareall(n, &n)) {
1646 0 : v <<= 1;
1647 0 : if (CUTOFF <= ROOT4 && uissquareall(n, &n)) {
1648 0 : v <<= 1;
1649 0 : if (CUTOFF <= ROOT8 && uissquareall(n, &n)) v <<= 1;
1650 : }
1651 : }
1652 :
1653 12721 : if (CUTOFF > ROOT5) mask = 1;
1654 : else
1655 : {
1656 12720 : const ulong CUTOFF5 = CUTOFF3*CUTOFF*CUTOFF;
1657 12720 : if (n < CUTOFF5) mask = 1; else mask = 3;
1658 12720 : if (CUTOFF <= ROOT7)
1659 : {
1660 12720 : const ulong CUTOFF7 = CUTOFF5*CUTOFF*CUTOFF;
1661 12720 : if (n >= CUTOFF7) mask = 7;
1662 : }
1663 : }
1664 :
1665 12721 : if (CUTOFF <= ROOT9 && (e = uis_357_power(n, &n, &mask))) { v *= e; mask=1; }
1666 12721 : if ((e = uis_357_power(n, &n, &mask))) v *= e;
1667 :
1668 12721 : if (uisprime_101(n)) { *pp = n; return v; }
1669 6984 : return 0;
1670 : }
1671 :
1672 : /*********************************************************************/
1673 : /** **/
1674 : /** KRONECKER SYMBOL **/
1675 : /** **/
1676 : /*********************************************************************/
1677 : /* t = 3,5 mod 8 ? (= 2 not a square mod t) */
1678 : static int
1679 635313100 : ome(long t)
1680 : {
1681 635313100 : switch(t & 7)
1682 : {
1683 : case 3:
1684 361976092 : case 5: return 1;
1685 273337008 : default: return 0;
1686 : }
1687 : }
1688 : /* t a t_INT, is t = 3,5 mod 8 ? */
1689 : static int
1690 4185160 : gome(GEN t)
1691 4185160 : { return signe(t)? ome( mod2BIL(t) ): 0; }
1692 :
1693 : /* assume y odd, return kronecker(x,y) * s */
1694 : static long
1695 483652245 : krouu_s(ulong x, ulong y, long s)
1696 : {
1697 483652245 : ulong x1 = x, y1 = y, z;
1698 2611121278 : while (x1)
1699 : {
1700 1643857788 : long r = vals(x1);
1701 1643937409 : if (r)
1702 : {
1703 885102228 : if (odd(r) && ome(y1)) s = -s;
1704 884981607 : x1 >>= r;
1705 : }
1706 1643816788 : if (x1 & y1 & 2) s = -s;
1707 1643816788 : z = y1 % x1; y1 = x1; x1 = z;
1708 : }
1709 483611245 : return (y1 == 1)? s: 0;
1710 : }
1711 :
1712 : long
1713 5053263 : kronecker(GEN x, GEN y)
1714 : {
1715 5053263 : pari_sp av = avma;
1716 5053263 : long s = 1, r;
1717 : ulong xu;
1718 :
1719 5053263 : if (typ(x) != t_INT) pari_err_TYPE("kronecker",x);
1720 5053263 : if (typ(y) != t_INT) pari_err_TYPE("kronecker",y);
1721 5053263 : switch (signe(y))
1722 : {
1723 63 : case -1: y = negi(y); if (signe(x) < 0) s = -1; break;
1724 0 : case 0: return is_pm1(x);
1725 : }
1726 5053263 : r = vali(y);
1727 5053263 : if (r)
1728 : {
1729 11899 : if (!mpodd(x)) return gc_long(av,0);
1730 10359 : if (odd(r) && gome(x)) s = -s;
1731 10359 : y = shifti(y,-r);
1732 : }
1733 5051723 : x = modii(x,y);
1734 11063195 : while (lgefint(x) > 3) /* x < y */
1735 : {
1736 : GEN z;
1737 959749 : r = vali(x);
1738 959749 : if (r)
1739 : {
1740 523994 : if (odd(r) && gome(y)) s = -s;
1741 523994 : x = shifti(x,-r);
1742 : }
1743 : /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */
1744 959749 : if (mod2BIL(x) & mod2BIL(y) & 2) s = -s;
1745 959749 : z = remii(y,x); y = x; x = z;
1746 959749 : if (gc_needed(av,2))
1747 : {
1748 0 : if(DEBUGMEM>1) pari_warn(warnmem,"kronecker");
1749 0 : gerepileall(av, 2, &x, &y);
1750 : }
1751 : }
1752 5051723 : xu = itou(x);
1753 5051723 : if (!xu) return is_pm1(y)? s: 0;
1754 5030765 : r = vals(xu);
1755 5030765 : if (r)
1756 : {
1757 2643085 : if (odd(r) && gome(y)) s = -s;
1758 2643085 : xu >>= r;
1759 : }
1760 : /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */
1761 5030765 : if (xu & mod2BIL(y) & 2) s = -s;
1762 5030765 : return gc_long(av, krouu_s(umodiu(y,xu), xu, s));
1763 : }
1764 :
1765 : long
1766 30023 : krois(GEN x, long y)
1767 : {
1768 : ulong yu;
1769 30023 : long s = 1;
1770 :
1771 30023 : if (y <= 0)
1772 : {
1773 7 : if (y == 0) return is_pm1(x);
1774 0 : yu = (ulong)-y; if (signe(x) < 0) s = -1;
1775 : }
1776 : else
1777 30016 : yu = (ulong)y;
1778 30016 : if (!odd(yu))
1779 : {
1780 : long r;
1781 13552 : if (!mpodd(x)) return 0;
1782 9772 : r = vals(yu); yu >>= r;
1783 9772 : if (odd(r) && gome(x)) s = -s;
1784 : }
1785 26236 : return krouu_s(umodiu(x, yu), yu, s);
1786 : }
1787 : /* assume y != 0 */
1788 : long
1789 342604110 : kroiu(GEN x, ulong y)
1790 : {
1791 : long r;
1792 342604110 : if (odd(y)) return krouu_s(umodiu(x,y), y, 1);
1793 2132514 : if (!mpodd(x)) return 0;
1794 2110380 : r = vals(y); y >>= r;
1795 2110380 : return krouu_s(umodiu(x,y), y, (odd(r) && gome(x))? -1: 1);
1796 : }
1797 :
1798 : /* assume y > 0, odd, return s * kronecker(x,y) */
1799 : static long
1800 181237 : krouodd(ulong x, GEN y, long s)
1801 : {
1802 : long r;
1803 181237 : if (lgefint(y) == 3) return krouu_s(x, y[2], s);
1804 41902 : if (!x) return 0; /* y != 1 */
1805 41902 : r = vals(x);
1806 41902 : if (r)
1807 : {
1808 7370 : if (odd(r) && gome(y)) s = -s;
1809 7370 : x >>= r;
1810 : }
1811 : /* x=3 mod 4 && y=3 mod 4 ? (both are odd here) */
1812 41902 : if (x & mod2BIL(y) & 2) s = -s;
1813 41902 : return krouu_s(umodiu(y,x), x, s);
1814 : }
1815 :
1816 : long
1817 180716 : krosi(long x, GEN y)
1818 : {
1819 180716 : const pari_sp av = avma;
1820 180716 : long s = 1, r;
1821 180716 : switch (signe(y))
1822 : {
1823 0 : case -1: y = negi(y); if (x < 0) s = -1; break;
1824 0 : case 0: return (x==1 || x==-1);
1825 : }
1826 180716 : r = vali(y);
1827 180716 : if (r)
1828 : {
1829 16842 : if (!odd(x)) return gc_long(av,0);
1830 16842 : if (odd(r) && ome(x)) s = -s;
1831 16842 : y = shifti(y,-r);
1832 : }
1833 180716 : if (x < 0) { x = -x; if (mod4(y) == 3) s = -s; }
1834 180716 : return gc_long(av, krouodd((ulong)x, y, s));
1835 : }
1836 :
1837 : long
1838 521 : kroui(ulong x, GEN y)
1839 : {
1840 521 : const pari_sp av = avma;
1841 521 : long s = 1, r;
1842 521 : switch (signe(y))
1843 : {
1844 0 : case -1: y = negi(y); break;
1845 0 : case 0: return x==1UL;
1846 : }
1847 521 : r = vali(y);
1848 521 : if (r)
1849 : {
1850 0 : if (!odd(x)) return gc_long(av,0);
1851 0 : if (odd(r) && ome(x)) s = -s;
1852 0 : y = shifti(y,-r);
1853 : }
1854 521 : return gc_long(av, krouodd(x, y, s));
1855 : }
1856 :
1857 : long
1858 80660940 : kross(long x, long y)
1859 : {
1860 : ulong yu;
1861 80660940 : long s = 1;
1862 :
1863 80660940 : if (y <= 0)
1864 : {
1865 427 : if (y == 0) return (labs(x)==1);
1866 399 : yu = (ulong)-y; if (x < 0) s = -1;
1867 : }
1868 : else
1869 80660513 : yu = (ulong)y;
1870 80660912 : if (!odd(yu))
1871 : {
1872 : long r;
1873 20989102 : if (!odd(x)) return 0;
1874 15037723 : r = vals(yu); yu >>= r;
1875 15037723 : if (odd(r) && ome(x)) s = -s;
1876 : }
1877 74709533 : x %= (long)yu; if (x < 0) x += yu;
1878 74709533 : return krouu_s((ulong)x, yu, s);
1879 : }
1880 :
1881 : long
1882 61007928 : krouu(ulong x, ulong y)
1883 : {
1884 : long r;
1885 61007928 : if (odd(y)) return krouu_s(x, y, 1);
1886 1675 : if (!odd(x)) return 0;
1887 1675 : r = vals(y); y >>= r;
1888 1675 : return krouu_s(x, y, (odd(r) && ome(x))? -1: 1);
1889 : }
1890 :
1891 : /*********************************************************************/
1892 : /** **/
1893 : /** HILBERT SYMBOL **/
1894 : /** **/
1895 : /*********************************************************************/
1896 : /* x,y are t_INT or t_REAL */
1897 : static long
1898 9977 : mphilbertoo(GEN x, GEN y)
1899 : {
1900 9977 : long sx = signe(x), sy = signe(y);
1901 9977 : if (!sx || !sy) return 0;
1902 9977 : return (sx < 0 && sy < 0)? -1: 1;
1903 : }
1904 :
1905 : long
1906 53119 : hilbertii(GEN x, GEN y, GEN p)
1907 : {
1908 : pari_sp av;
1909 : long oddvx, oddvy, z;
1910 :
1911 53119 : if (!p) return mphilbertoo(x,y);
1912 43163 : if (is_pm1(p) || signe(p) < 0) pari_err_PRIME("hilbertii",p);
1913 43163 : if (!signe(x) || !signe(y)) return 0;
1914 43142 : av = avma;
1915 43142 : oddvx = odd(Z_pvalrem(x,p,&x));
1916 43142 : oddvy = odd(Z_pvalrem(y,p,&y));
1917 : /* x, y are p-units, compute hilbert(x * p^oddvx, y * p^oddvy, p) */
1918 43142 : if (absequaliu(p, 2))
1919 : {
1920 10684 : z = (Mod4(x) == 3 && Mod4(y) == 3)? -1: 1;
1921 10684 : if (oddvx && gome(y)) z = -z;
1922 10684 : if (oddvy && gome(x)) z = -z;
1923 : }
1924 : else
1925 : {
1926 32458 : z = (oddvx && oddvy && mod4(p) == 3)? -1: 1;
1927 32458 : if (oddvx && kronecker(y,p) < 0) z = -z;
1928 32458 : if (oddvy && kronecker(x,p) < 0) z = -z;
1929 : }
1930 43142 : return gc_long(av, z);
1931 : }
1932 :
1933 : static void
1934 196 : err_prec(void) { pari_err_PREC("hilbert"); }
1935 : static void
1936 161 : err_p(GEN p, GEN q) { pari_err_MODULUS("hilbert", p,q); }
1937 : static void
1938 56 : err_oo(GEN p) { pari_err_MODULUS("hilbert", p, strtoGENstr("oo")); }
1939 :
1940 : /* x t_INTMOD, *pp = prime or NULL [ unset, set it to x.mod ].
1941 : * Return lift(x) provided it's p-adic accuracy is large enough to decide
1942 : * hilbert()'s value [ problem at p = 2 ] */
1943 : static GEN
1944 420 : lift_intmod(GEN x, GEN *pp)
1945 : {
1946 420 : GEN p = *pp, N = gel(x,1);
1947 420 : x = gel(x,2);
1948 420 : if (!p)
1949 : {
1950 266 : *pp = p = N;
1951 266 : switch(itos_or_0(p))
1952 : {
1953 : case 2:
1954 126 : case 4: err_prec();
1955 : }
1956 140 : return x;
1957 : }
1958 154 : if (!signe(p)) err_oo(N);
1959 112 : if (absequaliu(p,2))
1960 42 : { if (vali(N) <= 2) err_prec(); }
1961 : else
1962 70 : { if (!dvdii(N,p)) err_p(N,p); }
1963 28 : if (!signe(x)) err_prec();
1964 21 : return x;
1965 : }
1966 : /* x t_PADIC, *pp = prime or NULL [ unset, set it to x.p ].
1967 : * Return lift(x)*p^(v(x) mod 2) provided it's p-adic accuracy is large enough
1968 : * to decide hilbert()'s value [ problem at p = 2 ]*/
1969 : static GEN
1970 210 : lift_padic(GEN x, GEN *pp)
1971 : {
1972 210 : GEN p = *pp, q = gel(x,2), y = gel(x,4);
1973 210 : if (!p) *pp = p = q;
1974 147 : else if (!equalii(p,q)) err_p(p, q);
1975 105 : if (absequaliu(p,2) && precp(x) <= 2) err_prec();
1976 70 : if (!signe(y)) err_prec();
1977 70 : return odd(valp(x))? mulii(p,y): y;
1978 : }
1979 :
1980 : long
1981 658 : hilbert(GEN x, GEN y, GEN p)
1982 : {
1983 658 : pari_sp av = avma;
1984 658 : long tx = typ(x), ty = typ(y);
1985 :
1986 658 : if (p && typ(p) != t_INT) pari_err_TYPE("hilbert",p);
1987 658 : if (tx == t_REAL)
1988 : {
1989 77 : if (p && signe(p)) err_oo(p);
1990 63 : switch (ty)
1991 : {
1992 : case t_INT:
1993 7 : case t_REAL: return mphilbertoo(x,y);
1994 0 : case t_FRAC: return mphilbertoo(x,gel(y,1));
1995 56 : default: pari_err_TYPE2("hilbert",x,y);
1996 : }
1997 : }
1998 581 : if (ty == t_REAL)
1999 : {
2000 14 : if (p && signe(p)) err_oo(p);
2001 14 : switch (tx)
2002 : {
2003 : case t_INT:
2004 14 : case t_REAL: return mphilbertoo(x,y);
2005 0 : case t_FRAC: return mphilbertoo(gel(x,1),y);
2006 0 : default: pari_err_TYPE2("hilbert",x,y);
2007 : }
2008 : }
2009 567 : if (tx == t_INTMOD) { x = lift_intmod(x, &p); tx = t_INT; }
2010 364 : if (ty == t_INTMOD) { y = lift_intmod(y, &p); ty = t_INT; }
2011 :
2012 308 : if (tx == t_PADIC) { x = lift_padic(x, &p); tx = t_INT; }
2013 245 : if (ty == t_PADIC) { y = lift_padic(y, &p); ty = t_INT; }
2014 :
2015 168 : if (tx == t_FRAC) { tx = t_INT; x = p? mulii(gel(x,1),gel(x,2)): gel(x,1); }
2016 168 : if (ty == t_FRAC) { ty = t_INT; y = p? mulii(gel(y,1),gel(y,2)): gel(y,1); }
2017 :
2018 168 : if (tx != t_INT || ty != t_INT) pari_err_TYPE2("hilbert",x,y);
2019 168 : if (p && !signe(p)) p = NULL;
2020 168 : return gc_long(av, hilbertii(x,y,p));
2021 : }
2022 :
2023 : /*******************************************************************/
2024 : /* */
2025 : /* SQUARE ROOT MODULO p */
2026 : /* */
2027 : /*******************************************************************/
2028 : static void
2029 3916916 : checkp(ulong q, ulong p)
2030 3916916 : { if (!q) pari_err_PRIME("Fl_nonsquare",utoipos(p)); }
2031 : /* p = 1 (mod 4) prime, return the first quadratic non-residue, a prime */
2032 : static ulong
2033 26416637 : nonsquare1_Fl(ulong p)
2034 : {
2035 : forprime_t S;
2036 : ulong q;
2037 26416637 : if ((p & 7UL) != 1) return 2UL;
2038 10584553 : q = p % 3; if (q == 2) return 3UL;
2039 3226974 : checkp(q, p);
2040 3226968 : q = p % 5; if (q == 2 || q == 3) return 5UL;
2041 426195 : checkp(q, p);
2042 426195 : q = p % 7; if (q != 4 && q >= 3) return 7UL;
2043 159248 : checkp(q, p);
2044 159249 : u_forprime_init(&S, 11, p);
2045 422996 : while ((q = u_forprime_next(&S)))
2046 : {
2047 263747 : long i = krouu(q, p);
2048 263747 : if (i < 0) return q;
2049 104498 : checkp(q, p);
2050 : }
2051 0 : checkp(0, p);
2052 : return 0; /*LCOV_EXCL_LINE*/
2053 : }
2054 : /* p > 2 a prime */
2055 : ulong
2056 7714 : nonsquare_Fl(ulong p)
2057 7714 : { return ((p & 3UL) == 3)? p-1: nonsquare1_Fl(p); }
2058 :
2059 : ulong
2060 150676 : Fl_2gener_pre(ulong p, ulong pi)
2061 : {
2062 150676 : ulong p1 = p-1;
2063 150676 : long e = vals(p1);
2064 150676 : if (e == 1) return p1;
2065 56689 : return Fl_powu_pre(nonsquare1_Fl(p), p1 >> e, p, pi);
2066 : }
2067 :
2068 : /* Tonelli-Shanks. Assume p is prime and (a,p) != -1. */
2069 : ulong
2070 63708409 : Fl_sqrt_pre_i(ulong a, ulong y, ulong p, ulong pi)
2071 : {
2072 : long i, e, k;
2073 : ulong p1, q, v, w;
2074 :
2075 63708409 : if (!a) return 0;
2076 62371932 : p1 = p - 1; e = vals(p1);
2077 62374196 : if (e == 0) /* p = 2 */
2078 : {
2079 418935 : if (p != 2) pari_err_PRIME("Fl_sqrt [modulus]",utoi(p));
2080 418928 : return ((a & 1) == 0)? 0: 1;
2081 : }
2082 61955261 : if (e == 1)
2083 : {
2084 35593721 : v = Fl_powu_pre(a, (p+1) >> 2, p, pi);
2085 35590049 : if (Fl_sqr_pre(v, p, pi) != a) return ~0UL;
2086 35563472 : p1 = p - v; if (v > p1) v = p1;
2087 35563472 : return v;
2088 : }
2089 26361540 : q = p1 >> e; /* q = (p-1)/2^oo is odd */
2090 26361540 : p1 = Fl_powu_pre(a, q >> 1, p, pi); /* a ^ [(q-1)/2] */
2091 26361554 : if (!p1) return 0;
2092 26361554 : v = Fl_mul_pre(a, p1, p, pi);
2093 26361554 : w = Fl_mul_pre(v, p1, p, pi);
2094 26361557 : if (!y) y = Fl_powu_pre(nonsquare1_Fl(p), q, p, pi);
2095 74481692 : while (w != 1)
2096 : { /* a*w = v^2, y primitive 2^e-th root of 1
2097 : a square --> w even power of y, hence w^(2^(e-1)) = 1 */
2098 21786753 : p1 = Fl_sqr_pre(w,p,pi);
2099 21786753 : for (k=1; p1 != 1 && k < e; k++) p1 = Fl_sqr_pre(p1,p,pi);
2100 21786753 : if (k == e) return ~0UL;
2101 : /* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */
2102 21758589 : p1 = y;
2103 21758589 : for (i=1; i < e-k; i++) p1 = Fl_sqr_pre(p1, p, pi);
2104 21758589 : y = Fl_sqr_pre(p1, p, pi); e = k;
2105 21758589 : w = Fl_mul_pre(y, w, p, pi);
2106 21758588 : v = Fl_mul_pre(v, p1, p, pi);
2107 : }
2108 26333389 : p1 = p - v; if (v > p1) v = p1;
2109 26333389 : return v;
2110 : }
2111 :
2112 : ulong
2113 60253743 : Fl_sqrt(ulong a, ulong p)
2114 : {
2115 60253743 : ulong pi = get_Fl_red(p);
2116 60253951 : return Fl_sqrt_pre_i(a, 0, p, pi);
2117 : }
2118 :
2119 : ulong
2120 3415746 : Fl_sqrt_pre(ulong a, ulong p, ulong pi)
2121 : {
2122 3415746 : return Fl_sqrt_pre_i(a, 0, p, pi);
2123 : }
2124 :
2125 : static ulong
2126 46489 : Fl_lgener_pre_all(ulong l, long e, ulong r, ulong p, ulong pi, ulong *pt_m)
2127 : {
2128 : ulong x, y, m;
2129 46489 : ulong le1 = upowuu(l, e-1);
2130 73110 : for (x = 2; ; x++)
2131 : {
2132 99731 : y = Fl_powu_pre(x, r, p, pi);
2133 73109 : if (y==1) continue;
2134 56702 : m = Fl_powu_pre(y, le1, p, pi);
2135 56703 : if (m != 1) break;
2136 : }
2137 46489 : *pt_m = m;
2138 46489 : return y;
2139 : }
2140 :
2141 : /* solve x^l = a , l prime in G of order q.
2142 : *
2143 : * q = (l^e)*r, e >= 1, (r,l) = 1
2144 : * y generates the l-Sylow of G
2145 : * m = y^(l^(e-1)) != 1 */
2146 : static ulong
2147 110550 : Fl_sqrtl_raw(ulong a, ulong l, ulong e, ulong r, ulong p, ulong pi, ulong y, ulong m)
2148 : {
2149 : ulong p1, v, w, z, dl;
2150 : ulong u2;
2151 110550 : if (a==0) return a;
2152 110550 : u2 = Fl_inv(l%r, r);
2153 110550 : v = Fl_powu_pre(a, u2, p, pi);
2154 110550 : w = Fl_powu_pre(v, l, p, pi);
2155 110550 : w = Fl_mul_pre(w, Fl_inv(a, p), p, pi);
2156 110536 : if (w==1) return v;
2157 45264 : if (y==0) y = Fl_lgener_pre_all(l, e, r, p, pi, &m);
2158 109466 : while (w!=1)
2159 : {
2160 49545 : ulong k = 0;
2161 49545 : p1 = w;
2162 : do
2163 : {
2164 73354 : z = p1; p1 = Fl_powu_pre(p1, l, p, pi);
2165 73354 : k++;
2166 73354 : } while (p1!=1);
2167 49545 : if (k==e) return ULONG_MAX;
2168 18938 : dl = Fl_log_pre(z, m, l, p, pi);
2169 18938 : dl = Fl_neg(dl, l);
2170 18938 : p1 = Fl_powu_pre(y,dl*upowuu(l,e-k-1),p,pi);
2171 18938 : m = Fl_powu_pre(m, dl, p, pi);
2172 18938 : e = k;
2173 18938 : v = Fl_mul_pre(p1,v,p,pi);
2174 18938 : y = Fl_powu_pre(p1,l,p,pi);
2175 18938 : w = Fl_mul_pre(y,w,p,pi);
2176 : }
2177 14657 : return v;
2178 : }
2179 :
2180 : static ulong
2181 109808 : Fl_sqrtl_i(ulong a, ulong l, ulong p, ulong pi, ulong y, ulong m)
2182 : {
2183 109808 : ulong r, e = u_lvalrem(p-1, l, &r);
2184 109808 : return Fl_sqrtl_raw(a, l, e, r, p, pi, y, m);
2185 : }
2186 :
2187 : ulong
2188 109808 : Fl_sqrtl_pre(ulong a, ulong l, ulong p, ulong pi)
2189 : {
2190 109808 : return Fl_sqrtl_i(a, l, p, pi, 0, 0);
2191 : }
2192 :
2193 : ulong
2194 0 : Fl_sqrtl(ulong a, ulong l, ulong p)
2195 : {
2196 0 : ulong pi = get_Fl_red(p);
2197 0 : return Fl_sqrtl_i(a, l, p, pi, 0, 0);
2198 : }
2199 :
2200 : ulong
2201 67950 : Fl_sqrtn_pre(ulong a, long n, ulong p, ulong pi, ulong *zetan)
2202 : {
2203 67950 : ulong m, q = p-1, z;
2204 67950 : ulong nn = n >= 0 ? (ulong)n: -(ulong)n;
2205 67950 : if (a==0)
2206 : {
2207 48139 : if (n < 0) pari_err_INV("Fl_sqrtn", mkintmod(gen_0,utoi(p)));
2208 48132 : if (zetan) *zetan = 1UL;
2209 48132 : return 0;
2210 : }
2211 19811 : if (n==1)
2212 : {
2213 329 : if (zetan) *zetan = 1;
2214 329 : return n < 0? Fl_inv(a,p): a;
2215 : }
2216 19482 : if (n==2)
2217 : {
2218 4613 : if (zetan) *zetan = p-1;
2219 4613 : return Fl_sqrt_pre_i(a, 0, p, pi);
2220 : }
2221 14869 : if (a == 1 && !zetan) return a;
2222 7763 : m = ugcd(nn, q);
2223 7763 : z = 1;
2224 7763 : if (m!=1)
2225 : {
2226 1190 : GEN F = factoru(m);
2227 : long i, j, e;
2228 : ulong r, zeta, y, l;
2229 2436 : for (i = nbrows(F); i; i--)
2230 : {
2231 1302 : l = ucoeff(F,i,1);
2232 1302 : j = ucoeff(F,i,2);
2233 1302 : e = u_lvalrem(q,l, &r);
2234 1302 : y = Fl_lgener_pre_all(l, e, r, p, pi, &zeta);
2235 1302 : if (zetan)
2236 714 : z = Fl_mul_pre(z, Fl_powu_pre(y, upowuu(l,e-j), p, pi), p, pi);
2237 1302 : if (a!=1)
2238 : do
2239 : {
2240 742 : a = Fl_sqrtl_raw(a, l, e, r, p, pi, y, zeta);
2241 728 : if (a==ULONG_MAX) return ULONG_MAX;
2242 686 : } while (--j);
2243 : }
2244 : }
2245 7707 : if (m != nn)
2246 : {
2247 6594 : ulong qm = q/m, nm = nn/m;
2248 6594 : a = Fl_powu_pre(a, Fl_inv(nm%qm, qm), p, pi);
2249 : }
2250 7707 : if (n < 0) a = Fl_inv(a, p);
2251 7707 : if (zetan) *zetan = z;
2252 7707 : return a;
2253 : }
2254 :
2255 : ulong
2256 67950 : Fl_sqrtn(ulong a, long n, ulong p, ulong *zetan)
2257 : {
2258 67950 : ulong pi = get_Fl_red(p);
2259 67950 : return Fl_sqrtn_pre(a, n, p, pi, zetan);
2260 : }
2261 :
2262 : /* Cipolla is better than Tonelli-Shanks when e = v_2(p-1) is "too big".
2263 : * Otherwise, is a constant times worse; for p = 3 (mod 4), is about 3 times worse,
2264 : * and in average is about 2 or 2.5 times worse. But try both algorithms for
2265 : * S(n) = (2^n+3)^2-8 with n = 750, 771, 779, 790, 874, 1176, 1728, 2604, etc.
2266 : *
2267 : * If X^2 := t^2 - a is not a square in F_p (so X is in F_p^2), then
2268 : * (t+X)^(p+1) = (t-X)(t+X) = a, hence sqrt(a) = (t+X)^((p+1)/2) in F_p^2.
2269 : * If (a|p)=1, then sqrt(a) is in F_p.
2270 : * cf: LNCS 2286, pp 430-434 (2002) [Gonzalo Tornaria] */
2271 :
2272 : /* compute y^2, y = y[1] + y[2] X */
2273 : static GEN
2274 449 : sqrt_Cipolla_sqr(void *data, GEN y)
2275 : {
2276 449 : GEN u = gel(y,1), v = gel(y,2), p = gel(data,2), n = gel(data,3);
2277 449 : GEN u2 = sqri(u), v2 = sqri(v);
2278 449 : v = subii(sqri(addii(v,u)), addii(u2,v2));
2279 449 : u = addii(u2, mulii(v2,n));
2280 : /* NOT mkvec2: must be gerepileupto-able */
2281 449 : retmkvec2(modii(u,p), modii(v,p));
2282 : }
2283 : /* compute (t+X) y^2 */
2284 : static GEN
2285 23 : sqrt_Cipolla_msqr(void *data, GEN y)
2286 : {
2287 23 : GEN u = gel(y,1), v = gel(y,2), a = gel(data,1), p = gel(data,2), gt = gel(data,4);
2288 23 : ulong t = gt[2];
2289 23 : GEN d = addii(u, mului(t,v)), d2= sqri(d);
2290 23 : GEN b = remii(mulii(a,v), p);
2291 23 : u = subii(mului(t,d2), mulii(b,addii(u,d)));
2292 23 : v = subii(d2, mulii(b,v));
2293 : /* NOT mkvec2: must be gerepileupto-able */
2294 23 : retmkvec2(modii(u,p), modii(v,p));
2295 : }
2296 : /* assume a reduced mod p [ otherwise correct but inefficient ] */
2297 : static GEN
2298 8 : sqrt_Cipolla(GEN a, GEN p)
2299 : {
2300 : pari_sp av1;
2301 : GEN u, v, n, y, pov2;
2302 : ulong t;
2303 :
2304 8 : if (kronecker(a, p) < 0) return NULL;
2305 8 : pov2 = shifti(p,-1);
2306 8 : if (cmpii(a,pov2) > 0) a = subii(a,p); /* center: avoid multiplying by huge base*/
2307 :
2308 8 : av1 = avma;
2309 41 : for(t=1; ; t++)
2310 : {
2311 74 : n = subsi((long)(t*t), a);
2312 41 : if (kronecker(n, p) < 0) break;
2313 33 : set_avma(av1);
2314 : }
2315 :
2316 : /* compute (t+X)^((p-1)/2) =: u+vX */
2317 8 : u = utoipos(t);
2318 8 : y = gen_pow_fold(mkvec2(u, gen_1), pov2, mkvec4(a,p,n,u),
2319 : sqrt_Cipolla_sqr, sqrt_Cipolla_msqr);
2320 : /* Now u+vX = (t+X)^((p-1)/2); thus
2321 : * (u+vX)(t+X) = sqrt(a) + 0 X
2322 : * Whence,
2323 : * sqrt(a) = (u+vt)t - v*a
2324 : * 0 = (u+vt)
2325 : * Thus a square root is v*a */
2326 :
2327 8 : v = Fp_mul(gel(y, 2), a, p);
2328 8 : if (cmpii(v,pov2) > 0) v = subii(p,v);
2329 8 : return v;
2330 : }
2331 :
2332 : /* Return NULL if p is found to be composite */
2333 : static GEN
2334 2803 : Fp_2gener_all(long e, GEN p)
2335 : {
2336 : GEN y, m;
2337 : long k;
2338 2803 : GEN q = shifti(subiu(p,1), -e); /* q = (p-1)/2^oo is odd */
2339 2803 : if (e==0 && !equaliu(p,2)) return NULL;
2340 9315 : for (k=2; ; k++)
2341 6512 : {
2342 9315 : long i = krosi(k, p);
2343 9315 : if (i >= 0)
2344 : {
2345 6512 : if (i) continue;
2346 0 : return NULL;
2347 : }
2348 2803 : y = m = Fp_pow(utoi(k), q, p);
2349 9512 : for (i=1; i<e; i++)
2350 6709 : if (equali1(m = Fp_sqr(m, p))) break;
2351 2803 : if (i == e) break; /* success */
2352 : }
2353 2803 : return y;
2354 : }
2355 :
2356 : /* Return NULL if p is found to be composite */
2357 : GEN
2358 980 : Fp_2gener(GEN p)
2359 980 : { return Fp_2gener_all(vali(subis(p,1)),p); }
2360 :
2361 : /* smallest square root */
2362 : static GEN
2363 27551 : choose_sqrt(GEN v, GEN p)
2364 : {
2365 27551 : pari_sp av = avma;
2366 27551 : GEN q = subii(p,v);
2367 27551 : if (cmpii(v,q) > 0) v = q; else set_avma(av);
2368 27551 : return v;
2369 : }
2370 : /* Tonelli-Shanks. Assume p is prime and return NULL if (a,p) = -1. */
2371 : GEN
2372 3492988 : Fp_sqrt_i(GEN a, GEN y, GEN p)
2373 : {
2374 3492988 : pari_sp av = avma;
2375 : long i, k, e;
2376 : GEN p1, q, v, w;
2377 :
2378 3492988 : if (typ(a) != t_INT) pari_err_TYPE("Fp_sqrt",a);
2379 3492991 : if (typ(p) != t_INT) pari_err_TYPE("Fp_sqrt",p);
2380 3492991 : if (signe(p) <= 0 || equali1(p)) pari_err_PRIME("Fp_sqrt",p);
2381 3492988 : if (lgefint(p) == 3)
2382 : {
2383 3465322 : ulong pp = uel(p,2), u = Fl_sqrt(umodiu(a, pp), pp);
2384 3465358 : if (u == ~0UL) return NULL;
2385 3465316 : return utoi(u);
2386 : }
2387 :
2388 27666 : a = modii(a, p); if (!signe(a)) { set_avma(av); return gen_0; }
2389 27574 : p1 = subiu(p,1); e = vali(p1);
2390 27574 : if (e <= 2)
2391 : { /* direct formulas more efficient */
2392 : pari_sp av2;
2393 22565 : if (e == 0) pari_err_PRIME("Fp_sqrt [modulus]",p); /* p != 2 */
2394 22565 : if (e == 1)
2395 : {
2396 13362 : q = addiu(shifti(p1,-2),1); /* (p+1) / 4 */
2397 13362 : v = Fp_pow(a, q, p);
2398 : }
2399 : else
2400 : { /* Atkin's formula */
2401 9203 : GEN i, a2 = shifti(a,1);
2402 9203 : if (cmpii(a2,p) >= 0) a2 = subii(a2,p);
2403 9203 : q = shifti(p1, -3); /* (p-5)/8 */
2404 9203 : v = Fp_pow(a2, q, p);
2405 9203 : i = Fp_mul(a2, Fp_sqr(v,p), p); /* i^2 = -1 */
2406 9203 : v = Fp_mul(a, Fp_mul(v, subiu(i,1), p), p);
2407 : }
2408 22565 : av2 = avma;
2409 : /* must check equality in case (a/p) = -1 or p not prime */
2410 22565 : e = equalii(Fp_sqr(v,p), a); set_avma(av2);
2411 22565 : return e? gerepileuptoint(av,choose_sqrt(v,p)): NULL;
2412 : }
2413 : /* On average, Cipolla is better than Tonelli/Shanks if and only if
2414 : * e(e-1) > 8*log2(n)+20, see LNCS 2286 pp 430 [GTL] */
2415 5009 : if (e*(e-1) > 20 + 8 * expi(p))
2416 : {
2417 8 : v = sqrt_Cipolla(a,p); if (!v) return gc_NULL(av);
2418 8 : return gerepileuptoint(av,v);
2419 : }
2420 5001 : if (!y)
2421 : {
2422 1823 : y = Fp_2gener_all(e, p);
2423 1823 : if (!y) pari_err_PRIME("Fp_sqrt [modulus]",p);
2424 : }
2425 5001 : q = shifti(p1,-e); /* q = (p-1)/2^oo is odd */
2426 5001 : p1 = Fp_pow(a, shifti(q,-1), p); /* a ^ (q-1)/2 */
2427 5001 : v = Fp_mul(a, p1, p);
2428 5001 : w = Fp_mul(v, p1, p);
2429 17078 : while (!equali1(w))
2430 : { /* a*w = v^2, y primitive 2^e-th root of 1
2431 : a square --> w even power of y, hence w^(2^(e-1)) = 1 */
2432 7076 : p1 = Fp_sqr(w,p);
2433 7076 : for (k=1; !equali1(p1) && k < e; k++) p1 = Fp_sqr(p1,p);
2434 7076 : if (k == e) return gc_NULL(av); /* p composite or (a/p) != 1 */
2435 : /* w ^ (2^k) = 1 --> w = y ^ (u * 2^(e-k)), u odd */
2436 7076 : p1 = y;
2437 7076 : for (i=1; i < e-k; i++) p1 = Fp_sqr(p1,p);
2438 7076 : y = Fp_sqr(p1, p); e = k;
2439 7076 : w = Fp_mul(y, w, p);
2440 7076 : v = Fp_mul(v, p1, p);
2441 7076 : if (gc_needed(av,1))
2442 : {
2443 0 : if(DEBUGMEM>1) pari_warn(warnmem,"Fp_sqrt");
2444 0 : gerepileall(av,3, &y,&w,&v);
2445 : }
2446 : }
2447 5001 : return gerepileuptoint(av, choose_sqrt(v,p));
2448 : }
2449 :
2450 : GEN
2451 3478561 : Fp_sqrt(GEN a, GEN p)
2452 : {
2453 3478561 : return Fp_sqrt_i(a, NULL, p);
2454 : }
2455 :
2456 : /*********************************************************************/
2457 : /** **/
2458 : /** GCD & BEZOUT **/
2459 : /** **/
2460 : /*********************************************************************/
2461 :
2462 : GEN
2463 27761468 : lcmii(GEN x, GEN y)
2464 : {
2465 : pari_sp av;
2466 : GEN a, b;
2467 27761468 : if (!signe(x) || !signe(y)) return gen_0;
2468 27761468 : av = avma;
2469 27761468 : a = gcdii(x,y); if (!equali1(a)) y = diviiexact(y,a);
2470 27761458 : b = mulii(x,y); setabssign(b); return gerepileuptoint(av, b);
2471 : }
2472 :
2473 : /* given x in assume 0 < x < N; return u in (Z/NZ)^* such that u x = gcd(x,N) (mod N);
2474 : * set *pd = gcd(x,N) */
2475 : GEN
2476 4185676 : Fp_invgen(GEN x, GEN N, GEN *pd)
2477 : {
2478 : GEN d, d0, e, v;
2479 4185676 : if (lgefint(N) == 3)
2480 : {
2481 3619270 : ulong dd, NN = N[2], xx = umodiu(x,NN);
2482 3619270 : if (!xx) { *pd = N; return gen_0; }
2483 3619270 : xx = Fl_invgen(xx, NN, &dd);
2484 3619270 : *pd = utoi(dd); return utoi(xx);
2485 : }
2486 566406 : *pd = d = bezout(x, N, &v, NULL);
2487 566406 : if (equali1(d)) return v;
2488 : /* vx = gcd(x,N) (mod N), v coprime to N/d but need not be coprime to N */
2489 469379 : e = diviiexact(N,d);
2490 469379 : d0 = Z_ppo(d, e); /* d = d0 d1, d0 coprime to N/d, rad(d1) | N/d */
2491 469379 : if (equali1(d0)) return v;
2492 333159 : if (!equalii(d,d0)) e = lcmii(e, diviiexact(d,d0));
2493 333159 : return Z_chinese_coprime(v, gen_1, e, d0, mulii(e,d0));
2494 : }
2495 :
2496 : /*********************************************************************/
2497 : /** **/
2498 : /** CHINESE REMAINDERS **/
2499 : /** **/
2500 : /*********************************************************************/
2501 :
2502 : /* Chinese Remainder Theorem. x and y must have the same type (integermod,
2503 : * polymod, or polynomial/vector/matrix recursively constructed with these
2504 : * as coefficients). Creates (with the same type) a z in the same residue
2505 : * class as x and the same residue class as y, if it is possible.
2506 : *
2507 : * We also allow (during recursion) two identical objects even if they are
2508 : * not integermod or polymod. For example:
2509 : *
2510 : * ? x = [1, Mod(5, 11), Mod(X + Mod(2, 7), X^2 + 1)];
2511 : * ? y = [1, Mod(7, 17), Mod(X + Mod(0, 3), X^2 + 1)];
2512 : * ? chinese(x, y)
2513 : * %3 = [1, Mod(16, 187), Mod(X + mod(9, 21), X^2 + 1)] */
2514 :
2515 : static GEN
2516 595414 : gen_chinese(GEN x, GEN(*f)(GEN,GEN))
2517 : {
2518 595414 : GEN z = gassoc_proto(f,x,NULL);
2519 595407 : if (z == gen_1) retmkintmod(gen_0,gen_1);
2520 595372 : return z;
2521 : }
2522 :
2523 : /* x t_INTMOD, y t_POLMOD; promote x to t_POLMOD mod Pol(x.mod) then
2524 : * call chinese: makes Mod(0,1) a better "neutral" element */
2525 : static GEN
2526 21 : chinese_intpol(GEN x,GEN y)
2527 : {
2528 21 : pari_sp av = avma;
2529 21 : GEN z = mkpolmod(gel(x,2), scalarpol_shallow(gel(x,1), varn(gel(y,1))));
2530 21 : return gerepileupto(av, chinese(z, y));
2531 : }
2532 :
2533 : GEN
2534 49 : chinese1(GEN x) { return gen_chinese(x,chinese); }
2535 :
2536 : GEN
2537 16504 : chinese(GEN x, GEN y)
2538 : {
2539 : pari_sp av;
2540 16504 : long tx = typ(x), ty;
2541 : GEN z,p1,p2,d,u,v;
2542 :
2543 16504 : if (!y) return chinese1(x);
2544 16455 : if (gidentical(x,y)) return gcopy(x);
2545 16448 : ty = typ(y);
2546 16448 : if (tx == ty) switch(tx)
2547 : {
2548 : case t_POLMOD:
2549 : {
2550 28 : GEN A = gel(x,1), B = gel(y,1);
2551 28 : GEN a = gel(x,2), b = gel(y,2);
2552 28 : if (varn(A)!=varn(B)) pari_err_VAR("chinese",A,B);
2553 28 : if (RgX_equal(A,B)) retmkpolmod(chinese(a,b), gcopy(A)); /*same modulus*/
2554 28 : av = avma;
2555 28 : d = RgX_extgcd(A,B,&u,&v);
2556 28 : p2 = gsub(b, a);
2557 28 : if (!gequal0(gmod(p2, d))) break;
2558 28 : p1 = gdiv(A,d);
2559 28 : p2 = gadd(a, gmul(gmul(u,p1), p2));
2560 :
2561 28 : z = cgetg(3, t_POLMOD);
2562 28 : gel(z,1) = gmul(p1,B);
2563 28 : gel(z,2) = gmod(p2,gel(z,1));
2564 28 : return gerepileupto(av, z);
2565 : }
2566 : case t_INTMOD:
2567 : {
2568 16385 : GEN A = gel(x,1), B = gel(y,1);
2569 16385 : GEN a = gel(x,2), b = gel(y,2), c, d, C, U;
2570 16385 : z = cgetg(3,t_INTMOD);
2571 16385 : Z_chinese_pre(A, B, &C, &U, &d);
2572 16385 : c = Z_chinese_post(a, b, C, U, d);
2573 16385 : if (!c) pari_err_OP("chinese", x,y);
2574 16385 : set_avma((pari_sp)z);
2575 16385 : gel(z,1) = icopy(C);
2576 16385 : gel(z,2) = icopy(c); return z;
2577 : }
2578 : case t_POL:
2579 : {
2580 7 : long i, lx = lg(x), ly = lg(y);
2581 7 : if (varn(x) != varn(y)) break;
2582 7 : if (lx < ly) { swap(x,y); lswap(lx,ly); }
2583 7 : z = cgetg(lx, t_POL); z[1] = x[1];
2584 7 : for (i=2; i<ly; i++) gel(z,i) = chinese(gel(x,i),gel(y,i));
2585 7 : for ( ; i<lx; i++) gel(z,i) = gcopy(gel(x,i));
2586 7 : return z;
2587 : }
2588 :
2589 : case t_VEC: case t_COL: case t_MAT:
2590 : {
2591 : long i, lx;
2592 7 : z = cgetg_copy(x, &lx); if (lx!=lg(y)) break;
2593 7 : for (i=1; i<lx; i++) gel(z,i) = chinese(gel(x,i),gel(y,i));
2594 7 : return z;
2595 : }
2596 : }
2597 21 : if (tx == t_POLMOD && ty == t_INTMOD) return chinese_intpol(y,x);
2598 7 : if (ty == t_POLMOD && tx == t_INTMOD) return chinese_intpol(x,y);
2599 0 : pari_err_OP("chinese",x,y);
2600 : return NULL; /* LCOV_EXCL_LINE */
2601 : }
2602 :
2603 : /* init chinese(Mod(.,A), Mod(.,B)) */
2604 : void
2605 238927 : Z_chinese_pre(GEN A, GEN B, GEN *pC, GEN *pU, GEN *pd)
2606 : {
2607 238927 : GEN u, d = bezout(A,B,&u,NULL); /* U = u(A/d), u(A/d) + v(B/d) = 1 */
2608 238930 : GEN t = diviiexact(A,d);
2609 238925 : *pU = mulii(u, t);
2610 238917 : *pC = mulii(t, B);
2611 238911 : if (pd) *pd = d;
2612 238911 : }
2613 : /* Assume C = lcm(A, B), U = 0 mod (A/d), U = 1 mod (B/d), a = b mod d,
2614 : * where d = gcd(A,B) or NULL, return x = a (mod A), b (mod B).
2615 : * If d not NULL, check whether a = b mod d. */
2616 : GEN
2617 1226605 : Z_chinese_post(GEN a, GEN b, GEN C, GEN U, GEN d)
2618 : {
2619 : GEN b_a;
2620 1226605 : if (!signe(a))
2621 : {
2622 414428 : if (d && !dvdii(b, d)) return NULL;
2623 414428 : return Fp_mul(b, U, C);
2624 : }
2625 812177 : b_a = subii(b,a);
2626 812177 : if (d && !dvdii(b_a, d)) return NULL;
2627 812177 : return modii(addii(a, mulii(U, b_a)), C);
2628 : }
2629 : static ulong
2630 2322493 : u_chinese_post(ulong a, ulong b, ulong C, ulong U)
2631 : {
2632 2322493 : if (!a) return Fl_mul(b, U, C);
2633 2322493 : return Fl_add(a, Fl_mul(U, Fl_sub(b,a,C), C), C);
2634 : }
2635 :
2636 : GEN
2637 2142 : Z_chinese(GEN a, GEN b, GEN A, GEN B)
2638 : {
2639 2142 : pari_sp av = avma;
2640 2142 : GEN C, U; Z_chinese_pre(A, B, &C, &U, NULL);
2641 2142 : return gerepileuptoint(av, Z_chinese_post(a,b, C, U, NULL));
2642 : }
2643 : GEN
2644 220343 : Z_chinese_all(GEN a, GEN b, GEN A, GEN B, GEN *pC)
2645 : {
2646 220343 : GEN U; Z_chinese_pre(A, B, pC, &U, NULL);
2647 220328 : return Z_chinese_post(a,b, *pC, U, NULL);
2648 : }
2649 :
2650 : /* return lift(chinese(a mod A, b mod B))
2651 : * assume(A,B)=1, a,b,A,B integers and C = A*B */
2652 : GEN
2653 334209 : Z_chinese_coprime(GEN a, GEN b, GEN A, GEN B, GEN C)
2654 : {
2655 334209 : pari_sp av = avma;
2656 334209 : GEN U = mulii(Fp_inv(A,B), A);
2657 334209 : return gerepileuptoint(av, Z_chinese_post(a,b,C,U, NULL));
2658 : }
2659 : ulong
2660 2322493 : u_chinese_coprime(ulong a, ulong b, ulong A, ulong B, ulong C)
2661 2322493 : { return u_chinese_post(a,b,C, A * Fl_inv(A % B,B)); }
2662 :
2663 : /* chinese1 for coprime moduli in Z */
2664 : static GEN
2665 653218 : chinese1_coprime_Z_aux(GEN x, GEN y)
2666 : {
2667 653218 : GEN z = cgetg(3, t_INTMOD);
2668 653218 : GEN A = gel(x,1), a = gel(x, 2);
2669 653218 : GEN B = gel(y,1), b = gel(y, 2), C = mulii(A,B);
2670 653218 : pari_sp av = avma;
2671 653218 : GEN U = mulii(Fp_inv(A,B), A);
2672 653218 : gel(z,2) = gerepileuptoint(av, Z_chinese_post(a,b,C,U, NULL));
2673 653218 : gel(z,1) = C; return z;
2674 : }
2675 : GEN
2676 595365 : chinese1_coprime_Z(GEN x) {return gen_chinese(x,chinese1_coprime_Z_aux);}
2677 :
2678 : /*********************************************************************/
2679 : /** **/
2680 : /** MODULAR EXPONENTIATION **/
2681 : /** **/
2682 : /*********************************************************************/
2683 :
2684 : /* xa, ya = t_VECSMALL */
2685 : GEN
2686 1312381 : ZV_producttree(GEN xa)
2687 : {
2688 1312381 : long n = lg(xa)-1;
2689 1312381 : long m = n==1 ? 1: expu(n-1)+1;
2690 1312381 : GEN T = cgetg(m+1, t_VEC), t;
2691 : long i, j, k;
2692 1312377 : t = cgetg(((n+1)>>1)+1, t_VEC);
2693 1312374 : if (typ(xa)==t_VECSMALL)
2694 : {
2695 1091090 : for (j=1, k=1; k<n; j++, k+=2)
2696 632906 : gel(t, j) = muluu(xa[k], xa[k+1]);
2697 458184 : if (k==n) gel(t, j) = utoi(xa[k]);
2698 : } else {
2699 2016739 : for (j=1, k=1; k<n; j++, k+=2)
2700 1162544 : gel(t, j) = mulii(gel(xa,k), gel(xa,k+1));
2701 854195 : if (k==n) gel(t, j) = icopy(gel(xa,k));
2702 : }
2703 1312378 : gel(T,1) = t;
2704 2084907 : for (i=2; i<=m; i++)
2705 : {
2706 772533 : GEN u = gel(T, i-1);
2707 772533 : long n = lg(u)-1;
2708 772533 : t = cgetg(((n+1)>>1)+1, t_VEC);
2709 1794763 : for (j=1, k=1; k<n; j++, k+=2)
2710 1022234 : gel(t, j) = mulii(gel(u, k), gel(u, k+1));
2711 772529 : if (k==n) gel(t, j) = gel(u, k);
2712 772529 : gel(T, i) = t;
2713 : }
2714 1312374 : return T;
2715 : }
2716 :
2717 : /* return [A mod P[i], i=1..#P], T = ZV_producttree(P) */
2718 : GEN
2719 42297434 : Z_ZV_mod_tree(GEN A, GEN P, GEN T)
2720 : {
2721 : long i,j,k;
2722 42297434 : long m = lg(T)-1, n = lg(P)-1;
2723 : GEN t;
2724 42297434 : GEN Tp = cgetg(m+1, t_VEC);
2725 41467425 : gel(Tp, m) = mkvec(A);
2726 86234534 : for (i=m-1; i>=1; i--)
2727 : {
2728 44401576 : GEN u = gel(T, i);
2729 44401576 : GEN v = gel(Tp, i+1);
2730 44401576 : long n = lg(u)-1;
2731 44401576 : t = cgetg(n+1, t_VEC);
2732 92893364 : for (j=1, k=1; k<n; j++, k+=2)
2733 : {
2734 47923814 : gel(t, k) = modii(gel(v, j), gel(u, k));
2735 48348711 : gel(t, k+1) = modii(gel(v, j), gel(u, k+1));
2736 : }
2737 44969550 : if (k==n) gel(t, k) = gel(v, j);
2738 44969550 : gel(Tp, i) = t;
2739 : }
2740 : {
2741 41832958 : GEN u = gel(T, i+1);
2742 41832958 : GEN v = gel(Tp, i+1);
2743 41832958 : long l = lg(u)-1;
2744 41832958 : if (typ(P)==t_VECSMALL)
2745 : {
2746 40520731 : GEN R = cgetg(n+1, t_VECSMALL);
2747 128207364 : for (j=1, k=1; j<=l; j++, k+=2)
2748 : {
2749 87072245 : uel(R,k) = umodiu(gel(v, j), P[k]);
2750 87705636 : if (k < n)
2751 63417897 : uel(R,k+1) = umodiu(gel(v, j), P[k+1]);
2752 : }
2753 41135119 : return R;
2754 : }
2755 : else
2756 : {
2757 1312227 : GEN R = cgetg(n+1, t_VEC);
2758 3646482 : for (j=1, k=1; j<=l; j++, k+=2)
2759 : {
2760 2334255 : gel(R,k) = modii(gel(v, j), gel(P,k));
2761 2334263 : if (k < n)
2762 1795109 : gel(R,k+1) = modii(gel(v, j), gel(P,k+1));
2763 : }
2764 1312227 : return R;
2765 : }
2766 : }
2767 : }
2768 :
2769 : /* T = ZV_producttree(P), R = ZV_chinesetree(P,T) */
2770 : GEN
2771 32517923 : ZV_chinese_tree(GEN A, GEN P, GEN T, GEN R)
2772 : {
2773 32517923 : long m = lg(T)-1, n = lg(A)-1;
2774 : long i,j,k;
2775 32517923 : GEN Tp = cgetg(m+1, t_VEC);
2776 32414083 : GEN M = gel(T, 1);
2777 32414083 : GEN t = cgetg(lg(M), t_VEC);
2778 32288968 : if (typ(P)==t_VECSMALL)
2779 : {
2780 64502428 : for (j=1, k=1; k<n; j++, k+=2)
2781 : {
2782 44401493 : pari_sp av = avma;
2783 44401493 : GEN a = mului(A[k], gel(R,k)), b = mului(A[k+1], gel(R,k+1));
2784 44332113 : GEN tj = modii(addii(mului(P[k],b), mului(P[k+1],a)), gel(M,j));
2785 44616854 : gel(t, j) = gerepileuptoint(av, tj);
2786 : }
2787 20100935 : if (k==n) gel(t, j) = modii(mului(A[k], gel(R,k)), gel(M, j));
2788 : } else
2789 : {
2790 39611267 : for (j=1, k=1; k<n; j++, k+=2)
2791 : {
2792 27269451 : pari_sp av = avma;
2793 27269451 : GEN a = mulii(gel(A,k), gel(R,k)), b = mulii(gel(A,k+1), gel(R,k+1));
2794 27114725 : GEN tj = modii(addii(mulii(gel(P,k),b), mulii(gel(P,k+1),a)), gel(M,j));
2795 27199172 : gel(t, j) = gerepileuptoint(av, tj);
2796 : }
2797 12341816 : if (k==n) gel(t, j) = modii(mulii(gel(A,k), gel(R,k)), gel(M, j));
2798 : }
2799 32360305 : gel(Tp, 1) = t;
2800 66172054 : for (i=2; i<=m; i++)
2801 : {
2802 33639400 : GEN u = gel(T, i-1), M = gel(T, i);
2803 33639400 : GEN t = cgetg(lg(M), t_VEC);
2804 33688875 : GEN v = gel(Tp, i-1);
2805 33688875 : long n = lg(v)-1;
2806 87661539 : for (j=1, k=1; k<n; j++, k+=2)
2807 : {
2808 53849790 : pari_sp av = avma;
2809 215399160 : gel(t, j) = gerepileuptoint(av, modii(addii(mulii(gel(u, k), gel(v, k+1)),
2810 161549370 : mulii(gel(u, k+1), gel(v, k))), gel(M, j)));
2811 : }
2812 33811749 : if (k==n) gel(t, j) = gel(v, k);
2813 33811749 : gel(Tp, i) = t;
2814 : }
2815 32532654 : return gmael(Tp,m,1);
2816 : }
2817 :
2818 : static GEN
2819 673583 : ncV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)
2820 : {
2821 673583 : long i, l = lg(gel(vA,1)), n = lg(P);
2822 673583 : GEN mod = gmael(T, lg(T)-1, 1), V = cgetg(l, t_COL);
2823 29568793 : for (i=1; i < l; i++)
2824 : {
2825 28895463 : pari_sp av = avma;
2826 28895463 : GEN c, A = cgetg(n, typ(P));
2827 : long j;
2828 28818212 : for (j=1; j < n; j++) A[j] = mael(vA,j,i);
2829 28818212 : c = Fp_center(ZV_chinese_tree(A, P, T, R), mod, m2);
2830 28869641 : gel(V,i) = gerepileuptoint(av, c);
2831 : }
2832 673330 : return V;
2833 : }
2834 :
2835 : static GEN
2836 184583 : nxV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)
2837 : {
2838 184583 : long i, j, l, n = lg(P);
2839 184583 : GEN mod = gmael(T, lg(T)-1, 1), V, w;
2840 184583 : w = cgetg(n, t_VECSMALL);
2841 184513 : for(j=1; j<n; j++) w[j] = lg(gel(vA,j));
2842 184513 : l = vecsmall_max(w);
2843 184572 : V = cgetg(l, t_POL);
2844 184678 : V[1] = mael(vA,1,1);
2845 1105796 : for (i=2; i < l; i++)
2846 : {
2847 921328 : pari_sp av = avma;
2848 921328 : GEN c, A = cgetg(n, typ(P));
2849 920732 : if (typ(P)==t_VECSMALL)
2850 98684 : for (j=1; j < n; j++) A[j] = i < w[j] ? mael(vA,j,i): 0;
2851 : else
2852 822048 : for (j=1; j < n; j++) gel(A,j) = i < w[j] ? gmael(vA,j,i): gen_0;
2853 920732 : c = Fp_center(ZV_chinese_tree(A, P, T, R), mod, m2);
2854 921444 : gel(V,i) = gerepileuptoint(av, c);
2855 : }
2856 184468 : return ZX_renormalize(V, l);
2857 : }
2858 :
2859 : static GEN
2860 6249 : nxCV_polint_center_tree(GEN vA, GEN P, GEN T, GEN R, GEN m2)
2861 : {
2862 6249 : long i, j, l = lg(gel(vA,1)), n = lg(P);
2863 6249 : GEN A = cgetg(n, t_VEC);
2864 6249 : GEN V = cgetg(l, t_COL);
2865 122838 : for (i=1; i < l; i++)
2866 : {
2867 116588 : for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);
2868 116588 : gel(V,i) = nxV_polint_center_tree(A, P, T, R, m2);
2869 : }
2870 6250 : return V;
2871 : }
2872 :
2873 : static GEN
2874 117632 : polint_chinese(GEN worker, GEN mA, GEN P)
2875 : {
2876 117632 : long cnt, pending, n, i, j, l = lg(gel(mA,1));
2877 : struct pari_mt pt;
2878 : GEN done, va, M, A;
2879 : pari_timer ti;
2880 :
2881 117632 : if (l == 1) return cgetg(1, t_MAT);
2882 65948 : cnt = pending = 0;
2883 65948 : n = lg(P);
2884 65948 : A = cgetg(n, t_VEC);
2885 65948 : va = mkvec(A);
2886 65948 : M = cgetg(l, t_MAT);
2887 65948 : if (DEBUGLEVEL>4) timer_start(&ti);
2888 65948 : if (DEBUGLEVEL>5) err_printf("Start parallel Chinese remainder: ");
2889 65948 : mt_queue_start_lim(&pt, worker, l-1);
2890 520983 : for (i=1; i<l || pending; i++)
2891 : {
2892 : long workid;
2893 455035 : for(j=1; j < n; j++) gel(A,j) = gmael(mA,j,i);
2894 455035 : mt_queue_submit(&pt, i, i<l? va: NULL);
2895 455035 : done = mt_queue_get(&pt, &workid, &pending);
2896 455035 : if (done)
2897 : {
2898 424741 : gel(M,workid) = done;
2899 424741 : if (DEBUGLEVEL>5) err_printf("%ld%% ",(++cnt)*100/(l-1));
2900 : }
2901 : }
2902 65948 : if (DEBUGLEVEL>5) err_printf("\n");
2903 65948 : if (DEBUGLEVEL>4) timer_printf(&ti, "nmV_chinese_center");
2904 65948 : mt_queue_end(&pt);
2905 65948 : return M;
2906 : }
2907 :
2908 : GEN
2909 5806 : nxMV_polint_center_tree_worker(GEN vA, GEN T, GEN R, GEN P, GEN m2)
2910 : {
2911 5806 : return nxCV_polint_center_tree(vA, P, T, R, m2);
2912 : }
2913 :
2914 : static GEN
2915 130 : nxMV_polint_center_tree_seq(GEN vA, GEN P, GEN T, GEN R, GEN m2)
2916 : {
2917 130 : long i, j, l = lg(gel(vA,1)), n = lg(P);
2918 130 : GEN A = cgetg(n, t_VEC);
2919 130 : GEN V = cgetg(l, t_MAT);
2920 573 : for (i=1; i < l; i++)
2921 : {
2922 443 : for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);
2923 443 : gel(V,i) = nxCV_polint_center_tree(A, P, T, R, m2);
2924 : }
2925 130 : return V;
2926 : }
2927 :
2928 : static GEN
2929 420 : nxMV_polint_center_tree(GEN mA, GEN P, GEN T, GEN R, GEN m2)
2930 : {
2931 420 : GEN worker = snm_closure(is_entry("_nxMV_polint_worker"), mkvec4(T, R, P, m2));
2932 420 : return polint_chinese(worker, mA, P);
2933 : }
2934 :
2935 : static GEN
2936 7180 : nmV_polint_center_tree_seq(GEN vA, GEN P, GEN T, GEN R, GEN m2)
2937 : {
2938 7180 : long i, j, l = lg(gel(vA,1)), n = lg(P);
2939 7180 : GEN A = cgetg(n, t_VEC);
2940 7180 : GEN V = cgetg(l, t_MAT);
2941 258094 : for (i=1; i < l; i++)
2942 : {
2943 250914 : for (j=1; j < n; j++) gel(A,j) = gmael(vA,j,i);
2944 250914 : gel(V,i) = ncV_polint_center_tree(A, P, T, R, m2);
2945 : }
2946 7180 : return V;
2947 : }
2948 :
2949 : GEN
2950 418823 : nmV_polint_center_tree_worker(GEN vA, GEN T, GEN R, GEN P, GEN m2)
2951 : {
2952 418823 : return ncV_polint_center_tree(vA, P, T, R, m2);
2953 : }
2954 :
2955 : static GEN
2956 117212 : nmV_polint_center_tree(GEN mA, GEN P, GEN T, GEN R, GEN m2)
2957 : {
2958 117212 : GEN worker = snm_closure(is_entry("_polint_worker"), mkvec4(T, R, P, m2));
2959 117212 : return polint_chinese(worker, mA, P);
2960 : }
2961 :
2962 : /* return [A mod P[i], i=1..#P] */
2963 : GEN
2964 0 : Z_ZV_mod(GEN A, GEN P)
2965 : {
2966 0 : pari_sp av = avma;
2967 0 : return gerepilecopy(av, Z_ZV_mod_tree(A, P, ZV_producttree(P)));
2968 : }
2969 : /* P a t_VECSMALL */
2970 : GEN
2971 0 : Z_nv_mod(GEN A, GEN P)
2972 : {
2973 0 : pari_sp av = avma;
2974 0 : return gerepileuptoleaf(av, Z_ZV_mod_tree(A, P, ZV_producttree(P)));
2975 : }
2976 : /* B a ZX, T = ZV_producttree(P) */
2977 : GEN
2978 485408 : ZX_nv_mod_tree(GEN B, GEN A, GEN T)
2979 : {
2980 : pari_sp av;
2981 485408 : long i, j, l = lg(B), n = lg(A)-1;
2982 485408 : GEN V = cgetg(n+1, t_VEC);
2983 1904074 : for (j=1; j <= n; j++)
2984 : {
2985 1418785 : gel(V, j) = cgetg(l, t_VECSMALL);
2986 1418768 : mael(V, j, 1) = B[1]&VARNBITS;
2987 : }
2988 485289 : av = avma;
2989 10678143 : for (i=2; i < l; i++)
2990 : {
2991 10192735 : GEN v = Z_ZV_mod_tree(gel(B, i), A, T);
2992 39770224 : for (j=1; j <= n; j++)
2993 29577824 : mael(V, j, i) = v[j];
2994 10192400 : set_avma(av);
2995 : }
2996 1904239 : for (j=1; j <= n; j++)
2997 1418830 : (void) Flx_renormalize(gel(V, j), l);
2998 485409 : return V;
2999 : }
3000 :
3001 : static GEN
3002 3427 : to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; }
3003 :
3004 : GEN
3005 358 : ZXX_nv_mod_tree(GEN P, GEN xa, GEN T, long w)
3006 : {
3007 358 : pari_sp av = avma;
3008 358 : long i, j, l = lg(P), n = lg(xa)-1, vP = varn(P);
3009 358 : GEN V = cgetg(n+1, t_VEC);
3010 1113 : for (j=1; j <= n; j++)
3011 : {
3012 755 : gel(V, j) = cgetg(l, t_POL);
3013 755 : mael(V, j, 1) = vP;
3014 : }
3015 1846 : for (i=2; i < l; i++)
3016 : {
3017 1488 : GEN v = ZX_nv_mod_tree(to_ZX(gel(P, i), w), xa, T);
3018 4578 : for (j=1; j <= n; j++)
3019 3090 : gmael(V, j, i) = gel(v,j);
3020 : }
3021 1113 : for (j=1; j <= n; j++)
3022 755 : (void) FlxX_renormalize(gel(V, j), l);
3023 358 : return gerepilecopy(av, V);
3024 : }
3025 :
3026 : GEN
3027 443 : ZXC_nv_mod_tree(GEN C, GEN xa, GEN T, long w)
3028 : {
3029 443 : pari_sp av = avma;
3030 443 : long i, j, l = lg(C), n = lg(xa)-1;
3031 443 : GEN V = cgetg(n+1, t_VEC);
3032 1567 : for (j = 1; j <= n; j++)
3033 1124 : gel(V, j) = cgetg(l, t_COL);
3034 2382 : for (i = 1; i < l; i++)
3035 : {
3036 1939 : GEN v = ZX_nv_mod_tree(to_ZX(gel(C, i), w), xa, T);
3037 6761 : for (j = 1; j <= n; j++)
3038 4822 : gmael(V, j, i) = gel(v,j);
3039 : }
3040 443 : return gerepilecopy(av, V);
3041 : }
3042 :
3043 : GEN
3044 130 : ZXM_nv_mod_tree(GEN M, GEN xa, GEN T, long w)
3045 : {
3046 130 : pari_sp av = avma;
3047 130 : long i, j, l = lg(M), n = lg(xa)-1;
3048 130 : GEN V = cgetg(n+1, t_VEC);
3049 469 : for (j=1; j <= n; j++)
3050 339 : gel(V, j) = cgetg(l, t_MAT);
3051 573 : for (i=1; i < l; i++)
3052 : {
3053 443 : GEN v = ZXC_nv_mod_tree(gel(M, i), xa, T, w);
3054 1567 : for (j=1; j <= n; j++)
3055 1124 : gmael(V, j, i) = gel(v,j);
3056 : }
3057 130 : return gerepilecopy(av, V);
3058 : }
3059 :
3060 : GEN
3061 511737 : ZV_nv_mod_tree(GEN B, GEN A, GEN T)
3062 : {
3063 : pari_sp av;
3064 511737 : long i, j, l = lg(B), n = lg(A)-1;
3065 511737 : GEN V = cgetg(n+1, t_VEC);
3066 2381255 : for (j=1; j <= n; j++)
3067 1895195 : gel(V, j) = cgetg(l, t_VECSMALL);
3068 486060 : av = avma;
3069 31390678 : for (i=1; i < l; i++)
3070 : {
3071 30879033 : GEN v = Z_ZV_mod_tree(gel(B, i), A, T);
3072 155780535 : for (j=1; j <= n; j++)
3073 124677714 : mael(V, j, i) = v[j];
3074 31102821 : set_avma(av);
3075 : }
3076 511645 : return V;
3077 : }
3078 :
3079 : GEN
3080 20415 : ZM_nv_mod_tree(GEN M, GEN xa, GEN T)
3081 : {
3082 20415 : pari_sp av = avma;
3083 20415 : long i, j, l = lg(M), n = lg(xa)-1;
3084 20415 : GEN V = cgetg(n+1, t_VEC);
3085 78995 : for (j=1; j <= n; j++)
3086 58578 : gel(V, j) = cgetg(l, t_MAT);
3087 532135 : for (i=1; i < l; i++)
3088 : {
3089 511721 : GEN v = ZV_nv_mod_tree(gel(M, i), xa, T);
3090 2415377 : for (j=1; j <= n; j++)
3091 1903659 : gmael(V, j, i) = gel(v,j);
3092 : }
3093 20414 : return gerepilecopy(av, V);
3094 : }
3095 :
3096 : static GEN
3097 1308824 : ZV_sqr(GEN z)
3098 : {
3099 1308824 : long i,l = lg(z);
3100 1308824 : GEN x = cgetg(l, t_VEC);
3101 1308813 : if (typ(z)==t_VECSMALL)
3102 458027 : for (i=1; i<l; i++) gel(x,i) = sqru(z[i]);
3103 : else
3104 850786 : for (i=1; i<l; i++) gel(x,i) = sqri(gel(z,i));
3105 1308818 : return x;
3106 : }
3107 :
3108 : static GEN
3109 6838567 : ZT_sqr(GEN z)
3110 : {
3111 6838567 : if (typ(z) == t_INT)
3112 3454018 : return sqri(z);
3113 : else
3114 : {
3115 3384549 : long i,l = lg(z);
3116 3384549 : GEN x = cgetg(l, t_VEC);
3117 3384478 : for (i=1; i<l; i++) gel(x,i) = ZT_sqr(gel(z,i));
3118 3384644 : return x;
3119 : }
3120 : }
3121 :
3122 : static GEN
3123 1308818 : ZV_invdivexact(GEN y, GEN x)
3124 : {
3125 1308818 : long i, l = lg(y);
3126 1308818 : GEN z = cgetg(l,t_VEC);
3127 1308817 : if (typ(x)==t_VECSMALL)
3128 1934332 : for (i=1; i<l; i++)
3129 : {
3130 1476304 : pari_sp av = avma;
3131 1476304 : ulong a = Fl_inv(umodiu(diviuexact(gel(y,i),x[i]), x[i]), x[i]);
3132 1476378 : set_avma(av);
3133 1476367 : gel(z,i) = utoipos(a);
3134 : }
3135 : else
3136 3479662 : for (i=1; i<l; i++)
3137 2628874 : gel(z,i) = Fp_inv(diviiexact(gel(y,i), gel(x,i)), gel(x,i));
3138 1308816 : return z;
3139 : }
3140 :
3141 : /* P t_VECSMALL or t_VEC of t_INT */
3142 : GEN
3143 1308790 : ZV_chinesetree(GEN P, GEN T)
3144 : {
3145 1308790 : GEN T2 = ZT_sqr(T), P2 = ZV_sqr(P);
3146 1308818 : GEN mod = gmael(T,lg(T)-1,1);
3147 1308818 : return ZV_invdivexact(Z_ZV_mod_tree(mod, P2, T2), P);
3148 : }
3149 :
3150 : static GEN
3151 245004 : gc_chinese(pari_sp av, GEN T, GEN a, GEN *pt_mod)
3152 : {
3153 245004 : if (!pt_mod)
3154 2559 : return gerepileupto(av, a);
3155 : else
3156 : {
3157 242445 : GEN mod = gmael(T, lg(T)-1, 1);
3158 242445 : gerepileall(av, 2, &a, &mod);
3159 242445 : *pt_mod = mod;
3160 242445 : return a;
3161 : }
3162 : }
3163 :
3164 : GEN
3165 53956 : ZV_chinese_center(GEN A, GEN P, GEN *pt_mod)
3166 : {
3167 53956 : pari_sp av = avma;
3168 53956 : GEN T = ZV_producttree(P);
3169 53957 : GEN R = ZV_chinesetree(P, T);
3170 53957 : GEN a = ZV_chinese_tree(A, P, T, R);
3171 53957 : GEN mod = gmael(T, lg(T)-1, 1);
3172 53957 : GEN ca = Fp_center(a, mod, shifti(mod,-1));
3173 53957 : return gc_chinese(av, T, ca, pt_mod);
3174 : }
3175 :
3176 : GEN
3177 12637 : ZV_chinese(GEN A, GEN P, GEN *pt_mod)
3178 : {
3179 12637 : pari_sp av = avma;
3180 12637 : GEN T = ZV_producttree(P);
3181 12637 : GEN R = ZV_chinesetree(P, T);
3182 12637 : GEN a = ZV_chinese_tree(A, P, T, R);
3183 12637 : return gc_chinese(av, T, a, pt_mod);
3184 : }
3185 :
3186 : GEN
3187 10865 : nxV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)
3188 : {
3189 10865 : pari_sp av = avma;
3190 10865 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3191 10865 : GEN a = nxV_polint_center_tree(A, P, T, R, m2);
3192 10865 : return gerepileupto(av, a);
3193 : }
3194 :
3195 : GEN
3196 57029 : nxV_chinese_center(GEN A, GEN P, GEN *pt_mod)
3197 : {
3198 57029 : pari_sp av = avma;
3199 57029 : GEN T = ZV_producttree(P);
3200 57029 : GEN R = ZV_chinesetree(P, T);
3201 57029 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3202 57029 : GEN a = nxV_polint_center_tree(A, P, T, R, m2);
3203 57029 : return gc_chinese(av, T, a, pt_mod);
3204 : }
3205 :
3206 : GEN
3207 3760 : ncV_chinese_center(GEN A, GEN P, GEN *pt_mod)
3208 : {
3209 3760 : pari_sp av = avma;
3210 3760 : GEN T = ZV_producttree(P);
3211 3760 : GEN R = ZV_chinesetree(P, T);
3212 3760 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3213 3760 : GEN a = ncV_polint_center_tree(A, P, T, R, m2);
3214 3760 : return gc_chinese(av, T, a, pt_mod);
3215 : }
3216 :
3217 : GEN
3218 0 : ncV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)
3219 : {
3220 0 : pari_sp av = avma;
3221 0 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3222 0 : GEN a = ncV_polint_center_tree(A, P, T, R, m2);
3223 0 : return gerepileupto(av, a);
3224 : }
3225 :
3226 : GEN
3227 11 : nmV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)
3228 : {
3229 11 : pari_sp av = avma;
3230 11 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3231 11 : GEN a = nmV_polint_center_tree(A, P, T, R, m2);
3232 11 : return gerepileupto(av, a);
3233 : }
3234 :
3235 : GEN
3236 7180 : nmV_chinese_center_tree_seq(GEN A, GEN P, GEN T, GEN R)
3237 : {
3238 7180 : pari_sp av = avma;
3239 7180 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3240 7180 : GEN a = nmV_polint_center_tree_seq(A, P, T, R, m2);
3241 7180 : return gerepileupto(av, a);
3242 : }
3243 :
3244 : GEN
3245 117201 : nmV_chinese_center(GEN A, GEN P, GEN *pt_mod)
3246 : {
3247 117201 : pari_sp av = avma;
3248 117201 : GEN T = ZV_producttree(P);
3249 117201 : GEN R = ZV_chinesetree(P, T);
3250 117201 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3251 117201 : GEN a = nmV_polint_center_tree(A, P, T, R, m2);
3252 117201 : return gc_chinese(av, T, a, pt_mod);
3253 : }
3254 :
3255 : GEN
3256 0 : nxCV_chinese_center_tree(GEN A, GEN P, GEN T, GEN R)
3257 : {
3258 0 : pari_sp av = avma;
3259 0 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3260 0 : GEN a = nxCV_polint_center_tree(A, P, T, R, m2);
3261 0 : return gerepileupto(av, a);
3262 : }
3263 :
3264 : GEN
3265 0 : nxCV_chinese_center(GEN A, GEN P, GEN *pt_mod)
3266 : {
3267 0 : pari_sp av = avma;
3268 0 : GEN T = ZV_producttree(P);
3269 0 : GEN R = ZV_chinesetree(P, T);
3270 0 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3271 0 : GEN a = nxCV_polint_center_tree(A, P, T, R, m2);
3272 0 : return gc_chinese(av, T, a, pt_mod);
3273 : }
3274 :
3275 : GEN
3276 130 : nxMV_chinese_center_tree_seq(GEN A, GEN P, GEN T, GEN R)
3277 : {
3278 130 : pari_sp av = avma;
3279 130 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3280 130 : GEN a = nxMV_polint_center_tree_seq(A, P, T, R, m2);
3281 130 : return gerepileupto(av, a);
3282 : }
3283 :
3284 : GEN
3285 420 : nxMV_chinese_center(GEN A, GEN P, GEN *pt_mod)
3286 : {
3287 420 : pari_sp av = avma;
3288 420 : GEN T = ZV_producttree(P);
3289 420 : GEN R = ZV_chinesetree(P, T);
3290 420 : GEN m2 = shifti(gmael(T, lg(T)-1, 1), -1);
3291 420 : GEN a = nxMV_polint_center_tree(A, P, T, R, m2);
3292 420 : return gc_chinese(av, T, a, pt_mod);
3293 : }
3294 :
3295 : /**********************************************************************
3296 : ** **
3297 : ** Powering over (Z/NZ)^*, small N **
3298 : ** **
3299 : **********************************************************************/
3300 :
3301 : /* 2^n mod p; assume n > 1 */
3302 : static ulong
3303 19444360 : Fl_2powu_pre(ulong n, ulong p, ulong pi)
3304 : {
3305 19444360 : ulong y = 2;
3306 19444360 : int j = 1+bfffo(n);
3307 : /* normalize, i.e set highest bit to 1 (we know n != 0) */
3308 19444360 : n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */
3309 360346476 : for (; j; n<<=1,j--)
3310 : {
3311 340951901 : y = Fl_sqr_pre(y,p,pi);
3312 340895517 : if (n & HIGHBIT) y = Fl_double(y, p);
3313 : }
3314 19394575 : return y;
3315 : }
3316 :
3317 : /* 2^n mod p; assume n > 1 and !(p & HIGHMASK) */
3318 : static ulong
3319 820158 : Fl_2powu(ulong n, ulong p)
3320 : {
3321 820158 : ulong y = 2;
3322 820158 : int j = 1+bfffo(n);
3323 : /* normalize, i.e set highest bit to 1 (we know n != 0) */
3324 820158 : n<<=j; j = BITS_IN_LONG-j; /* first bit is now implicit */
3325 2965184 : for (; j; n<<=1,j--)
3326 : {
3327 2145026 : y = (y*y) % p;
3328 2145026 : if (n & HIGHBIT) y = Fl_double(y, p);
3329 : }
3330 820158 : return y;
3331 : }
3332 :
3333 : ulong
3334 94838067 : Fl_powu_pre(ulong x, ulong n0, ulong p, ulong pi)
3335 : {
3336 : ulong y, z, n;
3337 94838067 : if (n0 <= 1)
3338 : { /* frequent special cases */
3339 11513366 : if (n0 == 1) return x;
3340 3161020 : if (n0 == 0) return 1;
3341 : }
3342 83324701 : if (x <= 2)
3343 : {
3344 21265143 : if (x == 2) return Fl_2powu_pre(n0, p, pi);
3345 1855262 : return x; /* 0 or 1 */
3346 : }
3347 62059558 : y = 1; z = x; n = n0;
3348 : for(;;)
3349 : {
3350 1028780218 : if (n&1) y = Fl_mul_pre(y,z,p,pi);
3351 545530161 : n>>=1; if (!n) return y;
3352 483479877 : z = Fl_sqr_pre(z,p,pi);
3353 : }
3354 : }
3355 :
3356 : ulong
3357 44592675 : Fl_powu(ulong x, ulong n0, ulong p)
3358 : {
3359 : ulong y, z, n;
3360 44592675 : if (n0 <= 2)
3361 : { /* frequent special cases */
3362 37341414 : if (n0 == 2) return Fl_sqr(x,p);
3363 5128696 : if (n0 == 1) return x;
3364 81206 : if (n0 == 0) return 1;
3365 : }
3366 7251261 : if (x <= 1) return x; /* 0 or 1 */
3367 7203754 : if (p & HIGHMASK)
3368 641239 : return Fl_powu_pre(x, n0, p, get_Fl_red(p));
3369 6562515 : if (x == 2) return Fl_2powu(n0, p);
3370 5742357 : y = 1; z = x; n = n0;
3371 : for(;;)
3372 : {
3373 87823887 : if (n&1) y = (y*z) % p;
3374 46783122 : n>>=1; if (!n) return y;
3375 41040765 : z = (z*z) % p;
3376 : }
3377 : }
3378 :
3379 : /* Reduce data dependency to maximize internal parallelism */
3380 : GEN
3381 11044937 : Fl_powers_pre(ulong x, long n, ulong p, ulong pi)
3382 : {
3383 : long i, k;
3384 11044937 : GEN powers = cgetg(n + 2, t_VECSMALL);
3385 11038145 : powers[1] = 1; if (n == 0) return powers;
3386 11038145 : powers[2] = x;
3387 46519416 : for (i = 3, k=2; i <= n; i+=2, k++)
3388 : {
3389 35466149 : powers[i] = Fl_sqr_pre(powers[k], p, pi);
3390 35482577 : powers[i+1] = Fl_mul_pre(powers[k], powers[k+1], p, pi);
3391 : }
3392 11053267 : if (i==n+1)
3393 9663958 : powers[i] = Fl_sqr_pre(powers[k], p, pi);
3394 11053406 : return powers;
3395 : }
3396 :
3397 : GEN
3398 3325 : Fl_powers(ulong x, long n, ulong p)
3399 : {
3400 3325 : return Fl_powers_pre(x, n, p, get_Fl_red(p));
3401 : }
3402 :
3403 : /**********************************************************************
3404 : ** **
3405 : ** Powering over (Z/NZ)^*, large N **
3406 : ** **
3407 : **********************************************************************/
3408 :
3409 : static GEN
3410 4295551 : Fp_dblsqr(GEN x, GEN N)
3411 : {
3412 4295551 : GEN z = shifti(Fp_sqr(x, N), 1);
3413 4295550 : return cmpii(z, N) >= 0? subii(z, N): z;
3414 : }
3415 :
3416 : typedef struct muldata {
3417 : GEN (*sqr)(void * E, GEN x);
3418 : GEN (*mul)(void * E, GEN x, GEN y);
3419 : GEN (*mul2)(void * E, GEN x);
3420 : } muldata;
3421 :
3422 : /* modified Barrett reduction with one fold */
3423 : /* See Fast Modular Reduction, W. Hasenplaugh, G. Gaubatz, V. Gopal, ARITH 18 */
3424 :
3425 : static GEN
3426 7718 : Fp_invmBarrett(GEN p, long s)
3427 : {
3428 7718 : GEN R, Q = dvmdii(int2n(3*s),p,&R);
3429 7718 : return mkvec2(Q,R);
3430 : }
3431 :
3432 : /* a <= (N-1)^2, 2^(2s-2) <= N < 2^(2s). Return 0 <= r < N such that
3433 : * a = r (mod N) */
3434 : static GEN
3435 4225418 : Fp_rem_mBarrett(GEN a, GEN B, long s, GEN N)
3436 : {
3437 4225418 : pari_sp av = avma;
3438 4225418 : GEN P = gel(B, 1), Q = gel(B, 2); /* 2^(3s) = P N + Q, 0 <= Q < N */
3439 4225418 : long t = expi(P)+1; /* 2^(t-1) <= P < 2^t */
3440 4225418 : GEN u = shifti(a, -3*s), v = remi2n(a, 3*s); /* a = 2^(3s)u + v */
3441 4225418 : GEN A = addii(v, mulii(Q,u)); /* 0 <= A < 2^(3s+1) */
3442 4225418 : GEN q = shifti(mulii(shifti(A, t-3*s), P), -t); /* A/N - 4 < q <= A/N */
3443 4225418 : GEN r = subii(A, mulii(q, N));
3444 4225418 : GEN sr= subii(r,N); /* 0 <= r < 4*N */
3445 4225418 : if (signe(sr)<0) return gerepileuptoint(av, r);
3446 2545185 : r=sr; sr = subii(r,N); /* 0 <= r < 3*N */
3447 2545185 : if (signe(sr)<0) return gerepileuptoint(av, r);
3448 98533 : r=sr; sr = subii(r,N); /* 0 <= r < 2*N */
3449 98533 : return gerepileuptoint(av, signe(sr)>=0 ? sr:r);
3450 : }
3451 :
3452 : /* Montgomery reduction */
3453 :
3454 : INLINE ulong
3455 720501 : init_montdata(GEN N) { return (ulong) -invmod2BIL(mod2BIL(N)); }
3456 :
3457 : struct montred
3458 : {
3459 : GEN N;
3460 : ulong inv;
3461 : };
3462 :
3463 : /* Montgomery reduction */
3464 : static GEN
3465 32903653 : _sqr_montred(void * E, GEN x)
3466 : {
3467 32903653 : struct montred * D = (struct montred *) E;
3468 32903653 : return red_montgomery(sqri(x), D->N, D->inv);
3469 : }
3470 :
3471 : /* Montgomery reduction */
3472 : static GEN
3473 2820477 : _mul_montred(void * E, GEN x, GEN y)
3474 : {
3475 2820477 : struct montred * D = (struct montred *) E;
3476 2820477 : return red_montgomery(mulii(x, y), D->N, D->inv);
3477 : }
3478 :
3479 : static GEN
3480 5868535 : _mul2_montred(void * E, GEN x)
3481 : {
3482 5868535 : struct montred * D = (struct montred *) E;
3483 5868535 : GEN z = shifti(_sqr_montred(E, x), 1);
3484 5868535 : long l = lgefint(D->N);
3485 5868535 : while (lgefint(z) > l) z = subii(z, D->N);
3486 5868530 : return z;
3487 : }
3488 :
3489 : static GEN
3490 13352616 : _sqr_remii(void* N, GEN x)
3491 13352616 : { return remii(sqri(x), (GEN) N); }
3492 :
3493 : static GEN
3494 1068118 : _mul_remii(void* N, GEN x, GEN y)
3495 1068118 : { return remii(mulii(x, y), (GEN) N); }
3496 :
3497 : static GEN
3498 3030896 : _mul2_remii(void* N, GEN x)
3499 3030896 : { return Fp_dblsqr(x, (GEN) N); }
3500 :
3501 : struct redbarrett
3502 : {
3503 : GEN iM, N;
3504 : long s;
3505 : };
3506 :
3507 : static GEN
3508 3818882 : _sqr_remiibar(void *E, GEN x)
3509 : {
3510 3818882 : struct redbarrett * D = (struct redbarrett *) E;
3511 3818882 : return Fp_rem_mBarrett(sqri(x), D->iM, D->s, D->N);
3512 : }
3513 :
3514 : static GEN
3515 406536 : _mul_remiibar(void *E, GEN x, GEN y)
3516 : {
3517 406536 : struct redbarrett * D = (struct redbarrett *) E;
3518 406536 : return Fp_rem_mBarrett(mulii(x, y), D->iM, D->s, D->N);
3519 : }
3520 :
3521 : static GEN
3522 1264655 : _mul2_remiibar(void *E, GEN x)
3523 : {
3524 1264655 : struct redbarrett * D = (struct redbarrett *) E;
3525 1264655 : return Fp_dblsqr(x, D->N);
3526 : }
3527 :
3528 : static long
3529 963386 : Fp_select_red(GEN *y, ulong k, GEN N, long lN, muldata *D, void **pt_E)
3530 : {
3531 963386 : if (lN >= Fp_POW_BARRETT_LIMIT && (k==0 || ((double)k)*expi(*y) > 2 + expi(N)))
3532 : {
3533 7718 : struct redbarrett * E = (struct redbarrett *) stack_malloc(sizeof(struct redbarrett));
3534 7718 : D->sqr = &_sqr_remiibar;
3535 7718 : D->mul = &_mul_remiibar;
3536 7718 : D->mul2 = &_mul2_remiibar;
3537 7718 : E->N = N;
3538 7718 : E->s = 1+(expi(N)>>1);
3539 7718 : E->iM = Fp_invmBarrett(N, E->s);
3540 7718 : *pt_E = (void*) E;
3541 7718 : return 0;
3542 : }
3543 955668 : else if (mod2(N) && lN < Fp_POW_REDC_LIMIT)
3544 : {
3545 720503 : struct montred * E = (struct montred *) stack_malloc(sizeof(struct montred));
3546 720502 : *y = remii(shifti(*y, bit_accuracy(lN)), N);
3547 720503 : D->sqr = &_sqr_montred;
3548 720503 : D->mul = &_mul_montred;
3549 720503 : D->mul2 = &_mul2_montred;
3550 720503 : E->N = N;
3551 720503 : E->inv = init_montdata(N);
3552 720500 : *pt_E = (void*) E;
3553 720500 : return 1;
3554 : }
3555 : else
3556 : {
3557 235185 : D->sqr = &_sqr_remii;
3558 235185 : D->mul = &_mul_remii;
3559 235185 : D->mul2 = &_mul2_remii;
3560 235185 : *pt_E = (void*) N;
3561 235185 : return 0;
3562 : }
3563 : }
3564 :
3565 : GEN
3566 1462208 : Fp_powu(GEN A, ulong k, GEN N)
3567 : {
3568 1462208 : long lN = lgefint(N);
3569 : int base_is_2, use_montgomery;
3570 : muldata D;
3571 : void *E;
3572 : pari_sp av;
3573 :
3574 1462208 : if (lN == 3) {
3575 90308 : ulong n = uel(N,2);
3576 90308 : return utoi( Fl_powu(umodiu(A, n), k, n) );
3577 : }
3578 1371900 : if (k <= 2)
3579 : { /* frequent special cases */
3580 547848 : if (k == 2) return Fp_sqr(A,N);
3581 140765 : if (k == 1) return A;
3582 0 : if (k == 0) return gen_1;
3583 : }
3584 824052 : av = avma; A = modii(A,N);
3585 824052 : base_is_2 = 0;
3586 824052 : if (lgefint(A) == 3) switch(A[2])
3587 : {
3588 770 : case 1: set_avma(av); return gen_1;
3589 34640 : case 2: base_is_2 = 1; break;
3590 : }
3591 :
3592 : /* TODO: Move this out of here and use for general modular computations */
3593 823282 : use_montgomery = Fp_select_red(&A, k, N, lN, &D, &E);
3594 823282 : if (base_is_2)
3595 34640 : A = gen_powu_fold_i(A, k, E, D.sqr, D.mul2);
3596 : else
3597 788642 : A = gen_powu_i(A, k, E, D.sqr, D.mul);
3598 823282 : if (use_montgomery)
3599 : {
3600 641610 : A = red_montgomery(A, N, ((struct montred *) E)->inv);
3601 641610 : if (cmpii(A, N) >= 0) A = subii(A,N);
3602 : }
3603 823282 : return gerepileuptoint(av, A);
3604 : }
3605 :
3606 : GEN
3607 22302 : Fp_pows(GEN A, long k, GEN N)
3608 : {
3609 22302 : if (lgefint(N) == 3) {
3610 7813 : ulong n = N[2];
3611 7813 : ulong a = umodiu(A, n);
3612 7813 : if (k < 0) {
3613 126 : a = Fl_inv(a, n);
3614 126 : k = -k;
3615 : }
3616 7813 : return utoi( Fl_powu(a, (ulong)k, n) );
3617 : }
3618 14489 : if (k < 0) { A = Fp_inv(A, N); k = -k; };
3619 14489 : return Fp_powu(A, (ulong)k, N);
3620 : }
3621 :
3622 : /* A^K mod N */
3623 : GEN
3624 10224671 : Fp_pow(GEN A, GEN K, GEN N)
3625 : {
3626 : pari_sp av;
3627 10224671 : long s, lN = lgefint(N), sA;
3628 : int base_is_2, use_montgomery;
3629 : GEN y;
3630 : muldata D;
3631 : void *E;
3632 :
3633 10224671 : s = signe(K);
3634 10224671 : if (!s) return dvdii(A,N)? gen_0: gen_1;
3635 10062616 : if (lN == 3 && lgefint(K) == 3)
3636 : {
3637 9700728 : ulong n = N[2], a = umodiu(A, n);
3638 9700820 : if (s < 0) a = Fl_inv(a, n);
3639 9700820 : if (a <= 1) return utoi(a); /* 0 or 1 */
3640 8987976 : return utoi(Fl_powu(a, uel(K,2), n));
3641 : }
3642 :
3643 361888 : av = avma;
3644 361888 : if (s < 0) y = Fp_inv(A,N);
3645 : else
3646 : {
3647 361419 : y = modii(A,N);
3648 361414 : if (!signe(y)) { set_avma(av); return gen_0; }
3649 : }
3650 361883 : if (lgefint(K) == 3) return gerepileuptoint(av, Fp_powu(y, K[2], N));
3651 :
3652 140186 : base_is_2 = 0;
3653 140186 : sA = signe(y)==-1 && mod2(K);
3654 140186 : if (lgefint(y) == 3) switch(y[2])
3655 : {
3656 82 : case 1: return sA ? gen_m1 : gen_1;
3657 98103 : case 2: base_is_2 = 1; break;
3658 : }
3659 :
3660 : /* TODO: Move this out of here and use for general modular computations */
3661 140104 : use_montgomery = Fp_select_red(&y, 0UL, N, lN, &D, &E);
3662 140110 : if (base_is_2)
3663 98109 : y = gen_pow_fold_i(y, K, E, D.sqr, D.mul2);
3664 : else
3665 42001 : y = gen_pow_i(y, K, E, D.sqr, D.mul);
3666 140131 : if (use_montgomery)
3667 : {
3668 78895 : y = red_montgomery(y, N, ((struct montred *) E)->inv);
3669 78892 : if (cmpii(y,N) >= 0) y = subii(y,N);
3670 78894 : if (sA) y = subii(N, y);
3671 : }
3672 140130 : return gerepileuptoint(av,y);
3673 : }
3674 :
3675 : static GEN
3676 2001305 : _Fp_mul(void *E, GEN x, GEN y) { return Fp_mul(x,y,(GEN)E); }
3677 :
3678 : static GEN
3679 23500 : _Fp_sqr(void *E, GEN x) { return Fp_sqr(x,(GEN)E); }
3680 :
3681 : static GEN
3682 55230 : _Fp_one(void *E) { (void) E; return gen_1; }
3683 :
3684 : GEN
3685 84 : Fp_pow_init(GEN x, GEN n, long k, GEN p)
3686 : {
3687 84 : return gen_pow_init(x, n, k, (void*)p, &_Fp_sqr, &_Fp_mul);
3688 : }
3689 :
3690 : GEN
3691 55090 : Fp_pow_table(GEN R, GEN n, GEN p)
3692 : {
3693 55090 : return gen_pow_table(R, n, (void*)p, &_Fp_one, &_Fp_mul);
3694 : }
3695 :
3696 : GEN
3697 2016 : Fp_powers(GEN x, long n, GEN p)
3698 : {
3699 2016 : if (lgefint(p) == 3)
3700 1876 : return Flv_to_ZV(Fl_powers(umodiu(x, uel(p, 2)), n, uel(p, 2)));
3701 140 : return gen_powers(x, n, 1, (void*)p, _Fp_sqr, _Fp_mul, _Fp_one);
3702 : }
3703 :
3704 : GEN
3705 434 : FpV_prod(GEN V, GEN p)
3706 : {
3707 434 : return gen_product(V, (void *)p, &_Fp_mul);
3708 : }
3709 :
3710 : static GEN
3711 7270943 : _Fp_pow(void *E, GEN x, GEN n) { return Fp_pow(x,n,(GEN)E); }
3712 :
3713 : static GEN
3714 105 : _Fp_rand(void *E) { return addiu(randomi(subiu((GEN)E,1)),1); }
3715 :
3716 : static GEN Fp_easylog(void *E, GEN a, GEN g, GEN ord);
3717 :
3718 : static const struct bb_group Fp_star={_Fp_mul,_Fp_pow,_Fp_rand,hash_GEN,
3719 : equalii,equali1,Fp_easylog};
3720 :
3721 : static GEN
3722 788842 : _Fp_red(void *E, GEN x) { return Fp_red(x, (GEN)E); }
3723 :
3724 : static GEN
3725 930650 : _Fp_add(void *E, GEN x, GEN y) { (void) E; return addii(x,y); }
3726 :
3727 : static GEN
3728 835473 : _Fp_neg(void *E, GEN x) { (void) E; return negi(x); }
3729 :
3730 : static GEN
3731 520469 : _Fp_rmul(void *E, GEN x, GEN y) { (void) E; return mulii(x,y); }
3732 :
3733 : static GEN
3734 34096 : _Fp_inv(void *E, GEN x) { return Fp_inv(x,(GEN)E); }
3735 :
3736 : static int
3737 223979 : _Fp_equal0(GEN x) { return signe(x)==0; }
3738 :
3739 : static GEN
3740 28753 : _Fp_s(void *E, long x) { (void) E; return stoi(x); }
3741 :
3742 : static const struct bb_field Fp_field={_Fp_red,_Fp_add,_Fp_rmul,_Fp_neg,
3743 : _Fp_inv,_Fp_equal0,_Fp_s};
3744 :
3745 7468 : const struct bb_field *get_Fp_field(void **E, GEN p)
3746 : {
3747 7468 : *E = (void*)p; return &Fp_field;
3748 : }
3749 :
3750 : /*********************************************************************/
3751 : /** **/
3752 : /** ORDER of INTEGERMOD x in (Z/nZ)* **/
3753 : /** **/
3754 : /*********************************************************************/
3755 : ulong
3756 12327 : Fl_order(ulong a, ulong o, ulong p)
3757 : {
3758 12327 : pari_sp av = avma;
3759 : GEN m, P, E;
3760 : long i;
3761 12327 : if (a==1) return 1;
3762 8694 : if (!o) o = p-1;
3763 8694 : m = factoru(o);
3764 8694 : P = gel(m,1);
3765 8694 : E = gel(m,2);
3766 22218 : for (i = lg(P)-1; i; i--)
3767 : {
3768 13524 : ulong j, l = P[i], e = E[i], t = o / upowuu(l,e), y = Fl_powu(a, t, p);
3769 13524 : if (y == 1) o = t;
3770 15190 : else for (j = 1; j < e; j++)
3771 : {
3772 4445 : y = Fl_powu(y, l, p);
3773 4445 : if (y == 1) { o = t * upowuu(l, j); break; }
3774 : }
3775 : }
3776 8694 : return gc_ulong(av, o);
3777 : }
3778 :
3779 : /*Find the exact order of a assuming a^o==1*/
3780 : GEN
3781 10827 : Fp_order(GEN a, GEN o, GEN p) {
3782 10827 : if (lgefint(p) == 3 && (!o || typ(o) == t_INT))
3783 : {
3784 21 : ulong pp = p[2], oo = (o && lgefint(o)==3)? uel(o,2): pp-1;
3785 21 : return utoi( Fl_order(umodiu(a, pp), oo, pp) );
3786 : }
3787 10806 : return gen_order(a, o, (void*)p, &Fp_star);
3788 : }
3789 : GEN
3790 56 : Fp_factored_order(GEN a, GEN o, GEN p)
3791 56 : { return gen_factored_order(a, o, (void*)p, &Fp_star); }
3792 :
3793 : /* return order of a mod p^e, e > 0, pe = p^e */
3794 : static GEN
3795 70 : Zp_order(GEN a, GEN p, long e, GEN pe)
3796 : {
3797 : GEN ap, op;
3798 70 : if (absequaliu(p, 2))
3799 : {
3800 56 : if (e == 1) return gen_1;
3801 56 : if (e == 2) return mod4(a) == 1? gen_1: gen_2;
3802 49 : if (mod4(a) == 1)
3803 14 : op = gen_1;
3804 : else {
3805 35 : op = gen_2;
3806 35 : a = Fp_sqr(a, pe);
3807 : }
3808 : } else {
3809 14 : ap = (e == 1)? a: remii(a,p);
3810 14 : op = Fp_order(ap, subiu(p,1), p);
3811 14 : if (e == 1) return op;
3812 0 : a = Fp_pow(a, op, pe); /* 1 mod p */
3813 : }
3814 49 : if (equali1(a)) return op;
3815 7 : return mulii(op, powiu(p, e - Z_pval(subiu(a,1), p)));
3816 : }
3817 :
3818 : GEN
3819 63 : znorder(GEN x, GEN o)
3820 : {
3821 63 : pari_sp av = avma;
3822 : GEN b, a;
3823 :
3824 63 : if (typ(x) != t_INTMOD) pari_err_TYPE("znorder [t_INTMOD expected]",x);
3825 56 : b = gel(x,1); a = gel(x,2);
3826 56 : if (!equali1(gcdii(a,b))) pari_err_COPRIME("znorder", a,b);
3827 49 : if (!o)
3828 : {
3829 35 : GEN fa = Z_factor(b), P = gel(fa,1), E = gel(fa,2);
3830 35 : long i, l = lg(P);
3831 35 : o = gen_1;
3832 70 : for (i = 1; i < l; i++)
3833 : {
3834 35 : GEN p = gel(P,i);
3835 35 : long e = itos(gel(E,i));
3836 :
3837 35 : if (l == 2)
3838 35 : o = Zp_order(a, p, e, b);
3839 : else {
3840 0 : GEN pe = powiu(p,e);
3841 0 : o = lcmii(o, Zp_order(remii(a,pe), p, e, pe));
3842 : }
3843 : }
3844 35 : return gerepileuptoint(av, o);
3845 : }
3846 14 : return Fp_order(a, o, b);
3847 : }
3848 : GEN
3849 0 : order(GEN x) { return znorder(x, NULL); }
3850 :
3851 : /*********************************************************************/
3852 : /** **/
3853 : /** DISCRETE LOGARITHM in (Z/nZ)* **/
3854 : /** **/
3855 : /*********************************************************************/
3856 : static GEN
3857 70199 : Fp_log_halfgcd(ulong bnd, GEN C, GEN g, GEN p)
3858 : {
3859 70199 : pari_sp av = avma;
3860 : GEN h1, h2, F, G;
3861 70199 : if (!Fp_ratlift(g,p,C,shifti(C,-1),&h1,&h2)) return gc_NULL(av);
3862 42475 : if ((F = Z_issmooth_fact(h1, bnd)) && (G = Z_issmooth_fact(h2, bnd)))
3863 : {
3864 261 : GEN M = cgetg(3, t_MAT);
3865 261 : gel(M,1) = vecsmall_concat(gel(F, 1),gel(G, 1));
3866 261 : gel(M,2) = vecsmall_concat(gel(F, 2),zv_neg_inplace(gel(G, 2)));
3867 261 : return gerepileupto(av, M);
3868 : }
3869 42214 : return gc_NULL(av);
3870 : }
3871 :
3872 : static GEN
3873 70199 : Fp_log_find_rel(GEN b, ulong bnd, GEN C, GEN p, GEN *g, long *e)
3874 : {
3875 : GEN rel;
3876 : do
3877 : {
3878 70199 : (*e)++; *g = Fp_mul(*g, b, p);
3879 70199 : rel = Fp_log_halfgcd(bnd, C, *g, p);
3880 70199 : } while (!rel);
3881 261 : return rel;
3882 : }
3883 :
3884 : struct Fp_log_rel
3885 : {
3886 : GEN rel;
3887 : ulong prmax;
3888 : long nbrel, nbmax, nbgen;
3889 : };
3890 :
3891 : /* add u^e */
3892 : static void
3893 2583 : addifsmooth1(struct Fp_log_rel *r, GEN z, long u, long e)
3894 : {
3895 2583 : pari_sp av = avma;
3896 2583 : long off = r->prmax+1;
3897 2583 : GEN F = cgetg(3, t_MAT);
3898 2583 : gel(F,1) = vecsmall_append(gel(z,1), off+u);
3899 2583 : gel(F,2) = vecsmall_append(gel(z,2), e);
3900 2583 : gel(r->rel,++r->nbrel) = gerepileupto(av, F);
3901 2583 : }
3902 :
3903 : /* add u^-1 v^-1 */
3904 : static void
3905 99869 : addifsmooth2(struct Fp_log_rel *r, GEN z, long u, long v)
3906 : {
3907 99869 : pari_sp av = avma;
3908 99869 : long off = r->prmax+1;
3909 99869 : GEN P = mkvecsmall2(off+u,off+v), E = mkvecsmall2(-1,-1);
3910 99869 : GEN F = cgetg(3, t_MAT);
3911 99869 : gel(F,1) = vecsmall_concat(gel(z,1), P);
3912 99869 : gel(F,2) = vecsmall_concat(gel(z,2), E);
3913 99869 : gel(r->rel,++r->nbrel) = gerepileupto(av, F);
3914 99869 : }
3915 :
3916 : /*
3917 : Let p=C^2+c
3918 : Solve h = (C+x)*(C+a)-p = 0 [mod l]
3919 : h= -c+x*(C+a)+C*a = 0 [mod l]
3920 : x = (c-C*a)/(C+a) [mod l]
3921 : h = -c+C*(x+a)+a*x
3922 : */
3923 :
3924 : GEN
3925 39004 : Fp_log_sieve_worker(long a, long prmax, GEN C, GEN c, GEN Ci, GEN ci, GEN pi, GEN sz)
3926 : {
3927 39004 : pari_sp ltop = avma;
3928 39004 : long th = expi(mulis(C,a)), n = lg(pi)-1;
3929 : long i, j;
3930 38988 : GEN sieve = zero_zv(a+2)+1;
3931 39004 : GEN L = cgetg(1+a+2, t_VEC);
3932 38955 : pari_sp av = avma;
3933 38955 : long rel = 1;
3934 : GEN z, h;
3935 38955 : h = addis(C,a);
3936 38925 : if ((z = Z_issmooth_fact(h, prmax)))
3937 : {
3938 2414 : gel(L, rel++) = mkvec2(z, mkvecsmall3(1, a, -1));
3939 2413 : av = avma;
3940 : }
3941 16671116 : for(i=1; i<=n; i++)
3942 : {
3943 16632161 : ulong li = pi[i], s = sz[i], al = a % li;
3944 16632161 : ulong u, iv = Fl_invsafe(Fl_add(Ci[i],al,li),li);
3945 17031847 : if (!iv) continue;
3946 16600322 : u = Fl_mul(Fl_sub(ci[i],Fl_mul(Ci[i],al,li),li), iv ,li);
3947 76286030 : for(j = u; j<=a; j+=li)
3948 60104474 : sieve[j] += s;
3949 : }
3950 38955 : th = th - expu(th)-1;
3951 27866351 : for(j=0; j<a; j++)
3952 27827321 : if (sieve[j]>=th)
3953 : {
3954 111462 : GEN h = addiu(subii(muliu(C,a+j),c), a*j);
3955 111431 : if ((z = Z_issmooth_fact(h, prmax)))
3956 : {
3957 104664 : gel(L, rel++) = mkvec2(z, mkvecsmall3(2, a, j));
3958 104884 : av = avma;
3959 6631 : } else set_avma(av);
3960 : }
3961 : /* j = a */
3962 39030 : if (sieve[a]>=th)
3963 : {
3964 420 : GEN h = addiu(subii(muliu(C,2*a),c), a*a);
3965 420 : if ((z = Z_issmooth_fact(h, prmax)))
3966 : {
3967 343 : gel(L, rel++) = mkvec2(z, mkvecsmall3(1, a, -2));
3968 343 : av = avma;
3969 : }
3970 : }
3971 39030 : setlg(L, rel);
3972 39030 : return gerepilecopy(ltop, L);
3973 : }
3974 :
3975 : static long
3976 49 : Fp_log_sieve(struct Fp_log_rel *r, GEN C, GEN c, GEN Ci, GEN ci, GEN pi, GEN sz)
3977 : {
3978 : struct pari_mt pt;
3979 49 : long i, j, nb = 0;
3980 49 : GEN worker = snm_closure(is_entry("_Fp_log_sieve_worker"),
3981 : mkvecn(7, utoi(r->prmax), C, c, Ci, ci, pi, sz));
3982 49 : long running, pending = 0;
3983 49 : GEN W = zerovec(r->nbgen);
3984 49 : mt_queue_start_lim(&pt, worker, r->nbgen);
3985 39305 : for (i = 0; (running = (i < r->nbgen)) || pending; i++)
3986 : {
3987 : GEN done;
3988 : long idx;
3989 39256 : mt_queue_submit(&pt, i, running ? mkvec(stoi(i)): NULL);
3990 39256 : done = mt_queue_get(&pt, &idx, &pending);
3991 39256 : if (!done || lg(done)==1) continue;
3992 34146 : gel(W, idx+1) = done;
3993 34146 : nb += lg(done)-1;
3994 34146 : if (DEBUGLEVEL && (i&127)==0)
3995 0 : err_printf("%ld%% ",100*nb/r->nbmax);
3996 : }
3997 49 : mt_queue_end(&pt);
3998 37870 : for(j = 1; j <= r->nbgen && r->nbrel < r->nbmax; j++)
3999 : {
4000 : long ll, m;
4001 37821 : GEN L = gel(W,j);
4002 37821 : if (isintzero(L)) continue;
4003 32942 : ll = lg(L);
4004 135394 : for (m=1; m<ll && r->nbrel < r->nbmax ; m++)
4005 : {
4006 102452 : GEN Lm = gel(L,m), h = gel(Lm, 1), v = gel(Lm, 2);
4007 102452 : if (v[1] == 1)
4008 2583 : addifsmooth1(r, h, v[2], v[3]);
4009 : else
4010 99869 : addifsmooth2(r, h, v[2], v[3]);
4011 : }
4012 : }
4013 49 : return j;
4014 : }
4015 :
4016 : static GEN
4017 525 : ECP_psi(GEN x, GEN y)
4018 : {
4019 525 : long prec = realprec(x);
4020 525 : GEN lx = glog(x, prec), ly = glog(y, prec);
4021 525 : GEN u = gdiv(lx, ly);
4022 525 : return gpow(u, gneg(u),prec);
4023 : }
4024 :
4025 : struct computeG
4026 : {
4027 : GEN C;
4028 : long bnd, nbi;
4029 : };
4030 :
4031 : static GEN
4032 525 : _computeG(void *E, GEN gen)
4033 : {
4034 525 : struct computeG * d = (struct computeG *) E;
4035 525 : GEN ps = ECP_psi(gmul(gen,d->C), stoi(d->bnd));
4036 525 : return gsub(gmul(gsqr(gen),ps),gmul2n(gaddgs(gen,d->nbi),2));
4037 : }
4038 :
4039 : static long
4040 49 : compute_nbgen(GEN C, long bnd, long nbi)
4041 : {
4042 : struct computeG d;
4043 49 : d.C = shifti(C, 1);
4044 49 : d.bnd = bnd;
4045 49 : d.nbi = nbi;
4046 49 : return itos(ground(zbrent((void*)&d, _computeG, gen_2, stoi(bnd), DEFAULTPREC)));
4047 : }
4048 :
4049 : static GEN
4050 1367 : _psi(void*E, GEN y)
4051 : {
4052 1367 : GEN lx = (GEN) E;
4053 1367 : long prec = realprec(lx);
4054 1367 : GEN ly = glog(y, prec);
4055 1367 : GEN u = gdiv(lx, ly);
4056 1367 : return gsub(gdiv(y ,ly), gpow(u, u, prec));
4057 : }
4058 :
4059 : static GEN
4060 49 : opt_param(GEN x, long prec)
4061 : {
4062 49 : return zbrent((void*)glog(x,prec), _psi, gen_2, x, prec);
4063 : }
4064 :
4065 : static GEN
4066 49 : check_kernel(long nbg, long N, long prmax, GEN C, GEN M, GEN p, GEN m)
4067 : {
4068 49 : pari_sp av = avma;
4069 49 : long lM = lg(M)-1, nbcol = lM;
4070 49 : long tbs = maxss(1, expu(nbg/expi(m)));
4071 : for (;;)
4072 35 : {
4073 84 : GEN K = FpMs_leftkernel_elt_col(M, nbcol, N, m);
4074 : GEN tab;
4075 84 : long i, f=0;
4076 84 : long l = lg(K), lm = lgefint(m);
4077 84 : GEN idx = diviiexact(subiu(p,1),m), g;
4078 : pari_timer ti;
4079 84 : if (DEBUGLEVEL) timer_start(&ti);
4080 140 : for(i=1; i<l; i++)
4081 140 : if (signe(gel(K,i)))
4082 84 : break;
4083 84 : g = Fp_pow(utoi(i), idx, p);
4084 84 : tab = Fp_pow_init(g, p, tbs, p);
4085 84 : K = FpC_Fp_mul(K, Fp_inv(gel(K,i), m), m);
4086 130438 : for(i=1; i<l; i++)
4087 : {
4088 130354 : GEN k = gel(K,i);
4089 130354 : GEN j = i<=prmax ? utoi(i): addis(C,i-(prmax+1));
4090 130354 : if (signe(k)==0 || !equalii(Fp_pow_table(tab, k, p), Fp_pow(j, idx, p)))
4091 80542 : gel(K,i) = cgetineg(lm);
4092 : else
4093 49812 : f++;
4094 : }
4095 84 : if (DEBUGLEVEL) timer_printf(&ti,"found %ld/%ld logs", f, nbg);
4096 133 : if(f > (nbg>>1)) return gerepileupto(av, K);
4097 9877 : for(i=1; i<=nbcol; i++)
4098 : {
4099 9842 : long a = 1+random_Fl(lM);
4100 9842 : swap(gel(M,a),gel(M,i));
4101 : }
4102 35 : if (4*nbcol>5*nbg) nbcol = nbcol*9/10;
4103 : }
4104 : }
4105 :
4106 : static GEN
4107 98 : Fp_log_find_ind(GEN a, GEN K, long prmax, GEN C, GEN p, GEN m)
4108 : {
4109 98 : pari_sp av=avma;
4110 98 : GEN aa = gen_1;
4111 98 : long AV = 0;
4112 : for(;;)
4113 163 : {
4114 261 : GEN A = Fp_log_find_rel(a, prmax, C, p, &aa, &AV);
4115 261 : GEN F = gel(A,1), E = gel(A,2);
4116 261 : GEN Ao = gen_0;
4117 261 : long i, l = lg(F);
4118 1422 : for(i=1; i<l; i++)
4119 : {
4120 1324 : GEN Ki = gel(K,F[i]);
4121 1324 : if (signe(Ki)<0) break;
4122 1161 : Ao = addii(Ao, mulis(Ki, E[i]));
4123 : }
4124 359 : if (i==l) return Fp_divu(Ao, AV, m);
4125 163 : aa = gerepileuptoint(av, aa);
4126 : }
4127 : }
4128 :
4129 : static GEN
4130 49 : Fp_log_index(GEN a, GEN b, GEN m, GEN p)
4131 : {
4132 49 : pari_sp av = avma, av2;
4133 49 : long i, j, nbi, nbr = 0, nbrow, nbg;
4134 : GEN C, c, Ci, ci, pi, pr, sz, l, Ao, Bo, K, d, p_1;
4135 : pari_timer ti;
4136 : struct Fp_log_rel r;
4137 49 : ulong bnds = itou(roundr_safe(opt_param(sqrti(p),DEFAULTPREC)));
4138 49 : ulong bnd = 4*bnds;
4139 49 : if (!bnds || cmpii(sqru(bnds),m)>=0) return NULL;
4140 :
4141 49 : p_1 = subiu(p,1);
4142 49 : if (!is_pm1(gcdii(m,diviiexact(p_1,m))))
4143 0 : m = diviiexact(p_1, Z_ppo(p_1, m));
4144 49 : pr = primes_upto_zv(bnd);
4145 49 : nbi = lg(pr)-1;
4146 49 : C = sqrtremi(p, &c);
4147 49 : av2 = avma;
4148 12236 : for (i = 1; i <= nbi; ++i)
4149 : {
4150 12187 : ulong lp = pr[i];
4151 37793 : while (lp <= bnd)
4152 : {
4153 13419 : nbr++;
4154 13419 : lp *= pr[i];
4155 : }
4156 : }
4157 49 : pi = cgetg(nbr+1,t_VECSMALL);
4158 49 : Ci = cgetg(nbr+1,t_VECSMALL);
4159 49 : ci = cgetg(nbr+1,t_VECSMALL);
4160 49 : sz = cgetg(nbr+1,t_VECSMALL);
4161 12236 : for (i = 1, j = 1; i <= nbi; ++i)
4162 : {
4163 12187 : ulong lp = pr[i], sp = expu(2*lp-1);
4164 37793 : while (lp <= bnd)
4165 : {
4166 13419 : pi[j] = lp;
4167 13419 : Ci[j] = umodiu(C, lp);
4168 13419 : ci[j] = umodiu(c, lp);
4169 13419 : sz[j] = sp;
4170 13419 : lp *= pr[i];
4171 13419 : j++;
4172 : }
4173 : }
4174 49 : r.nbrel = 0;
4175 49 : r.nbgen = compute_nbgen(C, bnd, nbi);
4176 49 : r.nbmax = 2*(nbi+r.nbgen);
4177 49 : r.rel = cgetg(r.nbmax+1,t_VEC);
4178 49 : r.prmax = pr[nbi];
4179 49 : if (DEBUGLEVEL)
4180 : {
4181 0 : err_printf("bnd=%lu Size FB=%ld extra gen=%ld \n", bnd, nbi, r.nbgen);
4182 0 : timer_start(&ti);
4183 : }
4184 49 : nbg = Fp_log_sieve(&r, C, c, Ci, ci, pi, sz);
4185 49 : nbrow = r.prmax + nbg;
4186 49 : if (DEBUGLEVEL)
4187 : {
4188 0 : err_printf("\n");
4189 0 : timer_printf(&ti," %ld relations, %ld generators", r.nbrel, nbi+nbg);
4190 : }
4191 49 : setlg(r.rel,r.nbrel+1);
4192 49 : r.rel = gerepilecopy(av2, r.rel);
4193 49 : K = check_kernel(nbi+nbrow-r.prmax, nbrow, r.prmax, C, r.rel, p, m);
4194 49 : if (DEBUGLEVEL) timer_start(&ti);
4195 49 : Ao = Fp_log_find_ind(a, K, r.prmax, C, p, m);
4196 49 : if (DEBUGLEVEL) timer_printf(&ti," log element");
4197 49 : Bo = Fp_log_find_ind(b, K, r.prmax, C, p, m);
4198 49 : if (DEBUGLEVEL) timer_printf(&ti," log generator");
4199 49 : d = gcdii(Ao,Bo);
4200 49 : l = Fp_div(diviiexact(Ao, d) ,diviiexact(Bo, d), m);
4201 49 : if (!equalii(a,Fp_pow(b,l,p))) pari_err_BUG("Fp_log_index");
4202 49 : return gerepileuptoint(av, l);
4203 : }
4204 :
4205 : static int
4206 1478346 : Fp_log_use_index(long e, long p)
4207 : {
4208 1478346 : return (e >= 27 && 20*(p+6)<=e*e);
4209 : }
4210 :
4211 : /* Trivial cases a = 1, -1. Return x s.t. g^x = a or [] if no such x exist */
4212 : static GEN
4213 2206590 : Fp_easylog(void *E, GEN a, GEN g, GEN ord)
4214 : {
4215 2206590 : pari_sp av = avma;
4216 2206590 : GEN p = (GEN)E;
4217 : /* assume a reduced mod p, p not necessarily prime */
4218 2206590 : if (equali1(a)) return gen_0;
4219 : /* p > 2 */
4220 1426029 : if (equalii(subiu(p,1), a)) /* -1 */
4221 : {
4222 : pari_sp av2;
4223 : GEN t;
4224 422444 : ord = get_arith_Z(ord);
4225 422444 : if (mpodd(ord)) { set_avma(av); return cgetg(1, t_VEC); } /* no solution */
4226 422430 : t = shifti(ord,-1); /* only possible solution */
4227 422430 : av2 = avma;
4228 422430 : if (!equalii(Fp_pow(g, t, p), a)) { set_avma(av); return cgetg(1, t_VEC); }
4229 422402 : set_avma(av2); return gerepileuptoint(av, t);
4230 : }
4231 1003585 : if (typ(ord)==t_INT && BPSW_psp(p) && Fp_log_use_index(expi(ord),expi(p)))
4232 49 : return Fp_log_index(a, g, ord, p);
4233 1003536 : return gc_NULL(av); /* not easy */
4234 : }
4235 :
4236 : GEN
4237 1179181 : Fp_log(GEN a, GEN g, GEN ord, GEN p)
4238 : {
4239 1179181 : GEN v = get_arith_ZZM(ord);
4240 1179153 : GEN F = gmael(v,2,1);
4241 1179153 : long lF = lg(F)-1, lmax;
4242 1179153 : if (lF == 0) return equali1(a)? gen_0: cgetg(1, t_VEC);
4243 1081895 : lmax = expi(gel(F,lF));
4244 1081895 : if (BPSW_psp(p) && Fp_log_use_index(lmax,expi(p)))
4245 56 : v = mkvec2(gel(v,1),ZM_famat_limit(gel(v,2),int2n(27)));
4246 1081895 : return gen_PH_log(a,g,v,(void*)p,&Fp_star);
4247 : }
4248 :
4249 : static ulong
4250 16156 : Fl_log_naive(ulong a, ulong g, ulong ord, ulong p)
4251 : {
4252 16156 : ulong i, h=1;
4253 38319 : for(i=0; i<ord; i++, h = Fl_mul(h, g, p))
4254 38319 : if(a==h) return i;
4255 0 : return ~0UL;
4256 : }
4257 :
4258 : static ulong
4259 18938 : Fl_log_naive_pre(ulong a, ulong g, ulong ord, ulong p, ulong pi)
4260 : {
4261 18938 : ulong i, h=1;
4262 47766 : for(i=0; i<ord; i++, h = Fl_mul_pre(h, g, p, pi))
4263 47766 : if(a==h) return i;
4264 0 : return ~0UL;
4265 : }
4266 :
4267 : static ulong
4268 0 : Fl_log_Fp(ulong a, ulong g, ulong ord, ulong p)
4269 : {
4270 0 : pari_sp av = avma;
4271 0 : GEN r = Fp_log(utoi(a),utoi(g),utoi(ord),utoi(p));
4272 0 : return gc_ulong(av, typ(r)==t_INT ? itou(r): ~0UL);
4273 : }
4274 :
4275 : ulong
4276 18938 : Fl_log_pre(ulong a, ulong g, ulong ord, ulong p, ulong pi)
4277 : {
4278 18938 : if (ord <= 200) return Fl_log_naive_pre(a, g, ord, p, pi);
4279 0 : return Fl_log_Fp(a, g, ord, p);
4280 : }
4281 :
4282 : ulong
4283 16156 : Fl_log(ulong a, ulong g, ulong ord, ulong p)
4284 : {
4285 16156 : if (ord <= 200)
4286 16156 : return (p&HIGHMASK) ? Fl_log_naive_pre(a, g, ord, p, get_Fl_red(p))
4287 16156 : : Fl_log_naive(a, g, ord, p);
4288 0 : return Fl_log_Fp(a, g, ord, p);
4289 : }
4290 :
4291 : /* find x such that h = g^x mod N > 1, N = prod_{i <= l} P[i]^E[i], P[i] prime.
4292 : * PHI[l] = eulerphi(N / P[l]^E[l]). Destroys P/E */
4293 : static GEN
4294 112 : znlog_rec(GEN h, GEN g, GEN N, GEN P, GEN E, GEN PHI)
4295 : {
4296 112 : long l = lg(P) - 1, e = E[l];
4297 112 : GEN p = gel(P, l), phi = gel(PHI,l), pe = e == 1? p: powiu(p, e);
4298 : GEN a,b, hp,gp, hpe,gpe, ogpe; /* = order(g mod p^e) | p^(e-1)(p-1) */
4299 :
4300 112 : if (l == 1) {
4301 84 : hpe = h;
4302 84 : gpe = g;
4303 : } else {
4304 28 : hpe = modii(h, pe);
4305 28 : gpe = modii(g, pe);
4306 : }
4307 112 : if (e == 1) {
4308 28 : hp = hpe;
4309 28 : gp = gpe;
4310 : } else {
4311 84 : hp = remii(hpe, p);
4312 84 : gp = remii(gpe, p);
4313 : }
4314 112 : if (hp == gen_0 || gp == gen_0) return NULL;
4315 91 : if (absequaliu(p, 2))
4316 : {
4317 35 : GEN n = int2n(e);
4318 35 : ogpe = Zp_order(gpe, gen_2, e, n);
4319 35 : a = Fp_log(hpe, gpe, ogpe, n);
4320 35 : if (typ(a) != t_INT) return NULL;
4321 : }
4322 : else
4323 : { /* Avoid black box groups: (Z/p^2)^* / (Z/p)^* ~ (Z/pZ, +), where DL
4324 : is trivial */
4325 : /* [order(gp), factor(order(gp))] */
4326 56 : GEN v = Fp_factored_order(gp, subiu(p,1), p);
4327 56 : GEN ogp = gel(v,1);
4328 56 : if (!equali1(Fp_pow(hp, ogp, p))) return NULL;
4329 56 : a = Fp_log(hp, gp, v, p);
4330 56 : if (typ(a) != t_INT) return NULL;
4331 56 : if (e == 1) ogpe = ogp;
4332 : else
4333 : { /* find a s.t. g^a = h (mod p^e), p odd prime, e > 0, (h,p) = 1 */
4334 : /* use p-adic log: O(log p + e) mul*/
4335 : long vpogpe, vpohpe;
4336 :
4337 28 : hpe = Fp_mul(hpe, Fp_pow(gpe, negi(a), pe), pe);
4338 28 : gpe = Fp_pow(gpe, ogp, pe);
4339 : /* g,h = 1 mod p; compute b s.t. h = g^b */
4340 :
4341 : /* v_p(order g mod pe) */
4342 28 : vpogpe = equali1(gpe)? 0: e - Z_pval(subiu(gpe,1), p);
4343 : /* v_p(order h mod pe) */
4344 28 : vpohpe = equali1(hpe)? 0: e - Z_pval(subiu(hpe,1), p);
4345 28 : if (vpohpe > vpogpe) return NULL;
4346 :
4347 28 : ogpe = mulii(ogp, powiu(p, vpogpe)); /* order g mod p^e */
4348 28 : if (is_pm1(gpe)) return is_pm1(hpe)? a: NULL;
4349 28 : b = gdiv(Qp_log(cvtop(hpe, p, e)), Qp_log(cvtop(gpe, p, e)));
4350 28 : a = addii(a, mulii(ogp, padic_to_Q(b)));
4351 : }
4352 : }
4353 : /* gp^a = hp => x = a mod ogpe => generalized Pohlig-Hellman strategy */
4354 77 : if (l == 1) return a;
4355 :
4356 28 : N = diviiexact(N, pe); /* make N coprime to p */
4357 28 : h = Fp_mul(h, Fp_pow(g, modii(negi(a), phi), N), N);
4358 28 : g = Fp_pow(g, modii(ogpe, phi), N);
4359 28 : setlg(P, l); /* remove last element */
4360 28 : setlg(E, l);
4361 28 : b = znlog_rec(h, g, N, P, E, PHI);
4362 28 : if (!b) return NULL;
4363 28 : return addmulii(a, b, ogpe);
4364 : }
4365 :
4366 : static GEN
4367 84 : get_PHI(GEN P, GEN E)
4368 : {
4369 84 : long i, l = lg(P);
4370 84 : GEN PHI = cgetg(l, t_VEC);
4371 84 : gel(PHI,1) = gen_1;
4372 112 : for (i=1; i<l-1; i++)
4373 : {
4374 28 : GEN t, p = gel(P,i);
4375 28 : long e = E[i];
4376 28 : t = mulii(powiu(p, e-1), subiu(p,1));
4377 28 : if (i > 1) t = mulii(t, gel(PHI,i));
4378 28 : gel(PHI,i+1) = t;
4379 : }
4380 84 : return PHI;
4381 : }
4382 :
4383 : GEN
4384 224 : znlog(GEN h, GEN g, GEN o)
4385 : {
4386 224 : pari_sp av = avma;
4387 : GEN N, fa, P, E, x;
4388 224 : switch (typ(g))
4389 : {
4390 : case t_PADIC:
4391 : {
4392 28 : GEN p = gel(g,2);
4393 28 : long v = valp(g);
4394 28 : if (v < 0) pari_err_DIM("znlog");
4395 28 : if (v > 0) {
4396 0 : long k = gvaluation(h, p);
4397 0 : if (k % v) return cgetg(1,t_VEC);
4398 0 : k /= v;
4399 0 : if (!gequal(h, gpowgs(g,k))) { set_avma(av); return cgetg(1,t_VEC); }
4400 0 : set_avma(av); return stoi(k);
4401 : }
4402 28 : N = gel(g,3);
4403 28 : g = Rg_to_Fp(g, N);
4404 28 : break;
4405 : }
4406 : case t_INTMOD:
4407 189 : N = gel(g,1);
4408 189 : g = gel(g,2); break;
4409 7 : default: pari_err_TYPE("znlog", g);
4410 : return NULL; /* LCOV_EXCL_LINE */
4411 : }
4412 217 : if (equali1(N)) { set_avma(av); return gen_0; }
4413 217 : h = Rg_to_Fp(h, N);
4414 210 : if (o) return gerepileupto(av, Fp_log(h, g, o, N));
4415 84 : fa = Z_factor(N);
4416 84 : P = gel(fa,1);
4417 84 : E = vec_to_vecsmall(gel(fa,2));
4418 84 : x = znlog_rec(h, g, N, P, E, get_PHI(P,E));
4419 84 : if (!x) { set_avma(av); return cgetg(1,t_VEC); }
4420 49 : return gerepileuptoint(av, x);
4421 : }
4422 :
4423 : GEN
4424 61593 : Fp_sqrtn(GEN a, GEN n, GEN p, GEN *zeta)
4425 : {
4426 61593 : if (lgefint(p)==3)
4427 : {
4428 61201 : long nn = itos_or_0(n);
4429 61201 : if (nn)
4430 : {
4431 61201 : ulong pp = p[2];
4432 : ulong uz;
4433 61201 : ulong r = Fl_sqrtn(umodiu(a,pp),nn,pp, zeta ? &uz:NULL);
4434 61180 : if (r==ULONG_MAX) return NULL;
4435 61131 : if (zeta) *zeta = utoi(uz);
4436 61131 : return utoi(r);
4437 : }
4438 : }
4439 392 : a = modii(a,p);
4440 392 : if (!signe(a))
4441 : {
4442 0 : if (zeta) *zeta = gen_1;
4443 0 : if (signe(n) < 0) pari_err_INV("Fp_sqrtn", mkintmod(gen_0,p));
4444 0 : return gen_0;
4445 : }
4446 392 : if (absequaliu(n,2))
4447 : {
4448 224 : if (zeta) *zeta = subiu(p,1);
4449 224 : return signe(n) > 0 ? Fp_sqrt(a,p): Fp_sqrt(Fp_inv(a, p),p);
4450 : }
4451 168 : return gen_Shanks_sqrtn(a,n,subiu(p,1),zeta,(void*)p,&Fp_star);
4452 : }
4453 :
4454 : /*********************************************************************/
4455 : /** **/
4456 : /** FUNDAMENTAL DISCRIMINANTS **/
4457 : /** **/
4458 : /*********************************************************************/
4459 : static long
4460 1407 : fa_isfundamental(GEN F)
4461 : {
4462 1407 : GEN P = gel(F,1), E = gel(F,2);
4463 1407 : long i, s, l = lg(P);
4464 :
4465 1407 : if (l == 1) return 1;
4466 1400 : s = signe(gel(P,1)); /* = signe(x) */
4467 1400 : if (!s) return 0;
4468 1393 : if (s < 0) { l--; P = vecslice(P,2,l); E = vecslice(E,2,l); }
4469 1393 : if (l == 1) return 0;
4470 1386 : if (!absequaliu(gel(P,1), 2))
4471 686 : i = 1; /* need x = 1 mod 4 */
4472 : else
4473 : {
4474 700 : i = 2;
4475 700 : switch(itou(gel(E,1)))
4476 : {
4477 182 : case 2: s = -s; break; /* need x/4 = 3 mod 4 */
4478 84 : case 3: s = 0; break; /* no condition mod 4 */
4479 434 : default: return 0;
4480 : }
4481 : }
4482 1974 : for(; i < l; i++)
4483 : {
4484 1190 : if (!equali1(gel(E,i))) return 0;
4485 1022 : if (s && Mod4(gel(P,i)) == 3) s = -s;
4486 : }
4487 784 : return s >= 0;
4488 : }
4489 : long
4490 20412 : isfundamental(GEN x)
4491 : {
4492 20412 : if (typ(x) != t_INT)
4493 : {
4494 1407 : pari_sp av = avma;
4495 1407 : long v = fa_isfundamental(check_arith_all(x,"isfundamental"));
4496 1407 : return gc_long(av,v);
4497 : }
4498 19005 : return Z_isfundamental(x);
4499 : }
4500 :
4501 : /* x fundamental ? */
4502 : long
4503 16547 : uposisfundamental(ulong x)
4504 : {
4505 16547 : ulong r = x & 15; /* x mod 16 */
4506 16547 : if (!r) return 0;
4507 15770 : switch(r & 3)
4508 : { /* x mod 4 */
4509 3417 : case 0: return (r == 4)? 0: uissquarefree(x >> 2);
4510 5909 : case 1: return uissquarefree(x);
4511 6444 : default: return 0;
4512 : }
4513 : }
4514 : /* -x fundamental ? */
4515 : long
4516 32600 : unegisfundamental(ulong x)
4517 : {
4518 32600 : ulong r = x & 15; /* x mod 16 */
4519 32600 : if (!r) return 0;
4520 31004 : switch(r & 3)
4521 : { /* x mod 4 */
4522 7169 : case 0: return (r == 12)? 0: uissquarefree(x >> 2);
4523 13513 : case 3: return uissquarefree(x);
4524 10322 : default: return 0;
4525 : }
4526 : }
4527 : long
4528 24857 : sisfundamental(long x)
4529 24857 : { return x < 0? unegisfundamental((ulong)(-x)): uposisfundamental(x); }
4530 :
4531 : long
4532 19572 : Z_isfundamental(GEN x)
4533 : {
4534 : long r;
4535 19572 : switch(lgefint(x))
4536 : {
4537 7 : case 2: return 0;
4538 26767 : case 3: return signe(x) < 0? unegisfundamental(x[2])
4539 26767 : : uposisfundamental(x[2]);
4540 : }
4541 2010 : r = mod16(x);
4542 2010 : if (!r) return 0;
4543 1884 : if ((r & 3) == 0)
4544 : {
4545 : pari_sp av;
4546 376 : r >>= 2; /* |x|/4 mod 4 */
4547 376 : if (signe(x) < 0) r = 4-r;
4548 376 : if (r == 1) return 0;
4549 250 : av = avma;
4550 250 : r = Z_issquarefree( shifti(x,-2) );
4551 250 : return gc_long(av, r);
4552 : }
4553 1508 : r &= 3; /* |x| mod 4 */
4554 1508 : if (signe(x) < 0) r = 4-r;
4555 1508 : return (r==1) ? Z_issquarefree(x) : 0;
4556 : }
4557 :
4558 : static GEN
4559 2821 : fa_quaddisc(GEN f)
4560 : {
4561 2821 : GEN P = gel(f,1), E = gel(f,2), s = gen_1;
4562 2821 : long i, l = lg(P);
4563 9051 : for (i = 1; i < l; i++) /* possibly including -1 */
4564 6230 : if (mpodd(gel(E,i))) s = mulii(s, gel(P,i));
4565 2821 : if (Mod4(s) > 1) s = shifti(s,2);
4566 2821 : return s;
4567 : }
4568 :
4569 : GEN
4570 2821 : quaddisc(GEN x)
4571 : {
4572 2821 : const pari_sp av = avma;
4573 2821 : if (is_rational_t(typ(x))) x = factor(x);
4574 1407 : else x = check_arith_all(x,"quaddisc");
4575 2821 : return gerepileuptoint(av, fa_quaddisc(x));
4576 : }
4577 :
4578 : /*********************************************************************/
4579 : /** **/
4580 : /** FACTORIAL **/
4581 : /** **/
4582 : /*********************************************************************/
4583 : GEN
4584 206410 : mulu_interval_step(ulong a, ulong b, ulong step)
4585 : {
4586 206410 : pari_sp av = avma;
4587 : ulong k, l, N, n;
4588 : long lx;
4589 : GEN x;
4590 :
4591 206410 : if (!a) return gen_0;
4592 206410 : if (step == 1) return mulu_interval(a, b);
4593 206410 : n = 1 + (b-a) / step;
4594 206410 : b -= (b-a) % step;
4595 206410 : if (n < 61)
4596 : {
4597 205583 : if (n == 1) return utoipos(a);
4598 152598 : x = muluu(a,a+step); if (n == 2) return x;
4599 111450 : for (k=a+2*step; k<=b; k+=step) x = mului(k,x);
4600 111450 : return gerepileuptoint(av, x);
4601 : }
4602 : /* step | b-a */
4603 827 : lx = 1; x = cgetg(2 + n/2, t_VEC);
4604 827 : N = b + a;
4605 205962 : for (k = a;; k += step)
4606 : {
4607 411097 : l = N - k; if (l <= k) break;
4608 205135 : gel(x,lx++) = muluu(k,l);
4609 : }
4610 827 : if (l == k) gel(x,lx++) = utoipos(k);
4611 827 : setlg(x, lx);
4612 827 : return gerepileuptoint(av, ZV_prod(x));
4613 : }
4614 : /* return a * (a+1) * ... * b. Assume a <= b [ note: factoring out powers of 2
4615 : * first is slower ... ] */
4616 : GEN
4617 152733 : mulu_interval(ulong a, ulong b)
4618 : {
4619 152733 : pari_sp av = avma;
4620 : ulong k, l, N, n;
4621 : long lx;
4622 : GEN x;
4623 :
4624 152733 : if (!a) return gen_0;
4625 152733 : n = b - a + 1;
4626 152733 : if (n < 61)
4627 : {
4628 152719 : if (n == 1) return utoipos(a);
4629 98441 : x = muluu(a,a+1); if (n == 2) return x;
4630 69055 : for (k=a+2; k<=b; k++) x = mului(k,x);
4631 69055 : return gerepileuptoint(av, x);
4632 : }
4633 14 : lx = 1; x = cgetg(2 + n/2, t_VEC);
4634 14 : N = b + a;
4635 7007 : for (k = a;; k++)
4636 : {
4637 14000 : l = N - k; if (l <= k) break;
4638 6993 : gel(x,lx++) = muluu(k,l);
4639 : }
4640 14 : if (l == k) gel(x,lx++) = utoipos(k);
4641 14 : setlg(x, lx);
4642 14 : return gerepileuptoint(av, ZV_prod(x));
4643 : }
4644 : GEN
4645 476 : muls_interval(long a, long b)
4646 : {
4647 476 : pari_sp av = avma;
4648 476 : long lx, k, l, N, n = b - a + 1;
4649 : GEN x;
4650 :
4651 476 : if (a <= 0 && b >= 0) return gen_0;
4652 259 : if (n < 61)
4653 : {
4654 259 : x = stoi(a);
4655 259 : for (k=a+1; k<=b; k++) x = mulsi(k,x);
4656 259 : return gerepileuptoint(av, x);
4657 : }
4658 0 : lx = 1; x = cgetg(2 + n/2, t_VEC);
4659 0 : N = b + a;
4660 0 : for (k = a;; k++)
4661 : {
4662 0 : l = N - k; if (l <= k) break;
4663 0 : gel(x,lx++) = mulss(k,l);
4664 : }
4665 0 : if (l == k) gel(x,lx++) = stoi(k);
4666 0 : setlg(x, lx);
4667 0 : return gerepileuptoint(av, ZV_prod(x));
4668 : }
4669 :
4670 : GEN
4671 261634 : mpfact(long n)
4672 : {
4673 261634 : pari_sp av = avma;
4674 : GEN a, v;
4675 : long k;
4676 261634 : if (n <= 12) switch(n)
4677 : {
4678 120292 : case 0: case 1: return gen_1;
4679 41271 : case 2: return gen_2;
4680 1039 : case 3: return utoipos(6);
4681 10116 : case 4: return utoipos(24);
4682 751 : case 5: return utoipos(120);
4683 9136 : case 6: return utoipos(720);
4684 346 : case 7: return utoipos(5040);
4685 9045 : case 8: return utoipos(40320);
4686 351 : case 9: return utoipos(362880);
4687 9325 : case 10:return utoipos(3628800);
4688 223 : case 11:return utoipos(39916800);
4689 7144 : case 12:return utoipos(479001600);
4690 0 : default: pari_err_DOMAIN("factorial", "argument","<",gen_0,stoi(n));
4691 : }
4692 52595 : v = cgetg(expu(n) + 2, t_VEC);
4693 255429 : for (k = 1;; k++)
4694 202833 : {
4695 255429 : long m = n >> (k-1), l;
4696 255429 : if (m <= 2) break;
4697 202833 : l = (1 + (n >> k)) | 1;
4698 : /* product of odd numbers in ]n / 2^k, 2 / 2^(k-1)] */
4699 202833 : a = mulu_interval_step(l, m, 2);
4700 202833 : gel(v,k) = k == 1? a: powiu(a, k);
4701 : }
4702 52596 : a = gel(v,--k); while (--k) a = mulii(a, gel(v,k));
4703 52596 : a = shifti(a, factorial_lval(n, 2));
4704 52596 : return gerepileuptoint(av, a);
4705 : }
4706 :
4707 : ulong
4708 4739 : factorial_Fl(long n, ulong p)
4709 : {
4710 : long k;
4711 : ulong v;
4712 4739 : if (p <= (ulong)n) return 0;
4713 4739 : v = Fl_powu(2, factorial_lval(n, 2), p);
4714 16929 : for (k = 1;; k++)
4715 12191 : {
4716 16929 : long m = n >> (k-1), l, i;
4717 16929 : ulong a = 1;
4718 16929 : if (m <= 2) break;
4719 12191 : l = (1 + (n >> k)) | 1;
4720 : /* product of odd numbers in ]n / 2^k, 2 / 2^(k-1)] */
4721 82445 : for (i=l; i<=m; i+=2)
4722 70254 : a = Fl_mul(a, i, p);
4723 12191 : v = Fl_mul(v, k == 1? a: Fl_powu(a, k, p), p);
4724 : }
4725 4738 : return v;
4726 : }
4727 :
4728 : GEN
4729 60 : factorial_Fp(long n, GEN p)
4730 : {
4731 60 : pari_sp av = avma;
4732 : long k;
4733 60 : GEN v = Fp_powu(gen_2, factorial_lval(n, 2), p);
4734 194 : for (k = 1;; k++)
4735 134 : {
4736 194 : long m = n >> (k-1), l, i;
4737 194 : GEN a = gen_1;
4738 194 : if (m <= 2) break;
4739 134 : l = (1 + (n >> k)) | 1;
4740 : /* product of odd numbers in ]n / 2^k, 2 / 2^(k-1)] */
4741 402 : for (i=l; i<=m; i+=2)
4742 268 : a = Fp_mulu(a, i, p);
4743 134 : v = Fp_mul(v, k == 1? a: Fp_powu(a, k, p), p);
4744 134 : v = gerepileuptoint(av, v);
4745 : }
4746 60 : return v;
4747 : }
4748 :
4749 : /*******************************************************************/
4750 : /** **/
4751 : /** LUCAS & FIBONACCI **/
4752 : /** **/
4753 : /*******************************************************************/
4754 : static void
4755 56 : lucas(ulong n, GEN *a, GEN *b)
4756 : {
4757 : GEN z, t, zt;
4758 56 : if (!n) { *a = gen_2; *b = gen_1; return; }
4759 49 : lucas(n >> 1, &z, &t); zt = mulii(z, t);
4760 49 : switch(n & 3) {
4761 14 : case 0: *a = subiu(sqri(z),2); *b = subiu(zt,1); break;
4762 14 : case 1: *a = subiu(zt,1); *b = addiu(sqri(t),2); break;
4763 7 : case 2: *a = addiu(sqri(z),2); *b = addiu(zt,1); break;
4764 14 : case 3: *a = addiu(zt,1); *b = subiu(sqri(t),2);
4765 : }
4766 : }
4767 :
4768 : GEN
4769 7 : fibo(long n)
4770 : {
4771 7 : pari_sp av = avma;
4772 : GEN a, b;
4773 7 : if (!n) return gen_0;
4774 7 : lucas((ulong)(labs(n)-1), &a, &b);
4775 7 : a = diviuexact(addii(shifti(a,1),b), 5);
4776 7 : if (n < 0 && !odd(n)) setsigne(a, -1);
4777 7 : return gerepileuptoint(av, a);
4778 : }
4779 :
4780 : /*******************************************************************/
4781 : /* */
4782 : /* CONTINUED FRACTIONS */
4783 : /* */
4784 : /*******************************************************************/
4785 : static GEN
4786 2830683 : icopy_lg(GEN x, long l)
4787 : {
4788 2830683 : long lx = lgefint(x);
4789 : GEN y;
4790 :
4791 2830683 : if (lx >= l) return icopy(x);
4792 35 : y = cgeti(l); affii(x, y); return y;
4793 : }
4794 :
4795 : /* continued fraction of a/b. If y != NULL, stop when partial quotients
4796 : * differ from y */
4797 : static GEN
4798 2830979 : Qsfcont(GEN a, GEN b, GEN y, ulong k)
4799 : {
4800 : GEN z, c;
4801 2830979 : ulong i, l, ly = lgefint(b);
4802 :
4803 : /* times 1 / log2( (1+sqrt(5)) / 2 ) */
4804 2830979 : l = (ulong)(3 + bit_accuracy_mul(ly, 1.44042009041256));
4805 2830979 : if (k > 0 && k+1 > 0 && l > k+1) l = k+1; /* beware overflow */
4806 2830979 : if (l > LGBITS) l = LGBITS;
4807 :
4808 2830979 : z = cgetg(l,t_VEC);
4809 2830979 : l--;
4810 2830979 : if (y) {
4811 296 : pari_sp av = avma;
4812 296 : if (l >= (ulong)lg(y)) l = lg(y)-1;
4813 19467 : for (i = 1; i <= l; i++)
4814 : {
4815 19282 : GEN q = gel(y,i);
4816 19282 : gel(z,i) = q;
4817 19282 : c = b; if (!gequal1(q)) c = mulii(q, b);
4818 19282 : c = subii(a, c);
4819 19282 : if (signe(c) < 0)
4820 : { /* partial quotient too large */
4821 110 : c = addii(c, b);
4822 110 : if (signe(c) >= 0) i++; /* by 1 */
4823 110 : break;
4824 : }
4825 19172 : if (cmpii(c, b) >= 0)
4826 : { /* partial quotient too small */
4827 1 : c = subii(c, b);
4828 1 : if (cmpii(c, b) < 0) {
4829 : /* by 1. If next quotient is 1 in y, add 1 */
4830 0 : if (i < l && equali1(gel(y,i+1))) gel(z,i) = addiu(q,1);
4831 0 : i++;
4832 : }
4833 1 : break;
4834 : }
4835 19171 : if ((i & 0xff) == 0) gerepileall(av, 2, &b, &c);
4836 19171 : a = b; b = c;
4837 : }
4838 : } else {
4839 2830683 : a = icopy_lg(a, ly);
4840 2830683 : b = icopy(b);
4841 23440276 : for (i = 1; i <= l; i++)
4842 : {
4843 23440012 : gel(z,i) = truedvmdii(a,b,&c);
4844 23440012 : if (c == gen_0) { i++; break; }
4845 20609593 : affii(c, a); cgiv(c); c = a;
4846 20609593 : a = b; b = c;
4847 : }
4848 : }
4849 2830979 : i--;
4850 2830979 : if (i > 1 && gequal1(gel(z,i)))
4851 : {
4852 85 : cgiv(gel(z,i)); --i;
4853 85 : gel(z,i) = addui(1, gel(z,i)); /* unclean: leave old z[i] on stack */
4854 : }
4855 2830979 : setlg(z,i+1); return z;
4856 : }
4857 :
4858 : static GEN
4859 0 : sersfcont(GEN a, GEN b, long k)
4860 : {
4861 0 : long i, l = typ(a) == t_POL? lg(a): 3;
4862 : GEN y, c;
4863 0 : if (lg(b) > l) l = lg(b);
4864 0 : if (k > 0 && l > k+1) l = k+1;
4865 0 : y = cgetg(l,t_VEC);
4866 0 : for (i=1; i<l; i++)
4867 : {
4868 0 : gel(y,i) = poldivrem(a,b,&c);
4869 0 : if (gequal0(c)) { i++; break; }
4870 0 : a = b; b = c;
4871 : }
4872 0 : setlg(y, i); return y;
4873 : }
4874 :
4875 : GEN
4876 2831698 : gboundcf(GEN x, long k)
4877 : {
4878 : pari_sp av;
4879 2831698 : long tx = typ(x), e;
4880 : GEN y, a, b, c;
4881 :
4882 2831698 : if (k < 0) pari_err_DOMAIN("gboundcf","nmax","<",gen_0,stoi(k));
4883 2831691 : if (is_scalar_t(tx))
4884 : {
4885 2831691 : if (gequal0(x)) return mkvec(gen_0);
4886 2831586 : switch(tx)
4887 : {
4888 896 : case t_INT: return mkveccopy(x);
4889 : case t_REAL:
4890 303 : av = avma;
4891 303 : c = mantissa_real(x,&e);
4892 303 : if (e < 0) pari_err_PREC("gboundcf");
4893 296 : y = int2n(e);
4894 296 : a = Qsfcont(c,y, NULL, k);
4895 296 : b = addsi(signe(x), c);
4896 296 : return gerepilecopy(av, Qsfcont(b,y, a, k));
4897 :
4898 : case t_FRAC:
4899 2830387 : av = avma;
4900 2830387 : return gerepileupto(av, Qsfcont(gel(x,1),gel(x,2), NULL, k));
4901 : }
4902 0 : pari_err_TYPE("gboundcf",x);
4903 : }
4904 :
4905 0 : switch(tx)
4906 : {
4907 0 : case t_POL: return mkveccopy(x);
4908 : case t_SER:
4909 0 : av = avma;
4910 0 : return gerepileupto(av, gboundcf(ser2rfrac_i(x), k));
4911 : case t_RFRAC:
4912 0 : av = avma;
4913 0 : return gerepilecopy(av, sersfcont(gel(x,1), gel(x,2), k));
4914 : }
4915 0 : pari_err_TYPE("gboundcf",x);
4916 : return NULL; /* LCOV_EXCL_LINE */
4917 : }
4918 :
4919 : static GEN
4920 14 : sfcont2(GEN b, GEN x, long k)
4921 : {
4922 14 : pari_sp av = avma;
4923 14 : long lb = lg(b), tx = typ(x), i;
4924 : GEN y,p1;
4925 :
4926 14 : if (k)
4927 : {
4928 7 : if (k >= lb) pari_err_DIM("contfrac [too few denominators]");
4929 0 : lb = k+1;
4930 : }
4931 7 : y = cgetg(lb,t_VEC);
4932 7 : if (lb==1) return y;
4933 7 : if (is_scalar_t(tx))
4934 : {
4935 7 : if (!is_intreal_t(tx) && tx != t_FRAC) pari_err_TYPE("sfcont2",x);
4936 : }
4937 0 : else if (tx == t_SER) x = ser2rfrac_i(x);
4938 :
4939 7 : if (!gequal1(gel(b,1))) x = gmul(gel(b,1),x);
4940 7 : for (i = 1;;)
4941 : {
4942 63 : if (tx == t_REAL)
4943 : {
4944 35 : long e = expo(x);
4945 35 : if (e > 0 && nbits2prec(e+1) > realprec(x)) break;
4946 35 : gel(y,i) = floorr(x);
4947 35 : p1 = subri(x, gel(y,i));
4948 : }
4949 : else
4950 : {
4951 0 : gel(y,i) = gfloor(x);
4952 0 : p1 = gsub(x, gel(y,i));
4953 : }
4954 35 : if (++i >= lb) break;
4955 28 : if (gequal0(p1)) break;
4956 28 : x = gdiv(gel(b,i),p1);
4957 : }
4958 7 : setlg(y,i);
4959 7 : return gerepilecopy(av,y);
4960 : }
4961 :
4962 :
4963 : GEN
4964 105 : gcf(GEN x) { return gboundcf(x,0); }
4965 : GEN
4966 0 : gcf2(GEN b, GEN x) { return contfrac0(x,b,0); }
4967 : GEN
4968 49 : contfrac0(GEN x, GEN b, long nmax)
4969 : {
4970 : long tb;
4971 :
4972 49 : if (!b) return gboundcf(x,nmax);
4973 28 : tb = typ(b);
4974 28 : if (tb == t_INT) return gboundcf(x,itos(b));
4975 21 : if (! is_vec_t(tb)) pari_err_TYPE("contfrac0",b);
4976 21 : if (nmax < 0) pari_err_DOMAIN("contfrac","nmax","<",gen_0,stoi(nmax));
4977 14 : return sfcont2(b,x,nmax);
4978 : }
4979 :
4980 : GEN
4981 245 : contfracpnqn(GEN x, long n)
4982 : {
4983 245 : pari_sp av = avma;
4984 245 : long i, lx = lg(x);
4985 : GEN M,A,B, p0,p1, q0,q1;
4986 :
4987 245 : if (lx == 1)
4988 : {
4989 28 : if (! is_matvec_t(typ(x))) pari_err_TYPE("pnqn",x);
4990 21 : if (n >= 0) return cgetg(1,t_MAT);
4991 7 : return matid(2);
4992 : }
4993 217 : switch(typ(x))
4994 : {
4995 175 : case t_VEC: case t_COL: A = x; B = NULL; break;
4996 : case t_MAT:
4997 42 : switch(lgcols(x))
4998 : {
4999 0 : case 2: A = row(x,1); B = NULL; break;
5000 35 : case 3: A = row(x,2); B = row(x,1); break;
5001 7 : default: pari_err_DIM("pnqn [ nbrows != 1,2 ]");
5002 : return NULL; /*LCOV_EXCL_LINE*/
5003 : }
5004 35 : break;
5005 0 : default: pari_err_TYPE("pnqn",x);
5006 : return NULL; /*LCOV_EXCL_LINE*/
5007 : }
5008 210 : p1 = gel(A,1);
5009 210 : q1 = B? gel(B,1): gen_1; /* p[0], q[0] */
5010 210 : if (n >= 0)
5011 : {
5012 175 : lx = minss(lx, n+2);
5013 175 : if (lx == 2) return gerepilecopy(av, mkmat(mkcol2(p1,q1)));
5014 : }
5015 35 : else if (lx == 2)
5016 7 : return gerepilecopy(av, mkmat2(mkcol2(p1,q1), mkcol2(gen_1,gen_0)));
5017 : /* lx >= 3 */
5018 112 : p0 = gen_1;
5019 112 : q0 = gen_0; /* p[-1], q[-1] */
5020 112 : M = cgetg(lx, t_MAT);
5021 112 : gel(M,1) = mkcol2(p1,q1);
5022 364 : for (i=2; i<lx; i++)
5023 : {
5024 252 : GEN a = gel(A,i), p2,q2;
5025 252 : if (B) {
5026 84 : GEN b = gel(B,i);
5027 84 : p0 = gmul(b,p0);
5028 84 : q0 = gmul(b,q0);
5029 : }
5030 252 : p2 = gadd(gmul(a,p1),p0); p0=p1; p1=p2;
5031 252 : q2 = gadd(gmul(a,q1),q0); q0=q1; q1=q2;
5032 252 : gel(M,i) = mkcol2(p1,q1);
5033 : }
5034 112 : if (n < 0) M = mkmat2(gel(M,lx-1), gel(M,lx-2));
5035 112 : return gerepilecopy(av, M);
5036 : }
5037 : GEN
5038 0 : pnqn(GEN x) { return contfracpnqn(x,-1); }
5039 : /* x = [a0, ..., an] from gboundcf, n >= 0;
5040 : * return [[p0, ..., pn], [q0,...,qn]] */
5041 : GEN
5042 609308 : ZV_allpnqn(GEN x)
5043 : {
5044 609308 : long i, lx = lg(x);
5045 609308 : GEN p0, p1, q0, q1, p2, q2, P,Q, v = cgetg(3,t_VEC);
5046 :
5047 609308 : gel(v,1) = P = cgetg(lx, t_VEC);
5048 609308 : gel(v,2) = Q = cgetg(lx, t_VEC);
5049 609308 : p0 = gen_1; q0 = gen_0;
5050 609308 : gel(P, 1) = p1 = gel(x,1); gel(Q, 1) = q1 = gen_1;
5051 2092209 : for (i=2; i<lx; i++)
5052 : {
5053 1482901 : GEN a = gel(x,i);
5054 1482901 : gel(P, i) = p2 = addmulii(p0, a, p1); p0 = p1; p1 = p2;
5055 1482901 : gel(Q, i) = q2 = addmulii(q0, a, q1); q0 = q1; q1 = q2;
5056 : }
5057 609308 : return v;
5058 : }
5059 :
5060 : /* write Mod(x,N) as a/b, gcd(a,b) = 1, b <= B (no condition if B = NULL) */
5061 : static GEN
5062 42 : mod_to_frac(GEN x, GEN N, GEN B)
5063 : {
5064 : GEN a, b, A;
5065 42 : if (B) A = divii(shifti(N, -1), B);
5066 : else
5067 : {
5068 14 : A = sqrti(shifti(N, -1));
5069 14 : B = A;
5070 : }
5071 42 : if (!Fp_ratlift(x, N, A,B,&a,&b) || !equali1( gcdii(a,b) )) return NULL;
5072 28 : return equali1(b)? a: mkfrac(a,b);
5073 : }
5074 :
5075 : static GEN
5076 70 : mod_to_rfrac(GEN x, GEN N, long B)
5077 : {
5078 : GEN a, b;
5079 70 : long A, d = degpol(N);
5080 70 : if (B >= 0) A = d-1 - B;
5081 : else
5082 : {
5083 42 : B = d >> 1;
5084 42 : A = odd(d)? B : B-1;
5085 : }
5086 70 : if (varn(N) != varn(x)) x = scalarpol(x, varn(N));
5087 70 : if (!RgXQ_ratlift(x, N, A, B, &a,&b) || degpol(RgX_gcd(a,b)) > 0) return NULL;
5088 56 : return gdiv(a,b);
5089 : }
5090 :
5091 : /* k > 0 t_INT, x a t_FRAC, returns the convergent a/b
5092 : * of the continued fraction of x with b <= k maximal */
5093 : static GEN
5094 7 : bestappr_frac(GEN x, GEN k)
5095 : {
5096 : pari_sp av;
5097 : GEN p0, p1, p, q0, q1, q, a, y;
5098 :
5099 7 : if (cmpii(gel(x,2),k) <= 0) return gcopy(x);
5100 0 : av = avma; y = x;
5101 0 : p1 = gen_1; p0 = truedvmdii(gel(x,1), gel(x,2), &a); /* = floor(x) */
5102 0 : q1 = gen_0; q0 = gen_1;
5103 0 : x = mkfrac(a, gel(x,2)); /* = frac(x); now 0<= x < 1 */
5104 : for(;;)
5105 : {
5106 0 : x = ginv(x); /* > 1 */
5107 0 : a = typ(x)==t_INT? x: divii(gel(x,1), gel(x,2));
5108 0 : if (cmpii(a,k) > 0)
5109 : { /* next partial quotient will overflow limits */
5110 : GEN n, d;
5111 0 : a = divii(subii(k, q1), q0);
5112 0 : p = addii(mulii(a,p0), p1); p1=p0; p0=p;
5113 0 : q = addii(mulii(a,q0), q1); q1=q0; q0=q;
5114 : /* compare |y-p0/q0|, |y-p1/q1| */
5115 0 : n = gel(y,1);
5116 0 : d = gel(y,2);
5117 0 : if (abscmpii(mulii(q1, subii(mulii(q0,n), mulii(d,p0))),
5118 : mulii(q0, subii(mulii(q1,n), mulii(d,p1)))) < 0)
5119 0 : { p1 = p0; q1 = q0; }
5120 0 : break;
5121 : }
5122 0 : p = addii(mulii(a,p0), p1); p1=p0; p0=p;
5123 0 : q = addii(mulii(a,q0), q1); q1=q0; q0=q;
5124 :
5125 0 : if (cmpii(q0,k) > 0) break;
5126 0 : x = gsub(x,a); /* 0 <= x < 1 */
5127 0 : if (typ(x) == t_INT) { p1 = p0; q1 = q0; break; } /* x = 0 */
5128 :
5129 : }
5130 0 : return gerepileupto(av, gdiv(p1,q1));
5131 : }
5132 : /* k > 0 t_INT, x != 0 a t_REAL, returns the convergent a/b
5133 : * of the continued fraction of x with b <= k maximal */
5134 : static GEN
5135 386713 : bestappr_real(GEN x, GEN k)
5136 : {
5137 386713 : pari_sp av = avma;
5138 386713 : GEN kr, p0, p1, p, q0, q1, q, a, y = x;
5139 :
5140 386713 : p1 = gen_1; a = p0 = floorr(x);
5141 386713 : q1 = gen_0; q0 = gen_1;
5142 386713 : x = subri(x,a); /* 0 <= x < 1 */
5143 386713 : if (!signe(x)) { cgiv(x); return a; }
5144 377752 : kr = itor(k, realprec(x));
5145 : for(;;)
5146 468312 : {
5147 : long d;
5148 846064 : x = invr(x); /* > 1 */
5149 846064 : if (cmprr(x,kr) > 0)
5150 : { /* next partial quotient will overflow limits */
5151 372557 : a = divii(subii(k, q1), q0);
5152 372557 : p = addii(mulii(a,p0), p1); p1=p0; p0=p;
5153 372557 : q = addii(mulii(a,q0), q1); q1=q0; q0=q;
5154 : /* compare |y-p0/q0|, |y-p1/q1| */
5155 372557 : if (abscmprr(mulir(q1, subri(mulir(q0,y), p0)),
5156 : mulir(q0, subri(mulir(q1,y), p1))) < 0)
5157 11473 : { p1 = p0; q1 = q0; }
5158 372557 : break;
5159 : }
5160 473507 : d = nbits2prec(expo(x) + 1);
5161 473507 : if (d > lg(x)) { p1 = p0; q1 = q0; break; } /* original x was ~ 0 */
5162 :
5163 473328 : a = truncr(x); /* truncr(x) will NOT raise e_PREC */
5164 473328 : p = addii(mulii(a,p0), p1); p1=p0; p0=p;
5165 473328 : q = addii(mulii(a,q0), q1); q1=q0; q0=q;
5166 :
5167 473328 : if (cmpii(q0,k) > 0) break;
5168 469266 : x = subri(x,a); /* 0 <= x < 1 */
5169 469266 : if (!signe(x)) { p1 = p0; q1 = q0; break; }
5170 : }
5171 377752 : if (signe(q1) < 0) { togglesign_safe(&p1); togglesign_safe(&q1); }
5172 377752 : return gerepilecopy(av, equali1(q1)? p1: mkfrac(p1,q1));
5173 : }
5174 :
5175 : /* k t_INT or NULL */
5176 : static GEN
5177 614494 : bestappr_Q(GEN x, GEN k)
5178 : {
5179 614494 : long lx, tx = typ(x), i;
5180 : GEN a, y;
5181 :
5182 614494 : switch(tx)
5183 : {
5184 77 : case t_INT: return icopy(x);
5185 7 : case t_FRAC: return k? bestappr_frac(x, k): gcopy(x);
5186 : case t_REAL:
5187 462879 : if (!signe(x)) return gen_0;
5188 : /* i <= e iff nbits2lg(e+1) > lg(x) iff floorr(x) fails */
5189 386713 : i = bit_prec(x); if (i <= expo(x)) return NULL;
5190 386713 : return bestappr_real(x, k? k: int2n(i));
5191 :
5192 : case t_INTMOD: {
5193 28 : pari_sp av = avma;
5194 28 : a = mod_to_frac(gel(x,2), gel(x,1), k); if (!a) return NULL;
5195 21 : return gerepilecopy(av, a);
5196 : }
5197 : case t_PADIC: {
5198 14 : pari_sp av = avma;
5199 14 : long v = valp(x);
5200 14 : a = mod_to_frac(gel(x,4), gel(x,3), k); if (!a) return NULL;
5201 7 : if (v) a = gmul(a, powis(gel(x,2), v));
5202 7 : return gerepilecopy(av, a);
5203 : }
5204 :
5205 : case t_COMPLEX: {
5206 196 : pari_sp av = avma;
5207 196 : y = cgetg(3, t_COMPLEX);
5208 196 : gel(y,2) = bestappr(gel(x,2), k);
5209 196 : gel(y,1) = bestappr(gel(x,1), k);
5210 196 : if (gequal0(gel(y,2))) return gerepileupto(av, gel(y,1));
5211 0 : return y;
5212 : }
5213 : case t_SER:
5214 0 : if (ser_isexactzero(x)) return gcopy(x);
5215 : /* fall through */
5216 : case t_POLMOD: case t_POL: case t_RFRAC:
5217 : case t_VEC: case t_COL: case t_MAT:
5218 151293 : y = cgetg_copy(x, &lx);
5219 151293 : if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }
5220 752277 : for (; i<lx; i++)
5221 : {
5222 600984 : a = bestappr_Q(gel(x,i),k); if (!a) return NULL;
5223 600984 : gel(y,i) = a;
5224 : }
5225 151293 : if (tx == t_POL) return normalizepol(y);
5226 151279 : if (tx == t_SER) return normalize(y);
5227 151279 : return y;
5228 : }
5229 0 : pari_err_TYPE("bestappr_Q",x);
5230 : return NULL; /* LCOV_EXCL_LINE */
5231 : }
5232 :
5233 : static GEN
5234 56 : bestappr_ser(GEN x, long B)
5235 : {
5236 56 : long dN, v = valp(x), lx = lg(x);
5237 : GEN t;
5238 56 : x = normalizepol(ser2pol_i(x, lx));
5239 56 : dN = lx-2;
5240 56 : if (v > 0)
5241 : {
5242 14 : x = RgX_shift_shallow(x, v);
5243 14 : dN += v;
5244 : }
5245 42 : else if (v < 0)
5246 : {
5247 7 : if (B >= 0) B = maxss(B+v, 0);
5248 : }
5249 56 : t = mod_to_rfrac(x, pol_xn(dN, varn(x)), B);
5250 56 : if (!t) return NULL;
5251 42 : if (v < 0)
5252 : {
5253 : GEN a, b;
5254 : long vx;
5255 7 : if (typ(t) == t_POL) return RgX_mulXn(t, v);
5256 : /* t_RFRAC */
5257 7 : vx = varn(x);
5258 7 : a = gel(t,1);
5259 7 : b = gel(t,2);
5260 7 : v -= RgX_valrem(b, &b);
5261 7 : if (typ(a) == t_POL && varn(a) == vx) v += RgX_valrem(a, &a);
5262 7 : if (v < 0) b = RgX_shift(b, -v);
5263 0 : else if (v > 0) {
5264 0 : if (typ(a) != t_POL || varn(a) != vx) a = scalarpol_shallow(a, vx);
5265 0 : a = RgX_shift(a, v);
5266 : }
5267 7 : t = mkrfraccopy(a, b);
5268 : }
5269 42 : return t;
5270 : }
5271 : static GEN bestappr_RgX(GEN x, long B);
5272 : /* x t_POLMOD, B >= 0 or < 0 [omit condition on B].
5273 : * Look for coprime t_POL a,b, deg(b)<=B, such that a/b = x */
5274 : static GEN
5275 77 : bestappr_RgX(GEN x, long B)
5276 : {
5277 77 : long i, lx, tx = typ(x);
5278 : GEN y, t;
5279 77 : switch(tx)
5280 : {
5281 : case t_INT: case t_REAL: case t_INTMOD: case t_FRAC:
5282 : case t_COMPLEX: case t_PADIC: case t_QUAD: case t_POL:
5283 0 : return gcopy(x);
5284 :
5285 : case t_RFRAC: {
5286 14 : pari_sp av = avma;
5287 14 : if (B < 0 || degpol(gel(x,2)) <= B) return gcopy(x);
5288 7 : x = rfrac_to_ser(x, 2*B+1);
5289 7 : t = bestappr_ser(x, B); if (!t) return NULL;
5290 0 : return gerepileupto(av, t);
5291 : }
5292 : case t_POLMOD: {
5293 14 : pari_sp av = avma;
5294 14 : t = mod_to_rfrac(gel(x,2), gel(x,1), B); if (!t) return NULL;
5295 14 : return gerepileupto(av, t);
5296 : }
5297 : case t_SER: {
5298 49 : pari_sp av = avma;
5299 49 : t = bestappr_ser(x, B); if (!t) return NULL;
5300 42 : return gerepileupto(av, t);
5301 : }
5302 :
5303 : case t_VEC: case t_COL: case t_MAT:
5304 0 : y = cgetg_copy(x, &lx);
5305 0 : if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }
5306 0 : for (; i<lx; i++)
5307 : {
5308 0 : t = bestappr_RgX(gel(x,i),B); if (!t) return NULL;
5309 0 : gel(y,i) = t;
5310 : }
5311 0 : return y;
5312 : }
5313 0 : pari_err_TYPE("bestappr_RgX",x);
5314 : return NULL; /* LCOV_EXCL_LINE */
5315 : }
5316 :
5317 : /* allow k = NULL: maximal accuracy */
5318 : GEN
5319 13510 : bestappr(GEN x, GEN k)
5320 : {
5321 13510 : pari_sp av = avma;
5322 13510 : if (k) { /* replace by floor(k) */
5323 13237 : switch(typ(k))
5324 : {
5325 : case t_INT:
5326 1785 : break;
5327 : case t_REAL: case t_FRAC:
5328 11452 : k = floor_safe(k); /* left on stack for efficiency */
5329 11452 : if (!signe(k)) k = gen_1;
5330 11452 : break;
5331 : default:
5332 0 : pari_err_TYPE("bestappr [bound type]", k);
5333 0 : break;
5334 : }
5335 : }
5336 13510 : x = bestappr_Q(x, k);
5337 13510 : if (!x) { set_avma(av); return cgetg(1,t_VEC); }
5338 13496 : return x;
5339 : }
5340 : GEN
5341 77 : bestapprPade(GEN x, long B)
5342 : {
5343 77 : pari_sp av = avma;
5344 77 : GEN t = bestappr_RgX(x, B);
5345 77 : if (!t) { set_avma(av); return cgetg(1,t_VEC); }
5346 63 : return t;
5347 : }
5348 :
5349 : /***********************************************************************/
5350 : /** **/
5351 : /** FUNDAMENTAL UNIT AND REGULATOR (QUADRATIC FIELDS) **/
5352 : /** **/
5353 : /***********************************************************************/
5354 :
5355 : static GEN
5356 14 : get_quad(GEN f, GEN pol, long r)
5357 : {
5358 14 : GEN p1 = gcoeff(f,1,2), q1 = gcoeff(f,2,2);
5359 14 : return mkquad(pol, r? subii(p1,q1): p1, q1);
5360 : }
5361 :
5362 : /* replace f by f * [a,1; 1,0] */
5363 : static void
5364 14 : update_f(GEN f, GEN a)
5365 : {
5366 : GEN p1;
5367 14 : p1 = gcoeff(f,1,1);
5368 14 : gcoeff(f,1,1) = addii(mulii(a,p1), gcoeff(f,1,2));
5369 14 : gcoeff(f,1,2) = p1;
5370 :
5371 14 : p1 = gcoeff(f,2,1);
5372 14 : gcoeff(f,2,1) = addii(mulii(a,p1), gcoeff(f,2,2));
5373 14 : gcoeff(f,2,2) = p1;
5374 14 : }
5375 :
5376 : GEN
5377 7 : quadunit(GEN x)
5378 : {
5379 7 : pari_sp av = avma, av2;
5380 : GEN pol, y, a, u, v, sqd, f;
5381 : long r;
5382 :
5383 7 : check_quaddisc_real(x, &r, "quadunit");
5384 7 : pol = quadpoly(x);
5385 7 : sqd = sqrti(x); av2 = avma;
5386 7 : a = shifti(addui(r,sqd),-1);
5387 7 : f = mkmat2(mkcol2(a, gen_1), mkcol2(gen_1, gen_0)); /* [a,0; 1,0] */
5388 7 : u = stoi(r); v = gen_2;
5389 : for(;;)
5390 7 : {
5391 : GEN u1, v1;
5392 14 : u1 = subii(mulii(a,v),u);
5393 14 : v1 = divii(subii(x,sqri(u1)),v);
5394 14 : if ( equalii(v,v1) ) {
5395 7 : y = get_quad(f,pol,r);
5396 7 : update_f(f,a);
5397 7 : y = gdiv(get_quad(f,pol,r), conj_i(y));
5398 7 : break;
5399 : }
5400 7 : a = divii(addii(sqd,u1), v1);
5401 7 : if ( equalii(u,u1) ) {
5402 0 : y = get_quad(f,pol,r);
5403 0 : y = gdiv(y, conj_i(y));
5404 0 : break;
5405 : }
5406 7 : update_f(f,a);
5407 7 : u = u1; v = v1;
5408 7 : if (gc_needed(av2,2))
5409 : {
5410 0 : if(DEBUGMEM>1) pari_warn(warnmem,"quadunit");
5411 0 : gerepileall(av2,4, &a,&f,&u,&v);
5412 : }
5413 : }
5414 7 : if (signe(gel(y,3)) < 0) y = gneg(y);
5415 7 : return gerepileupto(av, y);
5416 : }
5417 :
5418 : GEN
5419 7 : quadunit0(GEN x, long v)
5420 : {
5421 7 : GEN y = quadunit(x);
5422 7 : if (v==-1) v = fetch_user_var("w");
5423 7 : setvarn(gel(y,1), v);
5424 7 : return y;
5425 : }
5426 :
5427 : GEN
5428 21 : quadregulator(GEN x, long prec)
5429 : {
5430 21 : pari_sp av = avma, av2;
5431 : GEN R, rsqd, u, v, sqd;
5432 : long r, Rexpo;
5433 :
5434 21 : check_quaddisc_real(x, &r, "quadregulator");
5435 21 : sqd = sqrti(x);
5436 21 : rsqd = gsqrt(x,prec);
5437 21 : Rexpo = 0; R = real2n(1, prec); /* = 2 */
5438 21 : av2 = avma;
5439 21 : u = stoi(r); v = gen_2;
5440 : for(;;)
5441 49 : {
5442 70 : GEN u1 = subii(mulii(divii(addii(u,sqd),v), v), u);
5443 70 : GEN v1 = divii(subii(x,sqri(u1)),v);
5444 70 : if (equalii(v,v1))
5445 : {
5446 7 : R = sqrr(R); shiftr_inplace(R, -1);
5447 7 : R = mulrr(R, divri(addir(u1,rsqd),v));
5448 7 : break;
5449 : }
5450 63 : if (equalii(u,u1))
5451 : {
5452 14 : R = sqrr(R); shiftr_inplace(R, -1);
5453 14 : break;
5454 : }
5455 49 : R = mulrr(R, divri(addir(u1,rsqd),v));
5456 49 : Rexpo += expo(R); setexpo(R,0);
5457 49 : u = u1; v = v1;
5458 49 : if (Rexpo & ~EXPOBITS) pari_err_OVERFLOW("quadregulator [exponent]");
5459 49 : if (gc_needed(av2,2))
5460 : {
5461 0 : if(DEBUGMEM>1) pari_warn(warnmem,"quadregulator");
5462 0 : gerepileall(av2,3, &R,&u,&v);
5463 : }
5464 : }
5465 21 : R = logr_abs(divri(R,v));
5466 21 : if (Rexpo)
5467 : {
5468 21 : GEN t = mulsr(Rexpo, mplog2(prec));
5469 21 : shiftr_inplace(t, 1);
5470 21 : R = addrr(R,t);
5471 : }
5472 21 : return gerepileuptoleaf(av, R);
5473 : }
5474 :
5475 : /*************************************************************************/
5476 : /** **/
5477 : /** CLASS NUMBER **/
5478 : /** **/
5479 : /*************************************************************************/
5480 :
5481 : int
5482 12943797 : qfb_equal1(GEN f) { return equali1(gel(f,1)); }
5483 :
5484 18316834 : static GEN qfi_pow(void *E, GEN f, GEN n)
5485 18316834 : { return E? nupow(f,n,(GEN)E): powgi(f,n); }
5486 23025703 : static GEN qfi_comp(void *E, GEN f, GEN g)
5487 23025703 : { return E? nucomp(f,g,(GEN)E): qficomp(f,g); }
5488 : static const struct bb_group qfi_group={ qfi_comp,qfi_pow,NULL,hash_GEN,
5489 : gidentical,qfb_equal1,NULL};
5490 :
5491 : GEN
5492 2941241 : qfi_order(GEN q, GEN o)
5493 2941241 : { return gen_order(q, o, NULL, &qfi_group); }
5494 :
5495 : GEN
5496 0 : qfi_log(GEN a, GEN g, GEN o)
5497 0 : { return gen_PH_log(a, g, o, NULL, &qfi_group); }
5498 :
5499 : GEN
5500 626556 : qfi_Shanks(GEN a, GEN g, long n)
5501 : {
5502 626556 : pari_sp av = avma;
5503 : GEN T, X;
5504 : long rt_n, c;
5505 :
5506 626556 : a = redimag(a);
5507 626556 : g = redimag(g);
5508 :
5509 626556 : rt_n = sqrt((double)n);
5510 626556 : c = n / rt_n;
5511 626556 : c = (c * rt_n < n + 1) ? c + 1 : c;
5512 :
5513 626556 : T = gen_Shanks_init(g, rt_n, NULL, &qfi_group);
5514 626556 : X = gen_Shanks(T, a, c, NULL, &qfi_group);
5515 :
5516 626556 : if (!X) { set_avma(av); return X; }
5517 332549 : return gerepileuptoint(av, X);
5518 : }
5519 :
5520 : GEN
5521 140 : qfbclassno0(GEN x,long flag)
5522 : {
5523 140 : switch(flag)
5524 : {
5525 126 : case 0: return map_proto_G(classno,x);
5526 14 : case 1: return map_proto_G(classno2,x);
5527 0 : default: pari_err_FLAG("qfbclassno");
5528 : }
5529 : return NULL; /* LCOV_EXCL_LINE */
5530 : }
5531 :
5532 : /* f^h = 1, return order(f). Set *pfao to its factorization */
5533 : static GEN
5534 2776995 : find_order(void *E, GEN f, GEN h, GEN *pfao)
5535 : {
5536 2776995 : GEN v = gen_factored_order(f, h, E, &qfi_group);
5537 2776995 : *pfao = gel(v,2); return gel(v,1);
5538 : }
5539 :
5540 : static int
5541 6705 : ok_q(GEN q, GEN h, GEN d2, long r2)
5542 : {
5543 6705 : if (d2)
5544 : {
5545 7 : if (r2 <= 2 && !mpodd(q)) return 0;
5546 7 : return is_pm1(Z_ppo(q,d2));
5547 : }
5548 : else
5549 : {
5550 6698 : if (r2 <= 1 && !mpodd(q)) return 0;
5551 6698 : return is_pm1(Z_ppo(q,h));
5552 : }
5553 : }
5554 :
5555 : /* a,b given by their factorizations. Return factorization of lcm(a,b).
5556 : * Set A,B such that A*B = lcm(a, b), (A,B)=1, A|a, B|b */
5557 : static GEN
5558 362162 : split_lcm(GEN a, GEN Fa, GEN b, GEN Fb, GEN *pA, GEN *pB)
5559 : {
5560 362162 : GEN P = ZC_union_shallow(gel(Fa,1), gel(Fb,1));
5561 362162 : GEN A = gen_1, B = gen_1;
5562 362162 : long i, l = lg(P);
5563 362162 : GEN E = cgetg(l, t_COL);
5564 1071040 : for (i=1; i<l; i++)
5565 : {
5566 708878 : GEN p = gel(P,i);
5567 708878 : long va = Z_pval(a,p);
5568 708878 : long vb = Z_pval(b,p);
5569 708878 : if (va < vb)
5570 : {
5571 364289 : B = mulii(B,powiu(p,vb));
5572 364289 : gel(E,i) = utoi(vb);
5573 : }
5574 : else
5575 : {
5576 344589 : A = mulii(A,powiu(p,va));
5577 344589 : gel(E,i) = utoi(va);
5578 : }
5579 : }
5580 362162 : *pA = A;
5581 362162 : *pB = B; return mkmat2(P,E);
5582 : }
5583 :
5584 : /* g1 has order d1, f has order o, replace g1 by an element of order lcm(d1,o)*/
5585 : static void
5586 362162 : update_g1(GEN *pg1, GEN *pd1, GEN *pfad1, GEN f, GEN o, GEN fao)
5587 : {
5588 362162 : GEN A,B, g1 = *pg1, d1 = *pd1;
5589 362162 : *pfad1 = split_lcm(d1,*pfad1, o,fao, &A,&B);
5590 362162 : *pg1 = gmul(powgi(g1, diviiexact(d1,A)), powgi(f, diviiexact(o,B)));
5591 362162 : *pd1 = mulii(A,B); /* g1 has order d1 <- lcm(d1,o) */
5592 362162 : }
5593 :
5594 : /* Write x = Df^2, where D = fundamental discriminant,
5595 : * P^E = factorisation of conductor f, with E[i] >= 0 */
5596 : static void
5597 2060327 : corediscfact(GEN x, long xmod4, GEN *ptD, GEN *ptP, GEN *ptE)
5598 : {
5599 2060327 : long s = signe(x), l, i;
5600 2060327 : GEN fa = absZ_factor(x);
5601 2060327 : GEN d, P = gel(fa,1), E = gtovecsmall(gel(fa,2));
5602 :
5603 2060327 : l = lg(P); d = gen_1;
5604 5362951 : for (i=1; i<l; i++)
5605 : {
5606 3302624 : if (E[i] & 1) d = mulii(d, gel(P,i));
5607 3302624 : E[i] >>= 1;
5608 : }
5609 2060327 : if (!xmod4 && mod4(d) != ((s < 0)? 3: 1)) { d = shifti(d,2); E[1]--; }
5610 2060327 : *ptD = (s < 0)? negi(d): d;
5611 2060327 : *ptP = P;
5612 2060327 : *ptE = E;
5613 2060327 : }
5614 :
5615 : static GEN
5616 2052517 : conductor_part(GEN x, long xmod4, GEN *ptD, GEN *ptreg)
5617 : {
5618 2052517 : long l, i, s = signe(x);
5619 : GEN E, H, D, P, reg;
5620 :
5621 2052517 : corediscfact(x, xmod4, &D, &P, &E);
5622 2052517 : H = gen_1; l = lg(P);
5623 : /* f \prod_{p|f} [ 1 - (D/p) p^-1 ] = \prod_{p^e||f} p^(e-1) [ p - (D/p) ] */
5624 5329269 : for (i=1; i<l; i++)
5625 : {
5626 3276752 : long e = E[i];
5627 3276752 : if (e)
5628 : {
5629 7 : GEN p = gel(P,i);
5630 7 : H = mulii(H, subis(p, kronecker(D,p)));
5631 7 : if (e >= 2) H = mulii(H, powiu(p,e-1));
5632 : }
5633 : }
5634 :
5635 : /* divide by [ O_K^* : O^* ] */
5636 2052517 : if (s < 0)
5637 : {
5638 2052503 : reg = NULL;
5639 2052503 : switch(itou_or_0(D))
5640 : {
5641 0 : case 4: H = shifti(H,-1); break;
5642 0 : case 3: H = divis(H,3); break;
5643 : }
5644 : } else {
5645 14 : reg = quadregulator(D,DEFAULTPREC);
5646 14 : if (!equalii(x,D))
5647 0 : H = divii(H, roundr(divrr(quadregulator(x,DEFAULTPREC), reg)));
5648 : }
5649 2052517 : if (ptreg) *ptreg = reg;
5650 2052517 : *ptD = D; return H;
5651 : }
5652 :
5653 : static long
5654 2052496 : two_rank(GEN x)
5655 : {
5656 2052496 : GEN p = gel(absZ_factor(x),1);
5657 2052496 : long l = lg(p)-1;
5658 : #if 0 /* positive disc not needed */
5659 : if (signe(x) > 0)
5660 : {
5661 : long i;
5662 : for (i=1; i<=l; i++)
5663 : if (mod4(gel(p,i)) == 3) { l--; break; }
5664 : }
5665 : #endif
5666 2052496 : return l-1;
5667 : }
5668 :
5669 : static GEN
5670 38995259 : sqr_primeform(GEN x, ulong p) { return redimag(qfisqr(primeform_u(x, p))); }
5671 : /* return a set of forms hopefully generating Cl(K)^2; set L ~ L(chi_D,1) */
5672 : static GEN
5673 2052496 : get_forms(GEN D, GEN *pL)
5674 : {
5675 2052496 : const long MAXFORM = 20;
5676 2052496 : GEN L, sqrtD = gsqrt(absi_shallow(D),DEFAULTPREC);
5677 2052496 : GEN forms = vectrunc_init(MAXFORM+1);
5678 2052496 : long s, nforms = 0;
5679 : ulong p;
5680 : forprime_t S;
5681 2052496 : L = mulrr(divrr(sqrtD,mppi(DEFAULTPREC)), dbltor(1.005));/*overshoot by 0.5%*/
5682 2052496 : s = itos_or_0( truncr(shiftr(sqrtr(sqrtD), 1)) );
5683 2052496 : if (!s) pari_err_OVERFLOW("classno [discriminant too large]");
5684 2052496 : if (s < 10) s = 200;
5685 1901369 : else if (s < 20) s = 1000;
5686 1477 : else if (s < 5000) s = 5000;
5687 2052496 : u_forprime_init(&S, 2, s);
5688 344232110 : while ( (p = u_forprime_next(&S)) )
5689 : {
5690 340127118 : long d, k = kroiu(D,p);
5691 : pari_sp av2;
5692 340127118 : if (!k) continue;
5693 337897177 : if (k > 0)
5694 : {
5695 169485505 : if (++nforms < MAXFORM) vectrunc_append(forms, sqr_primeform(D,p));
5696 169485505 : d = p-1;
5697 : }
5698 : else
5699 168411672 : d = p+1;
5700 337897177 : av2 = avma; affrr(divru(mulur(p,L),d), L); set_avma(av2);
5701 : }
5702 2052496 : *pL = L; return forms;
5703 : }
5704 :
5705 : /* h ~ #G, return o = order of f, set fao = its factorization */
5706 : static GEN
5707 2052545 : Shanks_order(void *E, GEN f, GEN h, GEN *pfao)
5708 : {
5709 2052545 : long s = minss(itos(sqrti(h)), 10000);
5710 2052545 : GEN T = gen_Shanks_init(f, s, E, &qfi_group);
5711 2052545 : GEN v = gen_Shanks(T, ginv(f), ULONG_MAX, E, &qfi_group);
5712 2052545 : return find_order(E, f, addiu(v,1), pfao);
5713 : }
5714 :
5715 : /* if g = 1 in G/<f> ? */
5716 : static int
5717 518 : equal1(void *E, GEN T, ulong N, GEN g)
5718 518 : { return !!gen_Shanks(T, g, N, E, &qfi_group); }
5719 :
5720 : /* Order of 'a' in G/<f>, T = gen_Shanks_init(f,n), order(f) < n*N
5721 : * FIXME: should be gen_order, but equal1 has the wrong prototype */
5722 : static GEN
5723 112 : relative_order(void *E, GEN a, GEN o, ulong N, GEN T)
5724 : {
5725 112 : pari_sp av = avma;
5726 : long i, l;
5727 : GEN m;
5728 :
5729 112 : m = get_arith_ZZM(o);
5730 112 : if (!m) pari_err_TYPE("gen_order [missing order]",a);
5731 112 : o = gel(m,1);
5732 112 : m = gel(m,2); l = lgcols(m);
5733 322 : for (i = l-1; i; i--)
5734 : {
5735 210 : GEN t, y, p = gcoeff(m,i,1);
5736 210 : long j, e = itos(gcoeff(m,i,2));
5737 210 : if (l == 2) {
5738 35 : t = gen_1;
5739 35 : y = a;
5740 : } else {
5741 175 : t = diviiexact(o, powiu(p,e));
5742 175 : y = powgi(a, t);
5743 : }
5744 210 : if (equal1(E, T,N,y)) o = t;
5745 : else {
5746 126 : for (j = 1; j < e; j++)
5747 : {
5748 28 : y = powgi(y, p);
5749 28 : if (equal1(E, T,N,y)) break;
5750 : }
5751 119 : if (j < e) {
5752 21 : if (j > 1) p = powiu(p, j);
5753 21 : o = mulii(t, p);
5754 : }
5755 : }
5756 : }
5757 112 : return gerepilecopy(av, o);
5758 : }
5759 :
5760 : /* h(x) for x<0 using Baby Step/Giant Step.
5761 : * Assumes G is not too far from being cyclic.
5762 : *
5763 : * Compute G^2 instead of G so as to kill most of the non-cyclicity */
5764 : GEN
5765 2054893 : classno(GEN x)
5766 : {
5767 2054893 : pari_sp av = avma;
5768 : long r2, k, s, i, l;
5769 : GEN forms, hin, Hf, D, g1, d1, d2, q, L, fad1, order_bound;
5770 : void *E;
5771 :
5772 2054893 : if (signe(x) >= 0) return classno2(x);
5773 :
5774 2054886 : check_quaddisc(x, &s, &k, "classno");
5775 2054886 : if (abscmpiu(x,12) <= 0) return gen_1;
5776 :
5777 2052496 : Hf = conductor_part(x, k, &D, NULL);
5778 2052496 : if (abscmpiu(D,12) <= 0) return gerepilecopy(av, Hf);
5779 2052496 : forms = get_forms(D, &L);
5780 2052496 : r2 = two_rank(D);
5781 2052496 : hin = roundr(shiftr(L, -r2)); /* rough approximation for #G, G = Cl(K)^2 */
5782 :
5783 2052496 : l = lg(forms);
5784 2052496 : order_bound = const_vec(l-1, NULL);
5785 2052496 : E = expi(D) > 60? (void*)sqrtnint(shifti(absi_shallow(D),-2),4): NULL;
5786 2052496 : g1 = gel(forms,1);
5787 2052496 : gel(order_bound,1) = d1 = Shanks_order(E, g1, hin, &fad1);
5788 2052496 : q = diviiround(hin, d1); /* approximate order of G/<g1> */
5789 2052496 : d2 = NULL; /* not computed yet */
5790 2052496 : if (is_pm1(q)) goto END;
5791 509036 : for (i=2; i < l; i++)
5792 : {
5793 502268 : GEN o, fao, a, F, fd, f = gel(forms,i);
5794 502268 : fd = powgi(f, d1); if (is_pm1(gel(fd,1))) continue;
5795 362162 : F = powgi(fd, q);
5796 362162 : a = gel(F,1);
5797 362162 : o = is_pm1(a)? find_order(E, fd, q, &fao): Shanks_order(E, fd, q, &fao);
5798 : /* f^(d1 q) = 1 */
5799 362162 : fao = merge_factor(fad1,fao, (void*)&cmpii, &cmp_nodata);
5800 362162 : o = find_order(E, f, fao, &fao);
5801 362162 : gel(order_bound,i) = o;
5802 : /* o = order of f, fao = factor(o) */
5803 362162 : update_g1(&g1,&d1,&fad1, f,o,fao);
5804 362162 : q = diviiround(hin, d1);
5805 362162 : if (is_pm1(q)) goto END;
5806 : }
5807 : /* very probably d1 = expo(Cl^2(K)), q ~ #Cl^2(K) / d1 */
5808 6768 : if (expi(q) > 3)
5809 : { /* q large: compute d2, 2nd elt divisor */
5810 70 : ulong N, n = 2*itou(sqrti(d1));
5811 70 : GEN D = d1, T = gen_Shanks_init(g1, n, E, &qfi_group);
5812 70 : d2 = gen_1;
5813 70 : N = itou( gceil(gdivgs(d1,n)) ); /* order(g1) <= n*N */
5814 287 : for (i = 1; i < l; i++)
5815 : {
5816 280 : GEN d, f = gel(forms,i), B = gel(order_bound,i);
5817 280 : if (!B) B = find_order(E, f, fad1, /*junk*/&d);
5818 280 : f = powgi(f,d2);
5819 280 : if (equal1(E, T,N,f)) continue;
5820 112 : B = gdiv(B,d2); if (typ(B) == t_FRAC) B = gel(B,1);
5821 : /* f^B = 1 */
5822 112 : d = relative_order(E, f, B, N,T);
5823 112 : d2= mulii(d,d2);
5824 112 : D = mulii(d1,d2);
5825 112 : q = diviiround(hin,D);
5826 112 : if (is_pm1(q)) { d1 = D; goto END; }
5827 : }
5828 : /* very probably, d2 is the 2nd elementary divisor */
5829 7 : d1 = D; /* product of first two elt divisors */
5830 : }
5831 : /* impose q | d2^oo (d1^oo if d2 not computed), and compatible with known
5832 : * 2-rank */
5833 6705 : if (!ok_q(q,d1,d2,r2))
5834 : {
5835 0 : GEN q0 = q;
5836 : long d;
5837 0 : if (cmpii(mulii(q,d1), hin) < 0)
5838 : { /* try q = q0+1,-1,+2,-2 */
5839 0 : d = 1;
5840 0 : do { q = addis(q0,d); d = d>0? -d: 1-d; } while(!ok_q(q,d1,d2,r2));
5841 : }
5842 : else
5843 : { /* q0-1,+1,-2,+2 */
5844 0 : d = -1;
5845 0 : do { q = addis(q0,d); d = d<0? -d: -1-d; } while(!ok_q(q,d1,d2,r2));
5846 : }
5847 : }
5848 6705 : d1 = mulii(d1,q);
5849 :
5850 : END:
5851 2052496 : return gerepileuptoint(av, shifti(mulii(d1,Hf), r2));
5852 : }
5853 :
5854 : GEN
5855 0 : quadclassno(GEN x)
5856 : {
5857 0 : pari_sp av = avma;
5858 : GEN Hf, D;
5859 : long s, r;
5860 0 : check_quaddisc(x, &s, &r, "quadclassno");
5861 0 : if (s < 0 && abscmpiu(x,12) <= 0) return gen_1;
5862 0 : Hf = conductor_part(x, r, &D, NULL);
5863 0 : return gerepileuptoint(av, mulii(Hf, gel(quadclassunit0(D,0,NULL,0),1)));
5864 : }
5865 :
5866 : /* use Euler products */
5867 : GEN
5868 21 : classno2(GEN x)
5869 : {
5870 21 : pari_sp av = avma;
5871 21 : const long prec = DEFAULTPREC;
5872 : long n, i, r, s;
5873 : GEN p1, p2, S, p4, p5, p7, Hf, Pi, reg, logd, d, dr, D, half;
5874 :
5875 21 : check_quaddisc(x, &s, &r, "classno2");
5876 21 : if (s < 0 && abscmpiu(x,12) <= 0) return gen_1;
5877 :
5878 21 : Hf = conductor_part(x, r, &D, ®);
5879 21 : if (s < 0 && abscmpiu(D,12) <= 0) return gerepilecopy(av, Hf); /* |D| < 12*/
5880 :
5881 21 : Pi = mppi(prec);
5882 21 : d = absi_shallow(D); dr = itor(d, prec);
5883 21 : logd = logr_abs(dr);
5884 21 : p1 = sqrtr(divrr(mulir(d,logd), gmul2n(Pi,1)));
5885 21 : if (s > 0)
5886 : {
5887 14 : GEN invlogd = invr(logd);
5888 14 : p2 = subsr(1, shiftr(mulrr(logr_abs(reg),invlogd),1));
5889 14 : if (cmprr(sqrr(p2), shiftr(invlogd,1)) >= 0) p1 = mulrr(p2,p1);
5890 : }
5891 21 : n = itos_or_0( mptrunc(p1) );
5892 21 : if (!n) pari_err_OVERFLOW("classno [discriminant too large]");
5893 :
5894 21 : p4 = divri(Pi,d);
5895 21 : p7 = invr(sqrtr_abs(Pi));
5896 21 : half = real2n(-1, prec);
5897 21 : if (s > 0)
5898 : { /* i = 1, shortcut */
5899 14 : p1 = sqrtr_abs(dr);
5900 14 : p5 = subsr(1, mulrr(p7,incgamc(half,p4,prec)));
5901 14 : S = addrr(mulrr(p1,p5), eint1(p4,prec));
5902 546 : for (i=2; i<=n; i++)
5903 : {
5904 532 : long k = kroiu(D,i); if (!k) continue;
5905 434 : p2 = mulir(sqru(i), p4);
5906 434 : p5 = subsr(1, mulrr(p7,incgamc(half,p2,prec)));
5907 434 : p5 = addrr(divru(mulrr(p1,p5),i), eint1(p2,prec));
5908 434 : S = (k>0)? addrr(S,p5): subrr(S,p5);
5909 : }
5910 14 : S = shiftr(divrr(S,reg),-1);
5911 : }
5912 : else
5913 : { /* i = 1, shortcut */
5914 7 : p1 = gdiv(sqrtr_abs(dr), Pi);
5915 7 : p5 = subsr(1, mulrr(p7,incgamc(half,p4,prec)));
5916 7 : S = addrr(p5, divrr(p1, mpexp(p4)));
5917 952 : for (i=2; i<=n; i++)
5918 : {
5919 945 : long k = kroiu(D,i); if (!k) continue;
5920 945 : p2 = mulir(sqru(i), p4);
5921 945 : p5 = subsr(1, mulrr(p7,incgamc(half,p2,prec)));
5922 945 : p5 = addrr(p5, divrr(p1, mulur(i, mpexp(p2))));
5923 945 : S = (k>0)? addrr(S,p5): subrr(S,p5);
5924 : }
5925 : }
5926 21 : return gerepileuptoint(av, mulii(Hf, roundr(S)));
5927 : }
5928 :
5929 : /* 1 + q + ... + q^v, v > 0 */
5930 : static GEN
5931 120 : geomsumu(ulong q, long v)
5932 : {
5933 120 : GEN u = utoipos(1+q);
5934 120 : for (; v > 1; v--) u = addui(1, mului(q, u));
5935 120 : return u;
5936 : }
5937 : static GEN
5938 120 : geomsum(GEN q, long v)
5939 : {
5940 : GEN u;
5941 120 : if (lgefint(q) == 3) return geomsumu(q[2], v);
5942 0 : u = addiu(q,1);
5943 0 : for (; v > 1; v--) u = addui(1, mulii(q, u));
5944 0 : return u;
5945 : }
5946 :
5947 : static GEN
5948 7810 : hclassno6_large(GEN x)
5949 : {
5950 : long i, l, s, xmod4;
5951 : GEN Q, H, D, P, E;
5952 :
5953 7810 : x = negi(x);
5954 7810 : check_quaddisc(x, &s, &xmod4, "hclassno");
5955 7810 : corediscfact(x, xmod4, &D, &P, &E);
5956 :
5957 7810 : Q = quadclassunit0(D, 0, NULL, 0);
5958 7810 : H = gel(Q,1); l = lg(P);
5959 :
5960 : /* H \prod_{p^e||f} (1 + (p^e-1)/(p-1))[ p - (D/p) ] */
5961 33682 : for (i=1; i<l; i++)
5962 : {
5963 25872 : long e = E[i], s;
5964 : GEN p, t;
5965 25872 : if (!e) continue;
5966 5003 : p = gel(P,i); s = kronecker(D,p);
5967 5003 : if (e == 1) t = addiu(p, 1-s);
5968 1000 : else if (s == 1) t = powiu(p,e);
5969 120 : else t = addui(1, mulii(subis(p, s), geomsum(p,e-1)));
5970 5003 : H = mulii(H,t);
5971 : }
5972 7810 : switch( itou_or_0(D) )
5973 : {
5974 0 : case 3: H = shifti(H,1);break;
5975 0 : case 4: H = muliu(H,3); break;
5976 7810 : default:H = muliu(H,6); break;
5977 : }
5978 7810 : return H;
5979 : }
5980 :
5981 : /* x > 0, x = 0,3 (mod 4). Return 6*hclassno(x), an integer */
5982 : GEN
5983 121905 : hclassno6(GEN x)
5984 : {
5985 121905 : ulong d = itou_or_0(x);
5986 121905 : if (!d || d > 500000) return hclassno6_large(x);
5987 114095 : return utoipos(hclassno6u(d));
5988 : }
5989 :
5990 : GEN
5991 46123 : hclassno(GEN x)
5992 : {
5993 : long a, s;
5994 46123 : if (typ(x) != t_INT) pari_err_TYPE("hclassno",x);
5995 46123 : s = signe(x);
5996 46123 : if (s < 0) return gen_0;
5997 46123 : if (!s) return gdivgs(gen_1, -12);
5998 46123 : a = mod4(x); if (a == 1 || a == 2) return gen_0;
5999 46123 : return gdivgs(hclassno6(x), 6);
6000 : }
6001 : /******************************************************************/
6002 : /* */
6003 : /* RAMANUJAN's TAU FUNCTION */
6004 : /* */
6005 : /******************************************************************/
6006 : /* 4|N > 0, not fundamental at 2; 6 * Hurwitz class number in level 2,
6007 : * equal to 6*(H(N)+2H(N/4)), H=qfbhclassno */
6008 : static GEN
6009 36750 : Hspec(GEN N)
6010 : {
6011 36750 : long v2 = Z_lvalrem(N, 2, &N), v2f = v2 >> 1;
6012 : GEN t;
6013 36750 : if (odd(v2)) { v2f--; N = shifti(N,3); }
6014 32557 : else if (mod4(N)!=3) { v2f--; N = shifti(N,2); }
6015 : /* N fundamental at 2, v2f = v2(f) s.t. N = f^2 D, D fundamental */
6016 36750 : t = addui(3, muliu(subiu(int2n(v2f+1), 3), 2 - kroiu(N,2)));
6017 36750 : return mulii(t, hclassno6(N));
6018 : }
6019 :
6020 : /* Ramanujan tau function for p prime */
6021 : static GEN
6022 14903 : tauprime(GEN p)
6023 : {
6024 14903 : pari_sp av = avma, av2;
6025 : GEN s, p2, p2_7, p_9, T;
6026 : ulong lim, t, tin;
6027 :
6028 14903 : if (absequaliu(p, 2)) return utoineg(24);
6029 : /* p > 2 */
6030 11396 : p2 = sqri(p);
6031 11396 : p2_7 = mului(7, p2);
6032 11396 : p_9 = mului(9, p);
6033 11396 : av2 = avma;
6034 11396 : lim = itou(sqrtint(p));
6035 11396 : tin = mod4(p) == 3? 1: 0;
6036 11396 : s = gen_0;
6037 87178 : for (t = 1; t <= lim; ++t)
6038 : {
6039 75782 : GEN h, a, t2 = sqru(t), D = shifti(subii(p, t2), 2); /* 4(p-t^2) */
6040 : /* t mod 2 != tin <=> D not fundamental at 2 */
6041 75782 : h = ((t&1UL) == tin)? hclassno6(D): Hspec(D);
6042 75782 : a = mulii(powiu(t2,3), addii(p2_7, mulii(t2, subii(shifti(t2,2), p_9))));
6043 75782 : s = addii(s, mulii(a,h));
6044 75782 : if (!(t & 255)) s = gerepileuptoint(av2, s);
6045 : }
6046 : /* 28p^3 - 28p^2 - 90p - 35 */
6047 11396 : T = subii(shifti(mulii(p2_7, subiu(p,1)), 2), addiu(mului(90,p), 35));
6048 11396 : s = shifti(diviuexact(s, 3), 6);
6049 11396 : return gerepileuptoint(av, subii(mulii(mulii(p2,p),T), addui(1, s)));
6050 : }
6051 :
6052 : /* Ramanujan tau function, return 0 for <= 0 */
6053 : GEN
6054 7035 : ramanujantau(GEN n)
6055 : {
6056 7035 : pari_sp ltop = avma;
6057 : GEN T, F, P, E;
6058 : long j, lP;
6059 :
6060 7035 : if (!(F = check_arith_all(n,"ramanujantau")))
6061 : {
6062 7014 : if (signe(n) <= 0) return gen_0;
6063 7007 : F = Z_factor(n);
6064 : }
6065 : else
6066 : {
6067 21 : P = gel(F,1);
6068 21 : if (lg(P) == 1 || signe(gel(P,1)) <= 0) return gen_0;
6069 : }
6070 :
6071 7014 : P = gel(F,1);
6072 7014 : E = gel(F,2); lP = lg(P);
6073 7014 : T = gen_1;
6074 21917 : for (j = 1; j < lP; j++)
6075 : {
6076 14903 : GEN p = gel(P,j), tp = tauprime(p), t1 = tp, t0 = gen_1;
6077 14903 : long k, e = itou(gel(E,j));
6078 20160 : for (k = 1; k < e; k++)
6079 : {
6080 5257 : GEN t2 = subii(mulii(tp, t1), mulii(powiu(p, 11), t0));
6081 5257 : t0 = t1; t1 = t2;
6082 : }
6083 14903 : T = mulii(T, t1);
6084 : }
6085 7014 : return gerepileuptoint(ltop, T);
6086 : }
|