Line data Source code
1 : /* Copyright (C) 2000-2003 The PARI group.
2 :
3 : This file is part of the PARI/GP package.
4 :
5 : PARI/GP is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 2 of the License, or (at your option) any later
8 : version. It is distributed in the hope that it will be useful, but WITHOUT
9 : ANY WARRANTY WHATSOEVER.
10 :
11 : Check the License for details. You should have received a copy of it, along
12 : with the package; see the file 'COPYING'. If not, write to the Free Software
13 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 :
15 : #include "pari.h"
16 : #include "paripriv.h"
17 :
18 : #define DEBUGLEVEL DEBUGLEVEL_galois
19 :
20 : /*************************************************************************/
21 : /** **/
22 : /** GALOIS CONJUGATES **/
23 : /** **/
24 : /*************************************************************************/
25 :
26 : static int
27 10976 : is2sparse(GEN x)
28 : {
29 10976 : long i, l = lg(x);
30 10976 : if (odd(l-3)) return 0;
31 32886 : for(i=3; i<l; i+=2)
32 22085 : if (signe(gel(x,i))) return 0;
33 10801 : return 1;
34 : }
35 :
36 : static GEN
37 35944 : galoisconj1(GEN nf)
38 : {
39 35944 : GEN x = get_nfpol(nf, &nf), f = nf? nf : x, y, z;
40 35944 : long i, lz, v = varn(x), nbmax;
41 35944 : pari_sp av = avma;
42 35944 : RgX_check_ZX(x, "nfgaloisconj");
43 35944 : nbmax = numberofconjugates(x, 2);
44 35945 : if (nbmax==1) retmkcol(pol_x(v));
45 11613 : if (nbmax==2 && is2sparse(x))
46 : {
47 10801 : GEN res = cgetg(3,t_COL);
48 10801 : gel(res,1) = deg1pol_shallow(gen_m1, gen_0, v);
49 10801 : gel(res,2) = pol_x(v);
50 10801 : return res;
51 : }
52 812 : x = leafcopy(x); setvarn(x, fetch_var_higher());
53 812 : z = nfroots(f, x); lz = lg(z);
54 812 : y = cgetg(lz, t_COL);
55 3913 : for (i = 1; i < lz; i++)
56 : {
57 3101 : GEN t = lift(gel(z,i));
58 3101 : if (typ(t) == t_POL) setvarn(t, v);
59 3101 : gel(y,i) = t;
60 : }
61 812 : (void)delete_var();
62 812 : return gerepileupto(av, y);
63 : }
64 :
65 : /*************************************************************************/
66 : /** **/
67 : /** GALOISCONJ4 **/
68 : /** **/
69 : /*************************************************************************/
70 : /*DEBUGLEVEL:
71 : 1: timing
72 : 2: outline
73 : 4: complete outline
74 : 6: detail
75 : 7: memory
76 : 9: complete detail
77 : */
78 : struct galois_borne {
79 : GEN l;
80 : long valsol;
81 : long valabs;
82 : GEN bornesol;
83 : GEN ladicsol;
84 : GEN ladicabs;
85 : GEN dis;
86 : };
87 : struct galois_lift {
88 : GEN T;
89 : GEN den;
90 : GEN p;
91 : GEN L;
92 : GEN Lden;
93 : long e;
94 : GEN Q;
95 : GEN TQ;
96 : struct galois_borne *gb;
97 : };
98 : struct galois_testlift {
99 : long n;
100 : long f;
101 : long g;
102 : GEN bezoutcoeff;
103 : GEN pauto;
104 : GEN C;
105 : GEN Cd;
106 : };
107 : struct galois_test { /* data for permutation test */
108 : GEN order; /* order of tests pour galois_test_perm */
109 : GEN borne, lborne; /* coefficient bounds */
110 : GEN ladic;
111 : GEN PV; /* NULL or vector of test matrices (Vmatrix) */
112 : GEN TM; /* transpose of M */
113 : GEN L; /* p-adic roots, known mod ladic */
114 : GEN M; /* vandermonde inverse */
115 : };
116 : /* result of the study of Frobenius degrees */
117 : enum ga_code {ga_all_normal=1,ga_ext_2=2,ga_non_wss=4,
118 : ga_all_nilpotent=8,ga_easy=16};
119 : struct galois_analysis {
120 : long p; /* prime to be lifted */
121 : long deg; /* degree of the lift */
122 : long ord;
123 : long l; /* l: prime number such that T is totally split mod l */
124 : long p4;
125 : long group;
126 : };
127 : struct galois_frobenius {
128 : long p;
129 : long fp;
130 : long deg;
131 : GEN Tmod;
132 : GEN psi;
133 : };
134 :
135 : /* #r = r1 + r2 */
136 : GEN
137 11532 : embed_roots(GEN ro, long r1)
138 : {
139 11532 : long r2 = lg(ro)-1-r1;
140 : GEN L;
141 11532 : if (!r2) L = ro;
142 : else
143 : {
144 5547 : long i,j, N = r1+2*r2;
145 5547 : L = cgetg(N+1, t_VEC);
146 6958 : for (i = 1; i <= r1; i++) gel(L,i) = gel(ro,i);
147 16535 : for (j = i; j <= N; i++)
148 : {
149 10988 : GEN z = gel(ro,i);
150 10988 : gel(L,j++) = z;
151 10988 : gel(L,j++) = mkcomplex(gel(z,1), gneg(gel(z,2)));
152 : }
153 : }
154 11532 : return L;
155 : }
156 : GEN
157 136364 : embed_disc(GEN z, long r1, long prec)
158 : {
159 136364 : pari_sp av = avma;
160 136364 : GEN t = real_1(prec);
161 136366 : long i, j, n = lg(z)-1, r2 = n-r1;
162 231524 : for (i = 1; i < r1; i++)
163 : {
164 95158 : GEN zi = gel(z,i);
165 665294 : for (j = i+1; j <= r1; j++) t = gmul(t, gsub(zi, gel(z,j)));
166 : }
167 719671 : for (j = r1+1; j <= n; j++)
168 : {
169 583328 : GEN zj = gel(z,j), a = gel(zj,1), b = gel(zj,2), b2 = gsqr(b);
170 600494 : for (i = 1; i <= r1; i++)
171 : {
172 17192 : GEN zi = gel(z,i);
173 17192 : t = gmul(t, gadd(gsqr(gsub(zi, a)), b2));
174 : }
175 583302 : t = gmul(t, b);
176 : }
177 136343 : if (r2) t = gmul2n(t, r2);
178 136348 : if (r2 > 1)
179 : {
180 124420 : GEN T = real_1(prec);
181 581775 : for (i = r1+1; i < n; i++)
182 : {
183 457363 : GEN zi = gel(z,i), a = gel(zi,1), b = gel(zi,2);
184 1963990 : for (j = i+1; j <= n; j++)
185 : {
186 1506635 : GEN zj = gel(z,j), c = gel(zj,1), d = gel(zj,2);
187 1506635 : GEN f = gsqr(gsub(a,c)), g = gsqr(gsub(b,d)), h = gsqr(gadd(b,d));
188 1506645 : T = gmul(T, gmul(gadd(f,g), gadd(f,h)));
189 : }
190 : }
191 124412 : t = gmul(t, T);
192 : }
193 136349 : t = gsqr(t);
194 136363 : if (odd(r2)) t = gneg(t);
195 136364 : return gerepileupto(av, t);
196 : }
197 :
198 : /* Compute bound for the coefficients of automorphisms.
199 : * T a ZX, den a t_INT denominator or NULL */
200 : GEN
201 84025 : initgaloisborne(GEN T, GEN den, long prec, GEN *pL, GEN *pprep, GEN *pD)
202 : {
203 : GEN L, prep, nf, r;
204 : pari_timer ti;
205 :
206 84025 : if (DEBUGLEVEL>=4) timer_start(&ti);
207 84025 : T = get_nfpol(T, &nf);
208 84026 : r = nf ? nf_get_roots(nf) : NULL;
209 84026 : if (nf && precision(gel(r, 1)) >= prec)
210 11532 : L = embed_roots(r, nf_get_r1(nf));
211 : else
212 72494 : L = QX_complex_roots(T, prec);
213 84027 : if (DEBUGLEVEL>=4) timer_printf(&ti,"roots");
214 84027 : prep = vandermondeinverseinit(L);
215 84023 : if (!den || pD)
216 : {
217 61851 : GEN res = RgV_prod(gabs(prep,prec));
218 61851 : GEN D = ZX_disc_all(T, 1 + gexpo(res)); /* +1 for safety */
219 61853 : if (pD) *pD = D;
220 61853 : if (!den) den = indexpartial(T,D);
221 : }
222 84025 : if (pprep) *pprep = prep;
223 84025 : *pL = L; return den;
224 : }
225 :
226 : /* ||| M ||| with respect to || x ||_oo, M t_MAT */
227 : GEN
228 422845 : matrixnorm(GEN M, long prec)
229 : {
230 422845 : long i,j,m, l = lg(M);
231 422845 : GEN B = real_0(prec);
232 :
233 422844 : if (l == 1) return B;
234 422844 : m = lgcols(M);
235 1535091 : for (i = 1; i < m; i++)
236 : {
237 1112251 : GEN z = gabs(gcoeff(M,i,1), prec);
238 5415113 : for (j = 2; j < l; j++) z = gadd(z, gabs(gcoeff(M,i,j), prec));
239 1112236 : if (gcmp(z, B) > 0) B = z;
240 : }
241 422840 : return B;
242 : }
243 :
244 : static GEN
245 31181 : galoisborne(GEN T, GEN dn, struct galois_borne *gb, long d)
246 : {
247 : pari_sp ltop, av2;
248 : GEN borne, borneroots, bornetrace, borneabs;
249 : long prec;
250 : GEN L, M, prep, den;
251 : pari_timer ti;
252 31181 : const long step=3;
253 :
254 31181 : prec = nbits2prec(bit_accuracy(ZX_max_lg(T)));
255 31181 : den = initgaloisborne(T,dn,prec, &L,&prep,&gb->dis);
256 31180 : if (!dn) dn = den;
257 31180 : ltop = avma;
258 31180 : if (DEBUGLEVEL>=4) timer_start(&ti);
259 31180 : M = vandermondeinverse(L, RgX_gtofp(T, prec), den, prep);
260 31181 : if (DEBUGLEVEL>=4) timer_printf(&ti,"vandermondeinverse");
261 31181 : borne = matrixnorm(M, prec);
262 31181 : borneroots = gsupnorm(L, prec); /*t_REAL*/
263 31181 : bornetrace = mulur((2*step)*degpol(T)/d,
264 31181 : powru(borneroots, minss(degpol(T), step)));
265 31180 : borneroots = ceil_safe(gmul(borne, borneroots));
266 31180 : borneabs = ceil_safe(gmax_shallow(gmul(borne, bornetrace),
267 : powru(bornetrace, d)));
268 31181 : av2 = avma;
269 : /*We use d-1 test, so we must overlift to 2^BITS_IN_LONG*/
270 31181 : gb->valsol = logint(shifti(borneroots,2+BITS_IN_LONG), gb->l) + 1;
271 31178 : gb->valabs = logint(shifti(borneabs,2), gb->l) + 1;
272 31181 : gb->valabs = maxss(gb->valsol, gb->valabs);
273 31181 : if (DEBUGLEVEL >= 4)
274 0 : err_printf("GaloisConj: val1=%ld val2=%ld\n", gb->valsol, gb->valabs);
275 31181 : set_avma(av2);
276 31181 : gb->bornesol = gerepileuptoint(ltop, shifti(borneroots,1));
277 31181 : if (DEBUGLEVEL >= 9)
278 0 : err_printf("GaloisConj: Bound %Ps\n",borneroots);
279 31181 : gb->ladicsol = powiu(gb->l, gb->valsol);
280 31181 : gb->ladicabs = powiu(gb->l, gb->valabs);
281 31180 : return dn;
282 : }
283 :
284 : static GEN
285 29725 : makeLden(GEN L,GEN den, struct galois_borne *gb)
286 29725 : { return FpC_Fp_mul(L, den, gb->ladicsol); }
287 :
288 : /* Initialize the galois_lift structure */
289 : static void
290 29830 : initlift(GEN T, GEN den, ulong p, GEN L, GEN Lden, struct galois_borne *gb, struct galois_lift *gl)
291 : {
292 : pari_sp av;
293 : long e;
294 29830 : gl->gb = gb;
295 29830 : gl->T = T;
296 29830 : gl->den = is_pm1(den)? gen_1: den;
297 29830 : gl->p = utoipos(p);
298 29830 : gl->L = L;
299 29830 : gl->Lden = Lden;
300 29830 : av = avma;
301 29830 : e = logint(shifti(gb->bornesol, 2+BITS_IN_LONG), gl->p) + 1;
302 29827 : set_avma(av);
303 29828 : if (e < 2) e = 2;
304 29828 : gl->e = e;
305 29828 : gl->Q = powuu(p, e);
306 29827 : gl->TQ = FpX_red(T,gl->Q);
307 29827 : }
308 :
309 : /* Check whether f is (with high probability) a solution and compute its
310 : * permutation */
311 : static int
312 65667 : poltopermtest(GEN f, struct galois_lift *gl, GEN pf)
313 : {
314 : pari_sp av;
315 65667 : GEN fx, fp, B = gl->gb->bornesol;
316 : long i, j, ll;
317 283738 : for (i = 2; i < lg(f); i++)
318 226343 : if (abscmpii(gel(f,i),B) > 0)
319 : {
320 8272 : if (DEBUGLEVEL>=4) err_printf("GaloisConj: Solution too large.\n");
321 8272 : if (DEBUGLEVEL>=8) err_printf("f=%Ps\n borne=%Ps\n",f,B);
322 8272 : return 0;
323 : }
324 57395 : ll = lg(gl->L);
325 57395 : fp = const_vecsmall(ll-1, 1); /* left on stack */
326 57395 : av = avma;
327 283935 : for (i = 1; i < ll; i++, set_avma(av))
328 : {
329 226713 : fx = FpX_eval(f, gel(gl->L,i), gl->gb->ladicsol);
330 1246978 : for (j = 1; j < ll; j++)
331 1246822 : if (fp[j] && equalii(fx, gel(gl->Lden,j))) { pf[i]=j; fp[j]=0; break; }
332 226699 : if (j == ll) return 0;
333 : }
334 57233 : return 1;
335 : }
336 :
337 : static long
338 60252 : galoisfrobeniustest(GEN aut, struct galois_lift *gl, GEN frob)
339 : {
340 60252 : pari_sp av = avma;
341 60252 : GEN tlift = aut;
342 60252 : if (gl->den != gen_1) tlift = FpX_Fp_mul(tlift, gl->den, gl->Q);
343 60254 : tlift = FpX_center_i(tlift, gl->Q, shifti(gl->Q,-1));
344 60254 : return gc_long(av, poltopermtest(tlift, gl, frob));
345 : }
346 :
347 : static GEN
348 64070 : monoratlift(void *E, GEN S, GEN q)
349 : {
350 64070 : pari_sp ltop = avma;
351 64070 : struct galois_lift *gl = (struct galois_lift *) E;
352 64070 : GEN qm1 = sqrti(shifti(q,-2)), N = gl->Q;
353 64067 : GEN tlift = FpX_ratlift(S, q, qm1, qm1, gl->den);
354 64070 : if (tlift)
355 : {
356 27195 : pari_sp ltop = avma;
357 27195 : GEN frob = cgetg(lg(gl->L), t_VECSMALL);
358 27195 : if(DEBUGLEVEL>=4)
359 0 : err_printf("MonomorphismLift: trying early solution %Ps\n",tlift);
360 27195 : if (gl->den != gen_1)
361 23381 : tlift = FpX_Fp_mul(FpX_red(Q_muli_to_int(tlift, gl->den), N),
362 : Fp_inv(gl->den, N), N);
363 27193 : if (galoisfrobeniustest(tlift, gl, frob))
364 : {
365 27035 : if(DEBUGLEVEL>=4) err_printf("MonomorphismLift: true early solution.\n");
366 27035 : return gerepilecopy(ltop, tlift);
367 : }
368 159 : if(DEBUGLEVEL>=4) err_printf("MonomorphismLift: false early solution.\n");
369 : }
370 37034 : set_avma(ltop);
371 37036 : return NULL;
372 : }
373 :
374 : static GEN
375 31764 : monomorphismratlift(GEN P, GEN S, struct galois_lift *gl)
376 : {
377 : pari_timer ti;
378 31764 : if (DEBUGLEVEL >= 1) timer_start(&ti);
379 31764 : S = ZpX_ZpXQ_liftroot_ea(P,S,gl->T,gl->p, gl->e, (void*)gl, monoratlift);
380 31765 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "monomorphismlift()");
381 31765 : return S;
382 : }
383 :
384 : /* Let T be a polynomial in Z[X] , p a prime number, S in Fp[X]/(T) so
385 : * that T(S)=0 [p,T]. Lift S in S_0 so that T(S_0)=0 [T,p^e]
386 : * Unclean stack */
387 : static GEN
388 31764 : automorphismlift(GEN S, struct galois_lift *gl)
389 : {
390 31764 : return monomorphismratlift(gl->T, S, gl);
391 : }
392 :
393 : static GEN
394 29828 : galoisdolift(struct galois_lift *gl)
395 : {
396 29828 : pari_sp av = avma;
397 29828 : GEN Tp = FpX_red(gl->T, gl->p);
398 29825 : GEN S = FpX_Frobenius(Tp, gl->p);
399 29829 : return gerepileupto(av, automorphismlift(S, gl));
400 : }
401 :
402 : static GEN
403 1347 : galoisdoliftn(struct galois_lift *gl, long e)
404 : {
405 1347 : pari_sp av = avma;
406 1347 : GEN Tp = FpX_red(gl->T, gl->p);
407 1347 : GEN S = FpXQ_autpow(FpX_Frobenius(Tp, gl->p), e, Tp, gl->p);
408 1347 : return gerepileupto(av, automorphismlift(S, gl));
409 : }
410 :
411 : static ulong
412 73 : findpsi(GEN D, ulong pstart, GEN P, GEN S, long o, GEN *Tmod, GEN *Tpsi)
413 : {
414 : forprime_t iter;
415 : ulong p;
416 73 : long n = degpol(P), i, j, g = n/o;
417 73 : GEN psi = cgetg(g+1, t_VECSMALL);
418 73 : u_forprime_init(&iter, pstart, ULONG_MAX);
419 2220 : while ((p = u_forprime_next(&iter)))
420 : {
421 : GEN F, Sp;
422 2220 : long gp = 0;
423 2220 : if (smodis(D, p) == 0)
424 196 : continue;
425 2024 : F = gel(Flx_factor(ZX_to_Flx(P, p), p), 1);
426 2024 : if (lg(F)-1 != g) continue;
427 701 : Sp = RgX_to_Flx(S, p);
428 1806 : for (j = 1; j <= g; j++)
429 : {
430 1679 : GEN Fj = gel(F, j);
431 1679 : GEN Sj = Flx_rem(Sp, Fj, p);
432 1679 : GEN A = Flxq_autpowers(Flx_Frobenius(Fj, p), o, Fj, p);
433 5732 : for (i = 1; i <= o; i++)
434 5158 : if (gequal(Sj, gel(A,i+1)))
435 : {
436 1105 : psi[j] = i; break;
437 : }
438 1679 : if (i > o) break;
439 1105 : if (gp==0 && i==1) gp=j;
440 : }
441 701 : if (gp && j > g)
442 : {
443 : /* Normalize result so that psi[l]=1 */
444 73 : if (gp!=1)
445 : {
446 7 : swap(gel(F,1),gel(F,gp));
447 7 : lswap(uel(psi,1),uel(psi,gp));
448 : }
449 73 : *Tpsi = Flv_Fl_div(psi,psi[g],o);
450 73 : *Tmod = FlxV_to_ZXV(F);
451 73 : return p;
452 : }
453 : }
454 0 : return 0;
455 : }
456 :
457 : static void
458 1771 : inittestlift(GEN plift, GEN Tmod, struct galois_lift *gl,
459 : struct galois_testlift *gt)
460 : {
461 : pari_timer ti;
462 1771 : gt->n = lg(gl->L) - 1;
463 1771 : gt->g = lg(Tmod) - 1;
464 1771 : gt->f = gt->n / gt->g;
465 1771 : gt->bezoutcoeff = bezout_lift_fact(gl->T, Tmod, gl->p, gl->e);
466 1771 : if (DEBUGLEVEL >= 2) timer_start(&ti);
467 1771 : gt->pauto = FpXQ_autpowers(plift, gt->f-1, gl->TQ, gl->Q);
468 1771 : if (DEBUGLEVEL >= 2) timer_printf(&ti, "Frobenius power");
469 1771 : }
470 :
471 : /* Explanation of the intheadlong technique:
472 : * Let C be a bound, B = BITS_IN_LONG, M > C*2^B a modulus and 0 <= a_i < M for
473 : * i=1,...,n where n < 2^B. We want to test if there exist k,l, |k| < C < M/2^B,
474 : * such that sum a_i = k + l*M
475 : * We write a_i*2^B/M = b_i+c_i with b_i integer and 0<=c_i<1, so that
476 : * sum b_i - l*2^B = k*2^B/M - sum c_i
477 : * Since -1 < k*2^B/M < 1 and 0<=c_i<1, it follows that
478 : * -n-1 < sum b_i - l*2^B < 1 i.e. -n <= sum b_i -l*2^B <= 0
479 : * So we compute z = - sum b_i [mod 2^B] and check if 0 <= z <= n. */
480 :
481 : /* Assume 0 <= x < mod. */
482 : static ulong
483 1360944 : intheadlong(GEN x, GEN mod)
484 : {
485 1360944 : pari_sp av = avma;
486 1360944 : long res = (long) itou(divii(shifti(x,BITS_IN_LONG),mod));
487 1360945 : return gc_long(av,res);
488 : }
489 : static GEN
490 58329 : vecheadlong(GEN W, GEN mod)
491 : {
492 58329 : long i, l = lg(W);
493 58329 : GEN V = cgetg(l, t_VECSMALL);
494 1380348 : for(i=1; i<l; i++) V[i] = intheadlong(gel(W,i), mod);
495 58329 : return V;
496 : }
497 : static GEN
498 5687 : matheadlong(GEN W, GEN mod)
499 : {
500 5687 : long i, l = lg(W);
501 5687 : GEN V = cgetg(l,t_MAT);
502 64016 : for(i=1; i<l; i++) gel(V,i) = vecheadlong(gel(W,i), mod);
503 5687 : return V;
504 : }
505 : static ulong
506 38926 : polheadlong(GEN P, long n, GEN mod)
507 : {
508 38926 : return (lg(P)>n+2)? intheadlong(gel(P,n+2),mod): 0;
509 : }
510 :
511 : #define headlongisint(Z,N) (-(ulong)(Z)<=(ulong)(N))
512 :
513 : static long
514 2016 : frobeniusliftall(GEN sg, long el, GEN *psi, struct galois_lift *gl,
515 : struct galois_testlift *gt, GEN frob)
516 : {
517 2016 : pari_sp av, ltop2, ltop = avma;
518 2016 : long i,j,k, c = lg(sg)-1, n = lg(gl->L)-1, m = gt->g, d = m / c;
519 : GEN pf, u, v, C, Cd, SG, cache;
520 2016 : long N1, N2, R1, Ni, ord = gt->f, c_idx = gt->g-1;
521 : ulong headcache;
522 2016 : long hop = 0;
523 : GEN NN, NQ;
524 : pari_timer ti;
525 :
526 2016 : *psi = pf = cgetg(m, t_VECSMALL);
527 2016 : ltop2 = avma;
528 2016 : NN = diviiexact(mpfact(m), mului(c, powiu(mpfact(d), c)));
529 2016 : if (DEBUGLEVEL >= 4)
530 0 : err_printf("GaloisConj: I will try %Ps permutations\n", NN);
531 2016 : N1=10000000;
532 2016 : NQ=divis_rem(NN,N1,&R1);
533 2016 : if (abscmpiu(NQ,1000000000)>0)
534 : {
535 0 : pari_warn(warner,"Combinatorics too hard : would need %Ps tests!\n"
536 : "I will skip it, but it may induce an infinite loop",NN);
537 0 : *psi = NULL; return gc_long(ltop,0);
538 : }
539 2016 : N2=itos(NQ); if(!N2) N1=R1;
540 2016 : if (DEBUGLEVEL>=4) timer_start(&ti);
541 2016 : set_avma(ltop2);
542 2016 : C = gt->C;
543 2016 : Cd= gt->Cd;
544 2016 : v = FpXQ_mul(gel(gt->pauto, 1+el%ord), gel(gt->bezoutcoeff, m),gl->TQ,gl->Q);
545 2016 : if (gl->den != gen_1) v = FpX_Fp_mul(v, gl->den, gl->Q);
546 2016 : SG = cgetg(lg(sg),t_VECSMALL);
547 6594 : for(i=1; i<lg(SG); i++) SG[i] = (el*sg[i])%ord + 1;
548 2016 : cache = cgetg(m+1,t_VECSMALL); cache[m] = polheadlong(v,1,gl->Q);
549 2016 : headcache = polheadlong(v,2,gl->Q);
550 5334 : for (i = 1; i < m; i++) pf[i] = 1 + i/d;
551 2016 : av = avma;
552 2016 : for (Ni = 0, i = 0; ;i++)
553 : {
554 301496 : for (j = c_idx ; j > 0; j--)
555 : {
556 236875 : long h = SG[pf[j]];
557 236875 : if (!mael(C,h,j))
558 : {
559 5025 : pari_sp av3 = avma;
560 5025 : GEN r = FpXQ_mul(gel(gt->pauto,h), gel(gt->bezoutcoeff,j),gl->TQ,gl->Q);
561 5025 : if (gl->den != gen_1) r = FpX_Fp_mul(r, gl->den, gl->Q);
562 5025 : gmael(C,h,j) = gclone(r);
563 5025 : mael(Cd,h,j) = polheadlong(r,1,gl->Q);
564 5025 : set_avma(av3);
565 : }
566 236875 : uel(cache,j) = uel(cache,j+1)+umael(Cd,h,j);
567 : }
568 64621 : if (headlongisint(uel(cache,1),n))
569 : {
570 3374 : ulong head = headcache;
571 33243 : for (j = 1; j < m; j++) head += polheadlong(gmael(C,SG[pf[j]],j),2,gl->Q);
572 3374 : if (headlongisint(head,n))
573 : {
574 1736 : u = v;
575 4221 : for (j = 1; j < m; j++) u = ZX_add(u, gmael(C,SG[pf[j]],j));
576 1736 : u = FpX_center_i(FpX_red(u, gl->Q), gl->Q, shifti(gl->Q,-1));
577 1736 : if (poltopermtest(u, gl, frob))
578 : {
579 1729 : if (DEBUGLEVEL >= 4)
580 : {
581 0 : timer_printf(&ti, "");
582 0 : err_printf("GaloisConj: %d hops on %Ps tests\n",hop,addis(mulss(Ni,N1),i));
583 : }
584 1729 : return gc_long(ltop2,1);
585 : }
586 7 : if (DEBUGLEVEL >= 4) err_printf("M");
587 : }
588 1638 : else hop++;
589 : }
590 62892 : if (DEBUGLEVEL >= 4 && i % maxss(N1/20, 1) == 0)
591 0 : timer_printf(&ti, "GaloisConj:Testing %Ps", addis(mulss(Ni,N1),i));
592 62892 : set_avma(av);
593 62892 : if (i == N1-1)
594 : {
595 287 : if (Ni==N2-1) N1 = R1;
596 287 : if (Ni==N2) break;
597 0 : Ni++; i = 0;
598 0 : if (DEBUGLEVEL>=4) timer_start(&ti);
599 : }
600 170952 : for (j = 2; j < m && pf[j-1] >= pf[j]; j++)
601 : /*empty*/; /* to kill clang Warning */
602 101722 : for (k = 1; k < j-k && pf[k] != pf[j-k]; k++) { lswap(pf[k], pf[j-k]); }
603 109703 : for (k = j - 1; pf[k] >= pf[j]; k--)
604 : /*empty*/;
605 62605 : lswap(pf[j], pf[k]); c_idx = j;
606 : }
607 287 : if (DEBUGLEVEL>=4) err_printf("GaloisConj: not found, %d hops \n",hop);
608 287 : *psi = NULL; return gc_long(ltop,0);
609 : }
610 :
611 : /* Compute the test matrix for the i-th line of V. Clone. */
612 : static GEN
613 5687 : Vmatrix(long i, struct galois_test *td)
614 : {
615 5687 : pari_sp av = avma;
616 5687 : GEN m = gclone( matheadlong(FpC_FpV_mul(td->L, row(td->M,i), td->ladic), td->ladic));
617 5687 : set_avma(av); return m;
618 : }
619 :
620 : /* Initialize galois_test */
621 : static void
622 5449 : inittest(GEN L, GEN M, GEN borne, GEN ladic, struct galois_test *td)
623 : {
624 5449 : long i, n = lg(L)-1;
625 5449 : GEN p = cgetg(n+1, t_VECSMALL);
626 5449 : if (DEBUGLEVEL >= 8) err_printf("GaloisConj: Init Test\n");
627 5449 : td->order = p;
628 44858 : for (i = 1; i <= n-2; i++) p[i] = i+2;
629 5449 : p[n-1] = 1; p[n] = 2;
630 5449 : td->borne = borne;
631 5449 : td->lborne = subii(ladic, borne);
632 5449 : td->ladic = ladic;
633 5449 : td->L = L;
634 5449 : td->M = M;
635 5449 : td->TM = shallowtrans(M);
636 5449 : td->PV = zero_zv(n);
637 5449 : gel(td->PV, 2) = Vmatrix(2, td);
638 5449 : }
639 :
640 : /* Free clones stored inside galois_test */
641 : static void
642 5449 : freetest(struct galois_test *td)
643 : {
644 : long i;
645 55756 : for (i = 1; i < lg(td->PV); i++)
646 50307 : if (td->PV[i]) { gunclone(gel(td->PV,i)); td->PV[i] = 0; }
647 5449 : }
648 :
649 : /* Check if the integer P seen as a p-adic number is close to an integer less
650 : * than td->borne in absolute value */
651 : static long
652 94906 : padicisint(GEN P, struct galois_test *td)
653 : {
654 94906 : pari_sp ltop = avma;
655 94906 : GEN U = modii(P, td->ladic);
656 94906 : long r = cmpii(U, td->borne) <= 0 || cmpii(U, td->lborne) >= 0;
657 94906 : return gc_long(ltop, r);
658 : }
659 :
660 : /* Check if the permutation pf is valid according to td.
661 : * If not, update td to make subsequent test faster (hopefully) */
662 : static long
663 117418 : galois_test_perm(struct galois_test *td, GEN pf)
664 : {
665 117418 : pari_sp av = avma;
666 117418 : long i, j, n = lg(td->L)-1;
667 117418 : GEN V, P = NULL;
668 213521 : for (i = 1; i < n; i++)
669 : {
670 206570 : long ord = td->order[i];
671 206570 : GEN PW = gel(td->PV, ord);
672 206570 : if (PW)
673 : {
674 111664 : ulong head = umael(PW,1,pf[1]);
675 7121072 : for (j = 2; j <= n; j++) head += umael(PW,j,pf[j]);
676 111664 : if (!headlongisint(head,n)) break;
677 : } else
678 : {
679 94906 : if (!P) P = vecpermute(td->L, pf);
680 94906 : V = FpV_dotproduct(gel(td->TM,ord), P, td->ladic);
681 94906 : if (!padicisint(V, td)) {
682 238 : gel(td->PV, ord) = Vmatrix(ord, td);
683 238 : if (DEBUGLEVEL >= 4) err_printf("M");
684 238 : break;
685 : }
686 : }
687 : }
688 117418 : if (i == n) return gc_long(av,1);
689 110467 : if (DEBUGLEVEL >= 4) err_printf("%d.", i);
690 110467 : if (i > 1)
691 : {
692 742 : long z = td->order[i];
693 1526 : for (j = i; j > 1; j--) td->order[j] = td->order[j-1];
694 742 : td->order[1] = z;
695 742 : if (DEBUGLEVEL >= 8) err_printf("%Ps", td->order);
696 : }
697 110467 : return gc_long(av,0);
698 : }
699 : /*Compute a*b/c when a*b will overflow*/
700 : static long
701 0 : muldiv(long a,long b,long c)
702 : {
703 0 : return (long)((double)a*(double)b/c);
704 : }
705 :
706 : /* F = cycle decomposition of sigma,
707 : * B = cycle decomposition of cl(tau).
708 : * Check all permutations pf who can possibly correspond to tau, such that
709 : * tau*sigma*tau^-1 = sigma^s and tau^d = sigma^t, where d = ord cl(tau)
710 : * x: vector of choices,
711 : * G: vector allowing linear access to elts of F.
712 : * Choices multiple of e are not changed. */
713 : static GEN
714 8805 : testpermutation(GEN F, GEN B, GEN x, long s, long e, long cut,
715 : struct galois_test *td)
716 : {
717 8805 : pari_sp av, avm = avma;
718 : long a, b, c, d, n, p1, p2, p3, p4, p5, p6, l1, l2, N1, N2, R1;
719 8805 : long i, j, cx, hop = 0, start = 0;
720 : GEN pf, ar, G, W, NN, NQ;
721 : pari_timer ti;
722 8805 : if (DEBUGLEVEL >= 1) timer_start(&ti);
723 8805 : a = lg(F)-1; b = lg(gel(F,1))-1;
724 8805 : c = lg(B)-1; d = lg(gel(B,1))-1;
725 8805 : n = a*b;
726 8805 : s = (b+s) % b;
727 8805 : pf = cgetg(n+1, t_VECSMALL);
728 8805 : av = avma;
729 8805 : ar = cgetg(a+2, t_VECSMALL); ar[a+1]=0;
730 8805 : G = cgetg(a+1, t_VECSMALL);
731 8805 : W = gel(td->PV, td->order[n]);
732 58384 : for (cx=1, i=1, j=1; cx <= a; cx++, i++)
733 : {
734 49579 : gel(G,cx) = gel(F, coeff(B,i,j));
735 49579 : if (i == d) { i = 0; j++; }
736 : }
737 8805 : NN = divis(powuu(b, c * (d - d/e)), cut);
738 8805 : if (DEBUGLEVEL>=4) err_printf("GaloisConj: I will try %Ps permutations\n", NN);
739 8805 : N1 = 1000000;
740 8805 : NQ = divis_rem(NN,N1,&R1);
741 8805 : if (abscmpiu(NQ,100000000)>0)
742 : {
743 0 : set_avma(avm);
744 0 : pari_warn(warner,"Combinatorics too hard: would need %Ps tests!\n"
745 : "I'll skip it but you will get a partial result...",NN);
746 0 : return identity_perm(n);
747 : }
748 8805 : N2 = itos(NQ);
749 10953 : for (l2 = 0; l2 <= N2; l2++)
750 : {
751 8805 : long nbiter = (l2<N2) ? N1: R1;
752 8805 : if (DEBUGLEVEL >= 2 && N2) err_printf("%d%% ", muldiv(l2,100,N2));
753 10147775 : for (l1 = 0; l1 < nbiter; l1++)
754 : {
755 10145627 : if (start)
756 : {
757 18145467 : for (i=1, j=e; i < a;)
758 : {
759 18145467 : if ((++(x[i])) != b) break;
760 8008645 : x[i++] = 0;
761 8008645 : if (i == j) { i++; j += e; }
762 : }
763 : }
764 8805 : else { start=1; i = a-1; }
765 : /* intheadlong test: overflow in + is OK, we compute mod 2^BIL */
766 46091760 : for (p1 = i+1, p5 = p1%d - 1 ; p1 >= 1; p1--, p5--) /* p5 = (p1%d) - 1 */
767 : {
768 : GEN G1, G6;
769 35946133 : ulong V = 0;
770 35946133 : if (p5 == - 1) { p5 = d - 1; p6 = p1 + 1 - d; } else p6 = p1 + 1;
771 35946133 : G1 = gel(G,p1); G6 = gel(G,p6);
772 35946133 : p4 = p5 ? x[p1-1] : 0;
773 109412742 : for (p2 = 1+p4, p3 = 1 + x[p1]; p2 <= b; p2++)
774 : {
775 73466609 : V += umael(W,uel(G6,p3),uel(G1,p2));
776 73466609 : p3 += s; if (p3 > b) p3 -= b;
777 : }
778 35946133 : p3 = 1 + x[p1] - s; if (p3 <= 0) p3 += b;
779 50258860 : for (p2 = p4; p2 >= 1; p2--)
780 : {
781 14312727 : V += umael(W,uel(G6,p3),uel(G1,p2));
782 14312727 : p3 -= s; if (p3 <= 0) p3 += b;
783 : }
784 35946133 : uel(ar,p1) = uel(ar,p1+1) + V;
785 : }
786 10145627 : if (!headlongisint(uel(ar,1),n)) continue;
787 :
788 : /* intheadlong succeeds. Full computation */
789 3511151 : for (p1=1, p5=d; p1 <= a; p1++, p5++)
790 : {
791 3394027 : if (p5 == d) { p5 = 0; p4 = 0; } else p4 = x[p1-1];
792 3394027 : if (p5 == d-1) p6 = p1+1-d; else p6 = p1+1;
793 9517409 : for (p2 = 1+p4, p3 = 1 + x[p1]; p2 <= b; p2++)
794 : {
795 6123382 : pf[mael(G,p1,p2)] = mael(G,p6,p3);
796 6123382 : p3 += s; if (p3 > b) p3 -= b;
797 : }
798 3394027 : p3 = 1 + x[p1] - s; if (p3 <= 0) p3 += b;
799 4417841 : for (p2 = p4; p2 >= 1; p2--)
800 : {
801 1023814 : pf[mael(G,p1,p2)] = mael(G,p6,p3);
802 1023814 : p3 -= s; if (p3 <= 0) p3 += b;
803 : }
804 : }
805 117124 : if (galois_test_perm(td, pf))
806 : {
807 6657 : if (DEBUGLEVEL >= 1)
808 : {
809 0 : GEN nb = addis(mulss(l2,N1),l1);
810 0 : timer_printf(&ti, "testpermutation(%Ps)", nb);
811 0 : if (DEBUGLEVEL >= 2 && hop)
812 0 : err_printf("GaloisConj: %d hop over %Ps iterations\n", hop, nb);
813 : }
814 6657 : set_avma(av); return pf;
815 : }
816 110467 : hop++;
817 : }
818 : }
819 2148 : if (DEBUGLEVEL >= 1)
820 : {
821 0 : timer_printf(&ti, "testpermutation(%Ps)", NN);
822 0 : if (DEBUGLEVEL >= 2 && hop)
823 0 : err_printf("GaloisConj: %d hop over %Ps iterations\n", hop, NN);
824 : }
825 2148 : return gc_NULL(avm);
826 : }
827 :
828 : /* List of subgroups of (Z/mZ)^* whose order divide o, and return the list
829 : * of their elements, sorted by increasing order */
830 : static GEN
831 1778 : listznstarelts(long m, long o)
832 : {
833 1778 : pari_sp av = avma;
834 : GEN L, zn, zns;
835 : long i, phi, ind, l;
836 1778 : if (m == 2) retmkvec(mkvecsmall(1));
837 1764 : zn = znstar(stoi(m));
838 1764 : phi = itos(gel(zn,1));
839 1764 : o = ugcd(o, phi); /* do we impose this on input ? */
840 1764 : zns = znstar_small(zn);
841 1764 : L = cgetg(o+1, t_VEC);
842 5824 : for (i=1,ind = phi; ind; ind -= phi/o, i++) /* by *decreasing* exact index */
843 4060 : gel(L,i) = subgrouplist(gel(zn,2), mkvec(utoipos(ind)));
844 1764 : L = shallowconcat1(L); l = lg(L);
845 5544 : for (i = 1; i < l; i++) gel(L,i) = znstar_hnf_elts(zns, gel(L,i));
846 1764 : return gerepilecopy(av, L);
847 : }
848 :
849 : /* A sympol is a symmetric polynomial
850 : *
851 : * Currently sympol are couple of t_VECSMALL [v,w]
852 : * v[1]...v[k], w[1]...w[k] represent the polynomial sum(i=1,k,v[i]*s_w[i])
853 : * where s_i(X_1,...,X_n) = sum(j=1,n,X_j^i) */
854 :
855 : static GEN
856 17617 : Flm_newtonsum(GEN M, ulong e, ulong p)
857 : {
858 17617 : long f = lg(M), g = lg(gel(M,1)), i, j;
859 17617 : GEN NS = cgetg(f, t_VECSMALL);
860 83416 : for(i=1; i<f; i++)
861 : {
862 65799 : ulong s = 0;
863 65799 : GEN Mi = gel(M,i);
864 293434 : for(j = 1; j < g; j++)
865 227635 : s = Fl_add(s, Fl_powu(uel(Mi,j), e, p), p);
866 65799 : uel(NS,i) = s;
867 : }
868 17617 : return NS;
869 : }
870 :
871 : static GEN
872 11259 : Flv_sympol_eval(GEN v, GEN NS, ulong p)
873 : {
874 11259 : pari_sp av = avma;
875 11259 : long i, l = lg(v);
876 11259 : GEN S = Flv_Fl_mul(gel(NS,1), uel(v,1), p);
877 11911 : for (i=2; i<l; i++)
878 652 : if (v[i]) S = Flv_add(S, Flv_Fl_mul(gel(NS,i), uel(v,i), p), p);
879 11259 : return gerepileuptoleaf(av, S);
880 : }
881 :
882 : static GEN
883 11259 : sympol_eval_newtonsum(long e, GEN O, GEN mod)
884 : {
885 11259 : long f = lg(O), g = lg(gel(O,1)), i, j;
886 11259 : GEN PL = cgetg(f, t_COL);
887 55309 : for(i=1; i<f; i++)
888 : {
889 44050 : pari_sp av = avma;
890 44050 : GEN s = gen_0;
891 180639 : for(j=1; j<g; j++) s = addii(s, Fp_powu(gmael(O,i,j), e, mod));
892 44050 : gel(PL,i) = gerepileuptoint(av, remii(s,mod));
893 : }
894 11259 : return PL;
895 : }
896 :
897 : static GEN
898 11182 : sympol_eval(GEN sym, GEN O, GEN mod)
899 : {
900 11182 : pari_sp av = avma;
901 : long i;
902 11182 : GEN v = gel(sym,1), w = gel(sym,2);
903 11182 : GEN S = gen_0;
904 22939 : for (i=1; i<lg(v); i++)
905 11757 : if (v[i]) S = gadd(S, gmulsg(v[i], sympol_eval_newtonsum(w[i], O, mod)));
906 11182 : return gerepileupto(av, S);
907 : }
908 :
909 : /* Let sigma be an automorphism of L (as a polynomial with rational coefs)
910 : * Let 'sym' be a symmetric polynomial defining alpha in L.
911 : * We have alpha = sym(x,sigma(x),,,sigma^(g-1)(x)). Compute alpha mod p */
912 : static GEN
913 5372 : sympol_aut_evalmod(GEN sym, long g, GEN sigma, GEN Tp, GEN p)
914 : {
915 5372 : pari_sp ltop=avma;
916 5372 : long i, j, npows = brent_kung_optpow(degpol(Tp)-1, g-1, 1);
917 5372 : GEN s, f, pows, v = zv_to_ZV(gel(sym,1)), w = zv_to_ZV(gel(sym,2));
918 5372 : sigma = RgX_to_FpX(sigma, p);
919 5372 : pows = FpXQ_powers(sigma,npows,Tp,p);
920 5372 : f = pol_x(varn(sigma));
921 5372 : s = pol_0(varn(sigma));
922 22150 : for(i=1; i<=g;i++)
923 : {
924 16778 : if (i > 1) f = FpX_FpXQV_eval(f,pows,Tp,p);
925 33934 : for(j=1; j<lg(v); j++)
926 17156 : s = FpX_add(s, FpX_Fp_mul(FpXQ_pow(f,gel(w,j),Tp,p),gel(v,j),p),p);
927 : }
928 5372 : return gerepileupto(ltop, s);
929 : }
930 :
931 : /* Let Sp be as computed with sympol_aut_evalmod
932 : * Let Tmod be the factorisation of T mod p.
933 : * Return the factorisation of the minimal polynomial of S mod p w.r.t. Tmod */
934 : static GEN
935 5372 : fixedfieldfactmod(GEN Sp, GEN p, GEN Tmod)
936 : {
937 5372 : long i, l = lg(Tmod);
938 5372 : GEN F = cgetg(l,t_VEC);
939 18220 : for(i=1; i<l; i++)
940 : {
941 12848 : GEN Ti = gel(Tmod,i);
942 12848 : gel(F,i) = FpXQ_minpoly(FpX_rem(Sp,Ti,p), Ti,p);
943 : }
944 5372 : return F;
945 : }
946 :
947 : static GEN
948 11182 : fixedfieldsurmer(ulong l, GEN NS, GEN W)
949 : {
950 11182 : const long step=3;
951 11182 : long i, j, n = lg(W)-1, m = 1L<<((n-1)<<1);
952 11182 : GEN sym = cgetg(n+1,t_VECSMALL);
953 11757 : for (j=1;j<n;j++) sym[j] = step;
954 11182 : sym[n] = 0;
955 11182 : if (DEBUGLEVEL>=4) err_printf("FixedField: Weight: %Ps\n",W);
956 11259 : for (i=0; i<m; i++)
957 : {
958 11259 : pari_sp av = avma;
959 : GEN L;
960 11834 : for (j=1; sym[j]==step; j++) sym[j]=0;
961 11259 : sym[j]++;
962 11259 : if (DEBUGLEVEL>=6) err_printf("FixedField: Sym: %Ps\n",sym);
963 11259 : L = Flv_sympol_eval(sym, NS, l);
964 11259 : if (!vecsmall_is1to1(L)) { set_avma(av); continue; }
965 11182 : return mkvec2(sym,W);
966 : }
967 0 : return NULL;
968 : }
969 :
970 : /*Check whether the line of NS are pair-wise distinct.*/
971 : static long
972 11757 : sympol_is1to1_lg(GEN NS, long n)
973 : {
974 11757 : long i, j, k, l = lgcols(NS);
975 54460 : for (i=1; i<l; i++)
976 172795 : for(j=i+1; j<l; j++)
977 : {
978 133915 : for(k=1; k<n; k++)
979 133340 : if (mael(NS,k,j)!=mael(NS,k,i)) break;
980 130092 : if (k>=n) return 0;
981 : }
982 11182 : return 1;
983 : }
984 :
985 : /* Let O a set of orbits of roots (see fixedfieldorbits) modulo mod,
986 : * l | mod and p two prime numbers. Return a vector [sym,s,P] where:
987 : * sym is a sympol, s is the set of images of sym on O and
988 : * P is the polynomial with roots s. */
989 : static GEN
990 11182 : fixedfieldsympol(GEN O, ulong l)
991 : {
992 11182 : pari_sp ltop=avma;
993 11182 : const long n=(BITS_IN_LONG>>1)-1;
994 11182 : GEN NS = cgetg(n+1,t_MAT), sym = NULL, W = cgetg(n+1,t_VECSMALL);
995 11182 : long i, e=1;
996 11182 : if (DEBUGLEVEL>=4)
997 0 : err_printf("FixedField: Size: %ldx%ld\n",lg(O)-1,lg(gel(O,1))-1);
998 11182 : O = ZM_to_Flm(O,l);
999 22939 : for (i=1; !sym && i<=n; i++)
1000 : {
1001 11757 : GEN L = Flm_newtonsum(O, e++, l);
1002 11757 : if (lg(O)>2)
1003 17519 : while (vecsmall_isconst(L)) L = Flm_newtonsum(O, e++, l);
1004 11757 : W[i] = e-1; gel(NS,i) = L;
1005 11757 : if (sympol_is1to1_lg(NS,i+1))
1006 11182 : sym = fixedfieldsurmer(l,NS,vecsmall_shorten(W,i));
1007 : }
1008 11182 : if (!sym) pari_err_BUG("fixedfieldsympol [p too small]");
1009 11182 : if (DEBUGLEVEL>=2) err_printf("FixedField: Found: %Ps\n",gel(sym,1));
1010 11182 : return gerepilecopy(ltop,sym);
1011 : }
1012 :
1013 : /* Let O a set of orbits as indices and L the corresponding roots.
1014 : * Return the set of orbits as roots. */
1015 : static GEN
1016 11182 : fixedfieldorbits(GEN O, GEN L)
1017 : {
1018 11182 : GEN S = cgetg(lg(O), t_MAT);
1019 : long i;
1020 53832 : for (i = 1; i < lg(O); i++) gel(S,i) = vecpermute(L, gel(O,i));
1021 11182 : return S;
1022 : }
1023 :
1024 : static GEN
1025 1057 : fixedfieldinclusion(GEN O, GEN PL)
1026 : {
1027 1057 : long i, j, f = lg(O)-1, g = lg(gel(O,1))-1;
1028 1057 : GEN S = cgetg(f*g + 1, t_COL);
1029 7112 : for (i = 1; i <= f; i++)
1030 : {
1031 6055 : GEN Oi = gel(O,i);
1032 24948 : for (j = 1; j <= g; j++) gel(S, Oi[j]) = gel(PL, i);
1033 : }
1034 1057 : return S;
1035 : }
1036 :
1037 : /* Polynomial attached to a vector of conjugates. Not stack clean */
1038 : static GEN
1039 51446 : vectopol(GEN v, GEN M, GEN den , GEN mod, GEN mod2, long x)
1040 : {
1041 51446 : long l = lg(v)+1, i;
1042 51446 : GEN z = cgetg(l,t_POL);
1043 51446 : z[1] = evalsigne(1)|evalvarn(x);
1044 394299 : for (i=2; i<l; i++)
1045 342855 : gel(z,i) = gdiv(centermodii(ZMrow_ZC_mul(M,v,i-1), mod, mod2), den);
1046 51444 : return normalizepol_lg(z, l);
1047 : }
1048 :
1049 : /* Polynomial associate to a permutation of the roots. Not stack clean */
1050 : static GEN
1051 49850 : permtopol(GEN p, GEN L, GEN M, GEN den, GEN mod, GEN mod2, long x)
1052 : {
1053 49850 : if (lg(p) != lg(L)) pari_err_TYPE("permtopol [permutation]", p);
1054 49850 : return vectopol(vecpermute(L,p), M, den, mod, mod2, x);
1055 : }
1056 :
1057 : static GEN
1058 8855 : galoisvecpermtopol(GEN gal, GEN vec, GEN mod, GEN mod2)
1059 : {
1060 8855 : long i, l = lg(vec);
1061 8855 : long v = varn(gal_get_pol(gal));
1062 8855 : GEN L = gal_get_roots(gal);
1063 8855 : GEN M = gal_get_invvdm(gal);
1064 8855 : GEN P = cgetg(l, t_MAT);
1065 46256 : for (i=1; i<l; i++)
1066 : {
1067 37408 : GEN p = gel(vec,i);
1068 37408 : if (typ(p) != t_VECSMALL) pari_err_TYPE("galoispermtopol", vec);
1069 37401 : gel(P, i) = vecpermute(L, p);
1070 : }
1071 8848 : P = RgM_to_RgXV(FpM_center(FpM_mul(M, P, mod), mod, mod2), v);
1072 8848 : return gdiv(P, gal_get_den(gal));
1073 : }
1074 :
1075 : static void
1076 66958 : notgalois(long p, struct galois_analysis *ga)
1077 : {
1078 66958 : if (DEBUGLEVEL >= 2) err_printf("GaloisAnalysis:non Galois for p=%ld\n", p);
1079 66958 : ga->p = p;
1080 66958 : ga->deg = 0;
1081 66958 : }
1082 :
1083 : /*Gather information about the group*/
1084 : static long
1085 96780 : init_group(long n, long np, GEN Fp, GEN Fe, long *porder)
1086 : {
1087 96780 : const long prim_nonwss_orders[] = { 48,56,60,72,75,80,196,200,216 };
1088 96780 : long i, phi_order = 1, order = 1, group = 0;
1089 : ulong p;
1090 :
1091 : /* non-WSS groups of this order? */
1092 967611 : for (i=0; i < (long)numberof(prim_nonwss_orders); i++)
1093 870852 : if (n % prim_nonwss_orders[i] == 0) { group |= ga_non_wss; break; }
1094 96780 : if (np == 2 && Fp[2] == 3 && Fe[2] == 1 && Fe[1] > 2) group |= ga_ext_2;
1095 :
1096 143484 : for (i = np; i > 0; i--)
1097 : {
1098 102674 : long p = Fp[i];
1099 102674 : if (phi_order % p == 0) { group |= ga_all_normal; break; }
1100 96829 : order *= p; phi_order *= p-1;
1101 96829 : if (Fe[i] > 1) break;
1102 : }
1103 96780 : if (uisprimepower(n, &p) || n == 135) group |= ga_all_nilpotent;
1104 96781 : if (n <= 104) group |= ga_easy; /* no need to use polynomial algo */
1105 96781 : *porder = order; return group;
1106 : }
1107 :
1108 : /*is a "better" than b ? (if so, update karma) */
1109 : static int
1110 162862 : improves(long a, long b, long plift, long p, long n, long *karma)
1111 : {
1112 162862 : if (!plift || a > b) { *karma = ugcd(p-1,n); return 1; }
1113 159187 : if (a == b) {
1114 156478 : long k = ugcd(p-1,n);
1115 156477 : if (k > *karma) { *karma = k; return 1; }
1116 : }
1117 141181 : return 0; /* worse */
1118 : }
1119 :
1120 : /* return 0 if not galois or not wss */
1121 : static int
1122 96782 : galoisanalysis(GEN T, struct galois_analysis *ga, long calcul_l, GEN bad)
1123 : {
1124 96782 : pari_sp ltop = avma, av;
1125 96782 : long group, linf, n, p, i, karma = 0;
1126 : GEN F, Fp, Fe, Fpe, O;
1127 : long np, order, plift, nbmax, nbtest, deg;
1128 : pari_timer ti;
1129 : forprime_t S;
1130 96782 : if (DEBUGLEVEL >= 1) timer_start(&ti);
1131 96782 : n = degpol(T);
1132 96782 : O = zero_zv(n);
1133 96782 : F = factoru_pow(n);
1134 96780 : Fp = gel(F,1); np = lg(Fp)-1;
1135 96780 : Fe = gel(F,2);
1136 96780 : Fpe= gel(F,3);
1137 96780 : group = init_group(n, np, Fp, Fe, &order);
1138 :
1139 : /*Now we study the orders of the Frobenius elements*/
1140 96781 : deg = Fp[np]; /* largest prime | n */
1141 96781 : plift = 0;
1142 96781 : nbtest = 0;
1143 96781 : nbmax = 8+(n>>1);
1144 96781 : u_forprime_init(&S, n*maxss(expu(n)-3, 2), ULONG_MAX);
1145 96782 : av = avma;
1146 496491 : while (!plift || (nbtest < nbmax && (nbtest <=8 || order < (n>>1)))
1147 30110 : || ((n == 24 || n==36) && O[6] == 0 && O[4] == 0)
1148 564834 : || ((group&ga_non_wss) && order == Fp[np]))
1149 : {
1150 504613 : long d, o, norm_o = 1;
1151 : GEN D, Tp;
1152 :
1153 504613 : if ((group&ga_non_wss) && nbtest >= 3*nbmax) break; /* in all cases */
1154 504613 : nbtest++; set_avma(av);
1155 504612 : p = u_forprime_next(&S);
1156 504612 : if (!p) pari_err_OVERFLOW("galoisanalysis [ran out of primes]");
1157 545432 : if (bad && dvdiu(bad, p)) continue;
1158 504612 : Tp = ZX_to_Flx(T,p);
1159 504603 : if (!Flx_is_squarefree(Tp,p)) { if (!--nbtest) nbtest = 1; continue; }
1160 :
1161 463773 : D = Flx_nbfact_by_degree(Tp, &d, p);
1162 463795 : o = n / d; /* d factors, all should have degree o */
1163 463795 : if (D[o] != d) { notgalois(p, ga); return gc_bool(ltop,0); }
1164 :
1165 397130 : if (!O[o]) O[o] = p;
1166 397130 : if (o % deg) goto ga_end; /* NB: deg > 1 */
1167 245648 : if ((group&ga_all_normal) && o < order) goto ga_end;
1168 :
1169 : /*Frob_p has order o > 1, find a power which generates a normal subgroup*/
1170 245494 : if (o * Fp[1] >= n)
1171 229718 : norm_o = o; /*subgroups of smallest index are normal*/
1172 : else
1173 : {
1174 19253 : for (i = np; i > 0; i--)
1175 : {
1176 19253 : if (o % Fpe[i]) break;
1177 3477 : norm_o *= Fpe[i];
1178 : }
1179 : }
1180 : /* Frob_p^(o/norm_o) generates a normal subgroup of order norm_o */
1181 245494 : if (norm_o != 1)
1182 : {
1183 233195 : if (!(group&ga_all_normal) || o > order)
1184 82632 : karma = ugcd(p-1,n);
1185 150563 : else if (!improves(norm_o, deg, plift,p,n, &karma)) goto ga_end;
1186 : /* karma0=0, deg0<=norm_o -> the first improves() returns 1 */
1187 101981 : deg = norm_o; group |= ga_all_normal; /* STORE */
1188 : }
1189 12299 : else if (group&ga_all_normal) goto ga_end;
1190 12299 : else if (!improves(o, order, plift,p,n, &karma)) goto ga_end;
1191 :
1192 104312 : order = o; plift = p; /* STORE */
1193 397129 : ga_end:
1194 397129 : if (DEBUGLEVEL >= 5)
1195 0 : err_printf("GaloisAnalysis:Nbtest=%ld,p=%ld,o=%ld,n_o=%d,best p=%ld,ord=%ld,k=%ld\n", nbtest, p, o, norm_o, plift, order,karma);
1196 : }
1197 : /* To avoid looping on non-WSS group.
1198 : * TODO: check for large groups. Would it be better to disable this check if
1199 : * we are in a good case (ga_all_normal && !(ga_ext_2) (e.g. 60)) ?*/
1200 30111 : ga->p = plift;
1201 30111 : if (!plift || ((group&ga_non_wss) && order == Fp[np]))
1202 : {
1203 1 : if (DEBUGLEVEL)
1204 0 : pari_warn(warner,"Galois group probably not weakly super solvable");
1205 0 : return 0;
1206 : }
1207 30110 : linf = 2*n*usqrt(n);
1208 30110 : if (calcul_l && O[1] <= linf)
1209 : {
1210 : pari_sp av2;
1211 : forprime_t S2;
1212 : ulong p;
1213 6940 : u_forprime_init(&S2, linf+1,ULONG_MAX);
1214 6940 : av2 = avma;
1215 96073 : while ((p = u_forprime_next(&S2)))
1216 : { /*find a totally split prime l > linf*/
1217 96073 : GEN Tp = ZX_to_Flx(T, p);
1218 96073 : long nb = Flx_nbroots(Tp, p);
1219 96073 : if (nb == n) { O[1] = p; break; }
1220 89420 : if (nb && Flx_is_squarefree(Tp,p)) { notgalois(p,ga); return gc_bool(ltop,0); }
1221 89133 : set_avma(av2);
1222 : }
1223 6653 : if (!p) pari_err_OVERFLOW("galoisanalysis [ran out of primes]");
1224 : }
1225 29823 : ga->group = group;
1226 29823 : ga->deg = deg;
1227 29823 : ga->ord = order;
1228 29823 : ga->l = O[1];
1229 29823 : ga->p4 = n >= 4 ? O[4] : 0;
1230 29823 : if (DEBUGLEVEL >= 4)
1231 0 : err_printf("GaloisAnalysis:p=%ld l=%ld group=%ld deg=%ld ord=%ld\n",
1232 0 : plift, O[1], group, deg, order);
1233 29823 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "galoisanalysis()");
1234 29823 : return gc_bool(ltop,1);
1235 : }
1236 :
1237 : static GEN
1238 98 : a4galoisgen(struct galois_test *td)
1239 : {
1240 98 : const long n = 12;
1241 98 : pari_sp ltop = avma, av, av2;
1242 98 : long i, j, k, N, hop = 0;
1243 : GEN MT, O,O1,O2,O3, ar, mt, t, u, res, orb, pft, pfu, pfv;
1244 :
1245 98 : res = cgetg(3, t_VEC);
1246 98 : pft = cgetg(n+1, t_VECSMALL);
1247 98 : pfu = cgetg(n+1, t_VECSMALL);
1248 98 : pfv = cgetg(n+1, t_VECSMALL);
1249 98 : gel(res,1) = mkvec3(pft,pfu,pfv);
1250 98 : gel(res,2) = mkvecsmall3(2,2,3);
1251 98 : av = avma;
1252 98 : ar = cgetg(5, t_VECSMALL);
1253 98 : mt = gel(td->PV, td->order[n]);
1254 98 : t = identity_perm(n) + 1; /* Sorry for this hack */
1255 98 : u = cgetg(n+1, t_VECSMALL) + 1; /* too lazy to correct */
1256 98 : MT = cgetg(n+1, t_MAT);
1257 1274 : for (j = 1; j <= n; j++) gel(MT,j) = cgetg(n+1, t_VECSMALL);
1258 1274 : for (j = 1; j <= n; j++)
1259 7644 : for (i = 1; i < j; i++)
1260 6468 : ucoeff(MT,i,j) = ucoeff(MT,j,i) = ucoeff(mt,i,j)+ucoeff(mt,j,i);
1261 : /* MT(i,i) unused */
1262 :
1263 98 : av2 = avma;
1264 : /* N = itos(gdiv(mpfact(n), mpfact(n >> 1))) >> (n >> 1); */
1265 : /* n = 2k = 12; N = (2k)! / (k! * 2^k) = 10395 */
1266 98 : N = 10395;
1267 98 : if (DEBUGLEVEL>=4) err_printf("A4GaloisConj: will test %ld permutations\n", N);
1268 98 : uel(ar,4) = umael(MT,11,12);
1269 98 : uel(ar,3) = uel(ar,4) + umael(MT,9,10);
1270 98 : uel(ar,2) = uel(ar,3) + umael(MT,7,8);
1271 98 : uel(ar,1) = uel(ar,2) + umael(MT,5,6);
1272 233268 : for (i = 0; i < N; i++)
1273 : {
1274 : long g;
1275 233268 : if (i)
1276 : {
1277 233170 : long a, x = i, y = 1;
1278 328726 : do { y += 2; a = x%y; x = x/y; } while (!a);
1279 233170 : switch (y)
1280 : {
1281 155491 : case 3:
1282 155491 : lswap(t[2], t[2-a]);
1283 155491 : break;
1284 62169 : case 5:
1285 62169 : x = t[0]; t[0] = t[2]; t[2] = t[1]; t[1] = x;
1286 62169 : lswap(t[4], t[4-a]);
1287 62169 : uel(ar,1) = uel(ar,2) + umael(MT,t[4],t[5]);
1288 62169 : break;
1289 13339 : case 7:
1290 13339 : x = t[0]; t[0] = t[4]; t[4] = t[3]; t[3] = t[1]; t[1] = t[2]; t[2] = x;
1291 13339 : lswap(t[6], t[6-a]);
1292 13339 : uel(ar,2) = uel(ar,3) + umael(MT,t[6],t[7]);
1293 13339 : uel(ar,1) = uel(ar,2) + umael(MT,t[4],t[5]);
1294 13339 : break;
1295 1975 : case 9:
1296 1975 : x = t[0]; t[0] = t[6]; t[6] = t[5]; t[5] = t[3]; t[3] = x;
1297 1975 : lswap(t[1], t[4]);
1298 1975 : lswap(t[8], t[8-a]);
1299 1975 : uel(ar,3) = uel(ar,4) + umael(MT,t[8],t[9]);
1300 1975 : uel(ar,2) = uel(ar,3) + umael(MT,t[6],t[7]);
1301 1975 : uel(ar,1) = uel(ar,2) + umael(MT,t[4],t[5]);
1302 1975 : break;
1303 196 : case 11:
1304 196 : x = t[0]; t[0] = t[8]; t[8] = t[7]; t[7] = t[5]; t[5] = t[1];
1305 196 : t[1] = t[6]; t[6] = t[3]; t[3] = t[2]; t[2] = t[4]; t[4] = x;
1306 196 : lswap(t[10], t[10-a]);
1307 196 : uel(ar,4) = umael(MT,t[10],t[11]);
1308 196 : uel(ar,3) = uel(ar,4) + umael(MT,t[8],t[9]);
1309 196 : uel(ar,2) = uel(ar,3) + umael(MT,t[6],t[7]);
1310 196 : uel(ar,1) = uel(ar,2) + umael(MT,t[4],t[5]);
1311 : }
1312 : }
1313 233268 : g = uel(ar,1)+umael(MT,t[0],t[1])+umael(MT,t[2],t[3]);
1314 233268 : if (headlongisint(g,n))
1315 : {
1316 686 : for (k = 0; k < n; k += 2)
1317 : {
1318 588 : pft[t[k]] = t[k+1];
1319 588 : pft[t[k+1]] = t[k];
1320 : }
1321 98 : if (galois_test_perm(td, pft)) break;
1322 0 : hop++;
1323 : }
1324 233170 : set_avma(av2);
1325 : }
1326 98 : if (DEBUGLEVEL >= 1 && hop)
1327 0 : err_printf("A4GaloisConj: %ld hop over %ld iterations\n", hop, N);
1328 98 : if (i == N) return gc_NULL(ltop);
1329 : /* N = itos(gdiv(mpfact(n >> 1), mpfact(n >> 2))) >> 1; */
1330 98 : N = 60;
1331 98 : if (DEBUGLEVEL >= 4) err_printf("A4GaloisConj: sigma=%Ps \n", pft);
1332 392 : for (k = 0; k < n; k += 4)
1333 : {
1334 294 : u[k+3] = t[k+3];
1335 294 : u[k+2] = t[k+1];
1336 294 : u[k+1] = t[k+2];
1337 294 : u[k] = t[k];
1338 : }
1339 4682 : for (i = 0; i < N; i++)
1340 : {
1341 4682 : ulong g = 0;
1342 4682 : if (i)
1343 : {
1344 4584 : long a, x = i, y = -2;
1345 7213 : do { y += 4; a = x%y; x = x/y; } while (!a);
1346 4584 : lswap(u[0],u[2]);
1347 4584 : switch (y)
1348 : {
1349 2292 : case 2:
1350 2292 : break;
1351 1955 : case 6:
1352 1955 : lswap(u[4],u[6]);
1353 1955 : if (!(a & 1))
1354 : {
1355 802 : a = 4 - (a>>1);
1356 802 : lswap(u[6], u[a]);
1357 802 : lswap(u[4], u[a-2]);
1358 : }
1359 1955 : break;
1360 337 : case 10:
1361 337 : x = u[6];
1362 337 : u[6] = u[3];
1363 337 : u[3] = u[2];
1364 337 : u[2] = u[4];
1365 337 : u[4] = u[1];
1366 337 : u[1] = u[0];
1367 337 : u[0] = x;
1368 337 : if (a >= 3) a += 2;
1369 337 : a = 8 - a;
1370 337 : lswap(u[10],u[a]);
1371 337 : lswap(u[8], u[a-2]);
1372 337 : break;
1373 : }
1374 : }
1375 32774 : for (k = 0; k < n; k += 2) g += mael(MT,u[k],u[k+1]);
1376 4682 : if (headlongisint(g,n))
1377 : {
1378 686 : for (k = 0; k < n; k += 2)
1379 : {
1380 588 : pfu[u[k]] = u[k+1];
1381 588 : pfu[u[k+1]] = u[k];
1382 : }
1383 98 : if (galois_test_perm(td, pfu)) break;
1384 0 : hop++;
1385 : }
1386 4584 : set_avma(av2);
1387 : }
1388 98 : if (i == N) return gc_NULL(ltop);
1389 98 : if (DEBUGLEVEL >= 1 && hop)
1390 0 : err_printf("A4GaloisConj: %ld hop over %ld iterations\n", hop, N);
1391 98 : if (DEBUGLEVEL >= 4) err_printf("A4GaloisConj: tau=%Ps \n", pfu);
1392 98 : set_avma(av2);
1393 98 : orb = mkvec2(pft,pfu);
1394 98 : O = vecperm_orbits(orb, 12);
1395 98 : if (DEBUGLEVEL >= 4) {
1396 0 : err_printf("A4GaloisConj: orb=%Ps\n", orb);
1397 0 : err_printf("A4GaloisConj: O=%Ps \n", O);
1398 : }
1399 98 : av2 = avma;
1400 98 : O1 = gel(O,1); O2 = gel(O,2); O3 = gel(O,3);
1401 147 : for (j = 0; j < 2; j++)
1402 : {
1403 147 : pfv[O1[1]] = O2[1];
1404 147 : pfv[O1[2]] = O2[3+j];
1405 147 : pfv[O1[3]] = O2[4 - (j << 1)];
1406 147 : pfv[O1[4]] = O2[2+j];
1407 494 : for (i = 0; i < 4; i++)
1408 : {
1409 445 : ulong g = 0;
1410 445 : switch (i)
1411 : {
1412 147 : case 0: break;
1413 125 : case 1: lswap(O3[1], O3[2]); lswap(O3[3], O3[4]); break;
1414 104 : case 2: lswap(O3[1], O3[4]); lswap(O3[2], O3[3]); break;
1415 69 : case 3: lswap(O3[1], O3[2]); lswap(O3[3], O3[4]); break;
1416 : }
1417 445 : pfv[O2[1]] = O3[1];
1418 445 : pfv[O2[3+j]] = O3[4-j];
1419 445 : pfv[O2[4 - (j<<1)]] = O3[2 + (j<<1)];
1420 445 : pfv[O2[2+j]] = O3[3-j];
1421 445 : pfv[O3[1]] = O1[1];
1422 445 : pfv[O3[4-j]] = O1[2];
1423 445 : pfv[O3[2 + (j<<1)]] = O1[3];
1424 445 : pfv[O3[3-j]] = O1[4];
1425 5785 : for (k = 1; k <= n; k++) g += mael(mt,k,pfv[k]);
1426 445 : if (headlongisint(g,n) && galois_test_perm(td, pfv))
1427 : {
1428 98 : set_avma(av);
1429 98 : if (DEBUGLEVEL >= 1)
1430 0 : err_printf("A4GaloisConj: %ld hop over %d iterations max\n",
1431 : hop, 10395 + 68);
1432 98 : return res;
1433 : }
1434 347 : hop++; set_avma(av2);
1435 : }
1436 : }
1437 0 : return gc_NULL(ltop);
1438 : }
1439 :
1440 : /* S4 */
1441 : static GEN
1442 1458 : s4makelift(GEN u, struct galois_lift *gl)
1443 1458 : { return FpXQ_powers(u, degpol(gl->T)-1, gl->TQ, gl->Q); }
1444 :
1445 : static long
1446 240527 : s4test(GEN u, GEN liftpow, struct galois_lift *gl, GEN phi)
1447 : {
1448 240527 : pari_sp av = avma;
1449 : GEN res, Q, Q2;
1450 240527 : long bl, i, d = lg(u)-2;
1451 : pari_timer ti;
1452 240527 : if (DEBUGLEVEL >= 6) timer_start(&ti);
1453 240527 : if (!d) return 0;
1454 240527 : Q = gl->Q; Q2 = shifti(Q,-1);
1455 240527 : res = gel(u,2);
1456 8557470 : for (i = 2; i <= d; i++)
1457 8316943 : if (lg(gel(liftpow,i))>2)
1458 8316943 : res = addii(res, mulii(gmael(liftpow,i,2), gel(u,i+1)));
1459 240527 : res = remii(res,Q);
1460 240527 : if (gl->den != gen_1) res = mulii(res, gl->den);
1461 240527 : res = centermodii(res, Q,Q2);
1462 240527 : if (abscmpii(res, gl->gb->bornesol) > 0) return gc_long(av,0);
1463 3677 : res = scalar_ZX_shallow(gel(u,2),varn(u));
1464 122240 : for (i = 2; i <= d ; i++)
1465 118563 : if (lg(gel(liftpow,i))>2)
1466 118563 : res = ZX_add(res, ZX_Z_mul(gel(liftpow,i), gel(u,i+1)));
1467 3677 : res = FpX_red(res, Q);
1468 3677 : if (gl->den != gen_1) res = FpX_Fp_mul(res, gl->den, Q);
1469 3677 : res = FpX_center_i(res, Q, shifti(Q,-1));
1470 3677 : bl = poltopermtest(res, gl, phi);
1471 3677 : if (DEBUGLEVEL >= 6) timer_printf(&ti, "s4test()");
1472 3677 : return gc_long(av,bl);
1473 : }
1474 :
1475 : static GEN
1476 513 : s4releveauto(GEN M, GEN B, GEN T, GEN p,long a1,long a2,long a3,long a4,long a5,long a6)
1477 : {
1478 513 : GEN F = ZX_mul(gel(M,a1),gel(B,a2));
1479 513 : F = ZX_add(F, ZX_mul(gel(M,a2),gel(B,a1)));
1480 513 : F = ZX_add(F, ZX_mul(gel(M,a3),gel(B,a4)));
1481 513 : F = ZX_add(F, ZX_mul(gel(M,a4),gel(B,a3)));
1482 513 : F = ZX_add(F, ZX_mul(gel(M,a5),gel(B,a6)));
1483 513 : F = ZX_add(F, ZX_mul(gel(M,a6),gel(B,a5)));
1484 513 : return FpXQ_red(F, T, p);
1485 : }
1486 :
1487 : static GEN
1488 321242 : lincomb(GEN B, long a, long b, long j)
1489 : {
1490 321242 : long k = (-j) & 3;
1491 321242 : return ZX_add(gmael(B,a,j+1), gmael(B,b,k+1));
1492 : }
1493 :
1494 : static GEN
1495 91 : FpXV_ffisom(GEN V, GEN p)
1496 : {
1497 91 : pari_sp av = avma;
1498 91 : long i, j, l = lg(V);
1499 91 : GEN S = cgetg(l, t_VEC), Si = cgetg(l, t_VEC), M;
1500 679 : for (i = 1; i < l; i++)
1501 : {
1502 588 : gel(S,i) = FpX_ffisom(gel(V,1), gel(V,i), p);
1503 588 : gel(Si,i) = FpXQ_ffisom_inv(gel(S,i), gel(V,i), p);
1504 : }
1505 91 : M = cgetg(l, t_MAT);
1506 679 : for (j = 1; j < l; j++)
1507 588 : gel(M,j) = FpXC_FpXQ_eval(Si, gel(S,j), gel(V,j), p);
1508 91 : return gerepileupto(av, M);
1509 : }
1510 :
1511 : static GEN
1512 91 : mkliftpow(GEN x, GEN T, GEN p, struct galois_lift *gl)
1513 679 : { pari_APPLY_same(automorphismlift(FpXV_chinese(gel(x,i), T, p, NULL), gl)) }
1514 :
1515 : #define rot3(x,y,z) {long _t=x; x=y; y=z; z=_t;}
1516 : #define rot4(x,y,z,t) {long _u=x; x=y; y=z; z=t; t=_u;}
1517 :
1518 : /* FIXME: could use the intheadlong technique */
1519 : static GEN
1520 77 : s4galoisgen(struct galois_lift *gl)
1521 : {
1522 77 : const long n = 24;
1523 : struct galois_testlift gt;
1524 77 : pari_sp av, ltop2, ltop = avma;
1525 : long i, j;
1526 77 : GEN sigma, tau, phi, res, r1,r2,r3,r4, pj, p = gl->p, Q = gl->Q, TQ = gl->TQ;
1527 : GEN sg, Tp, Tmod, misom, B, Bcoeff, liftpow, liftp, aut;
1528 :
1529 77 : res = cgetg(3, t_VEC);
1530 77 : r1 = cgetg(n+1, t_VECSMALL);
1531 77 : r2 = cgetg(n+1, t_VECSMALL);
1532 77 : r3 = cgetg(n+1, t_VECSMALL);
1533 77 : r4 = cgetg(n+1, t_VECSMALL);
1534 77 : gel(res,1)= mkvec4(r1,r2,r3,r4);
1535 77 : gel(res,2) = mkvecsmall4(2,2,3,2);
1536 77 : ltop2 = avma;
1537 77 : sg = identity_perm(6);
1538 77 : pj = zero_zv(6);
1539 77 : sigma = cgetg(n+1, t_VECSMALL);
1540 77 : tau = cgetg(n+1, t_VECSMALL);
1541 77 : phi = cgetg(n+1, t_VECSMALL);
1542 77 : Tp = FpX_red(gl->T,p);
1543 77 : Tmod = gel(FpX_factor(Tp,p), 1);
1544 77 : misom = FpXV_ffisom(Tmod, p);
1545 77 : aut = galoisdolift(gl);
1546 77 : inittestlift(aut, Tmod, gl, >);
1547 77 : B = FqC_FqV_mul(gt.pauto, gt.bezoutcoeff, gl->TQ, Q);
1548 77 : Bcoeff = gt.bezoutcoeff;
1549 77 : liftp = mkliftpow(shallowtrans(misom), Tmod, p, gl);
1550 77 : av = avma;
1551 128 : for (i = 0; i < 3; i++, set_avma(av))
1552 : {
1553 : pari_sp av1, av2, av3;
1554 : GEN u, u1, u2, u3;
1555 : long j1, j2, j3;
1556 128 : if (i)
1557 : {
1558 51 : if (i == 1) { lswap(sg[2],sg[3]); }
1559 1 : else { lswap(sg[1],sg[3]); }
1560 : }
1561 128 : u = s4releveauto(liftp,Bcoeff,TQ,Q,sg[1],sg[2],sg[3],sg[4],sg[5],sg[6]);
1562 128 : liftpow = s4makelift(u, gl);
1563 128 : av1 = avma;
1564 422 : for (j1 = 0; j1 < 4; j1++, set_avma(av1))
1565 : {
1566 371 : u1 = lincomb(B,sg[5],sg[6],j1);
1567 371 : av2 = avma;
1568 1676 : for (j2 = 0; j2 < 4; j2++, set_avma(av2))
1569 : {
1570 1382 : u2 = lincomb(B,sg[3],sg[4],j2);
1571 1382 : u2 = FpX_add(u1, u2, Q); av3 = avma;
1572 6717 : for (j3 = 0; j3 < 4; j3++, set_avma(av3))
1573 : {
1574 5412 : u3 = lincomb(B,sg[1],sg[2],j3);
1575 5412 : u3 = FpX_add(u2, u3, Q);
1576 5412 : if (DEBUGLEVEL >= 4)
1577 0 : err_printf("S4GaloisConj: Testing %d/3:%d/4:%d/4:%d/4:%Ps\n",
1578 : i,j1,j2,j3, sg);
1579 5412 : if (s4test(u3, liftpow, gl, sigma))
1580 : {
1581 77 : pj[1] = j3;
1582 77 : pj[2] = j2;
1583 77 : pj[3] = j1; goto suites4;
1584 : }
1585 : }
1586 : }
1587 : }
1588 : }
1589 0 : return gc_NULL(ltop);
1590 77 : suites4:
1591 77 : if (DEBUGLEVEL >= 4) err_printf("S4GaloisConj: sigma=%Ps\n", sigma);
1592 77 : if (DEBUGLEVEL >= 4) err_printf("S4GaloisConj: pj=%Ps\n", pj);
1593 77 : set_avma(av);
1594 168 : for (j = 1; j <= 3; j++)
1595 : {
1596 : pari_sp av2, av3;
1597 : GEN u;
1598 : long w, l;
1599 168 : rot3(sg[1], sg[3], sg[5])
1600 168 : rot3(sg[2], sg[4], sg[6])
1601 168 : rot3(pj[1], pj[2], pj[3])
1602 399 : for (l = 0; l < 2; l++, set_avma(av))
1603 : {
1604 308 : u = s4releveauto(liftp,Bcoeff,TQ,Q,sg[1],sg[3],sg[2],sg[4],sg[5],sg[6]);
1605 308 : liftpow = s4makelift(u, gl);
1606 308 : av2 = avma;
1607 847 : for (w = 0; w < 4; w += 2, set_avma(av2))
1608 : {
1609 : GEN uu;
1610 616 : pj[6] = (w + pj[3]) & 3;
1611 616 : uu = lincomb(B, sg[5], sg[6], pj[6]);
1612 616 : uu = FpX_red(uu, Q);
1613 616 : av3 = avma;
1614 2894 : for (i = 0; i < 4; i++, set_avma(av3))
1615 : {
1616 : GEN u;
1617 2355 : pj[4] = i;
1618 2355 : pj[5] = (i + pj[2] - pj[1]) & 3;
1619 2355 : if (DEBUGLEVEL >= 4)
1620 0 : err_printf("S4GaloisConj: Testing %d/3:%d/2:%d/2:%d/4:%Ps:%Ps\n",
1621 : j-1, w >> 1, l, i, sg, pj);
1622 2355 : u = ZX_add(lincomb(B,sg[1],sg[3],pj[4]),
1623 2355 : lincomb(B,sg[2],sg[4],pj[5]));
1624 2355 : u = FpX_add(uu,u,Q);
1625 2355 : if (s4test(u, liftpow, gl, tau)) goto suites4_2;
1626 : }
1627 : }
1628 231 : lswap(sg[3], sg[4]);
1629 231 : pj[2] = (-pj[2]) & 3;
1630 : }
1631 : }
1632 0 : return gc_NULL(ltop);
1633 77 : suites4_2:
1634 77 : set_avma(av);
1635 : {
1636 77 : long abc = (pj[1] + pj[2] + pj[3]) & 3;
1637 77 : long abcdef = ((abc + pj[4] + pj[5] - pj[6]) & 3) >> 1;
1638 : GEN u;
1639 : pari_sp av2;
1640 77 : u = s4releveauto(liftp,Bcoeff,TQ,Q,sg[1],sg[4],sg[2],sg[5],sg[3],sg[6]);
1641 77 : liftpow = s4makelift(u, gl);
1642 77 : av2 = avma;
1643 367 : for (j = 0; j < 8; j++)
1644 : {
1645 : long h, g, i;
1646 367 : h = j & 3;
1647 367 : g = (abcdef + ((j & 4) >> 1)) & 3;
1648 367 : i = (h + abc - g) & 3;
1649 367 : u = ZX_add(lincomb(B,sg[1],sg[4], g), lincomb(B,sg[2],sg[5], h));
1650 367 : u = FpX_add(u, lincomb(B,sg[3],sg[6], i),Q);
1651 367 : if (DEBUGLEVEL >= 4)
1652 0 : err_printf("S4GaloisConj: Testing %d/8 %d:%d:%d\n", j,g,h,i);
1653 367 : if (s4test(u, liftpow, gl, phi)) break;
1654 290 : set_avma(av2);
1655 : }
1656 : }
1657 77 : if (j == 8) return gc_NULL(ltop);
1658 1925 : for (i = 1; i <= n; i++)
1659 : {
1660 1848 : r1[i] = sigma[tau[i]];
1661 1848 : r2[i] = phi[sigma[tau[phi[i]]]];
1662 1848 : r3[i] = phi[sigma[i]];
1663 1848 : r4[i] = sigma[i];
1664 : }
1665 77 : set_avma(ltop2); return res;
1666 : }
1667 :
1668 : static GEN
1669 910 : f36releveauto2(GEN Bl, GEN T, GEN p,GEN a)
1670 : {
1671 910 : GEN F = gmael(Bl,a[1],a[1]);
1672 910 : F = ZX_add(F,gmael(Bl,a[2],a[3]));
1673 910 : F = ZX_add(F,gmael(Bl,a[3],a[2]));
1674 910 : F = ZX_add(F,gmael(Bl,a[4],a[5]));
1675 910 : F = ZX_add(F,gmael(Bl,a[5],a[4]));
1676 910 : F = ZX_add(F,gmael(Bl,a[6],a[7]));
1677 910 : F = ZX_add(F,gmael(Bl,a[7],a[6]));
1678 910 : F = ZX_add(F,gmael(Bl,a[8],a[9]));
1679 910 : F = ZX_add(F,gmael(Bl,a[9],a[8]));
1680 910 : return FpXQ_red(F, T, p);
1681 : }
1682 :
1683 : static GEN
1684 35 : f36releveauto4(GEN Bl, GEN T, GEN p,GEN a)
1685 : {
1686 35 : GEN F = gmael(Bl,a[1],a[1]);
1687 35 : F = ZX_add(F,gmael(Bl,a[2],a[3]));
1688 35 : F = ZX_add(F,gmael(Bl,a[3],a[4]));
1689 35 : F = ZX_add(F,gmael(Bl,a[4],a[5]));
1690 35 : F = ZX_add(F,gmael(Bl,a[5],a[2]));
1691 35 : F = ZX_add(F,gmael(Bl,a[6],a[7]));
1692 35 : F = ZX_add(F,gmael(Bl,a[7],a[8]));
1693 35 : F = ZX_add(F,gmael(Bl,a[8],a[9]));
1694 35 : F = ZX_add(F,gmael(Bl,a[9],a[6]));
1695 35 : return FpXQ_red(F, T, p);
1696 : }
1697 :
1698 : static GEN
1699 14 : f36galoisgen(struct galois_lift *gl)
1700 : {
1701 14 : const long n = 36;
1702 : struct galois_testlift gt;
1703 14 : pari_sp av, ltop2, ltop = avma;
1704 : long i;
1705 14 : GEN sigma, tau, rho, res, r1,r2,r3, pj, pk, p = gl->p, Q = gl->Q, TQ = gl->TQ;
1706 : GEN sg, s4, sp, Tp, Tmod, misom, Bcoeff, liftpow, aut, liftp, B, Bl, tam;
1707 14 : res = cgetg(3, t_VEC);
1708 14 : r1 = cgetg(n+1, t_VECSMALL);
1709 14 : r2 = cgetg(n+1, t_VECSMALL);
1710 14 : r3 = cgetg(n+1, t_VECSMALL);
1711 14 : gel(res,1)= mkvec3(r1,r2,r3);
1712 14 : gel(res,2) = mkvecsmall3(3,3,4);
1713 14 : ltop2 = avma;
1714 14 : sg = identity_perm(9);
1715 14 : s4 = identity_perm(9);
1716 14 : sp = identity_perm(9);
1717 14 : pj = zero_zv(4);
1718 14 : pk = zero_zv(2);
1719 14 : sigma = cgetg(n+1, t_VECSMALL);
1720 14 : tau = r3;
1721 14 : rho = cgetg(n+1, t_VECSMALL);
1722 14 : Tp = FpX_red(gl->T,p);
1723 14 : Tmod = gel(FpX_factor(Tp,p), 1);
1724 14 : misom = FpXV_ffisom(Tmod, p);
1725 14 : aut = galoisdolift(gl);
1726 14 : inittestlift(aut, Tmod, gl, >);
1727 14 : Bcoeff = gt.bezoutcoeff;
1728 14 : B = FqC_FqV_mul(gt.pauto, Bcoeff, gl->TQ, gl->Q);
1729 14 : liftp = mkliftpow(shallowtrans(misom), Tmod, p, gl);
1730 14 : Bl = FqC_FqV_mul(liftp,Bcoeff, gl->TQ, gl->Q);
1731 14 : av = avma;
1732 910 : for (i = 0; i < 105; i++, set_avma(av))
1733 : {
1734 : pari_sp av0, av1, av2, av3;
1735 : GEN u0, u1, u2, u3;
1736 : long j0, j1, j2, j3, s;
1737 910 : if (i)
1738 : {
1739 896 : rot3(sg[7],sg[8],sg[9])
1740 896 : if (i%3==0)
1741 : {
1742 294 : s=sg[5]; sg[5]=sg[6]; sg[6]=sg[7]; sg[7]=sg[8]; sg[8]=sg[9]; sg[9]=s;
1743 294 : if (i%15==0)
1744 : {
1745 49 : s=sg[3]; sg[3]=sg[4]; sg[4]=sg[5];
1746 49 : sg[5]=sg[6]; sg[6]=sg[7]; sg[7]=sg[8]; sg[8]=sg[9]; sg[9]=s;
1747 : }
1748 : }
1749 : }
1750 910 : liftpow = s4makelift(f36releveauto2(Bl, TQ, Q, sg), gl);
1751 910 : av0 = avma;
1752 4522 : for (j0 = 0; j0 < 4; j0++, set_avma(av0))
1753 : {
1754 3626 : u0 = lincomb(B,sg[8],sg[9],j0);
1755 3626 : u0 = FpX_add(u0, gmael(B,sg[1],3), Q); av1 = avma;
1756 18095 : for (j1 = 0; j1 < 4; j1++, set_avma(av1))
1757 : {
1758 14483 : u1 = lincomb(B,sg[6],sg[7],j1);
1759 14483 : u1 = FpX_add(u0, u1, Q); av2 = avma;
1760 72380 : for (j2 = 0; j2 < 4; j2++, set_avma(av2))
1761 : {
1762 57911 : u2 = lincomb(B,sg[4],sg[5],j2);
1763 57911 : u2 = FpX_add(u1, u2, Q); av3 = avma;
1764 289527 : for (j3 = 0; j3 < 4; j3++, set_avma(av3))
1765 : {
1766 231630 : u3 = lincomb(B,sg[2],sg[3],j3);
1767 231630 : u3 = FpX_add(u2, u3, Q);
1768 231630 : if (s4test(u3, liftpow, gl, sigma))
1769 : {
1770 14 : pj[1] = j3;
1771 14 : pj[2] = j2;
1772 14 : pj[3] = j1;
1773 14 : pj[4] = j0; goto suitef36;
1774 : }
1775 : }
1776 : }
1777 : }
1778 : }
1779 : }
1780 0 : return gc_NULL(ltop);
1781 14 : suitef36:
1782 14 : s4[1]=sg[1]; s4[2]=sg[2]; s4[4]=sg[3];
1783 14 : s4[3]=sg[4]; s4[5]=sg[5]; s4[6]=sg[6];
1784 14 : s4[8]=sg[7]; s4[7]=sg[8]; s4[9]=sg[9];
1785 14 : for (i = 0; i < 12; i++, set_avma(av))
1786 : {
1787 : pari_sp av0, av1;
1788 : GEN u0, u1;
1789 : long j0, j1;
1790 14 : if (i)
1791 : {
1792 0 : lswap(s4[3],s4[5]); pj[2] = (-pj[2])&3;
1793 0 : if (odd(i)) { lswap(s4[7],s4[9]); pj[4]=(-pj[4])&3; }
1794 0 : if (i%4==0)
1795 : {
1796 0 : rot3(s4[3],s4[6],s4[7]);
1797 0 : rot3(s4[5],s4[8],s4[9]);
1798 0 : rot3(pj[2],pj[3],pj[4]);
1799 : }
1800 : }
1801 14 : liftpow = s4makelift(f36releveauto4(Bl, TQ, Q, s4), gl);
1802 14 : av0 = avma;
1803 21 : for (j0 = 0; j0 < 4; j0++, set_avma(av0))
1804 : {
1805 21 : u0 = FpX_add(gmael(B,s4[1],2), gmael(B,s4[2],1+j0),Q);
1806 21 : u0 = FpX_add(u0, gmael(B,s4[3],1+smodss(pj[2]-j0,4)),Q);
1807 21 : u0 = FpX_add(u0, gmael(B,s4[4],1+smodss(j0-pj[1]-pj[2],4)),Q);
1808 21 : u0 = FpX_add(u0, gmael(B,s4[5],1+smodss(pj[1]-j0,4)),Q);
1809 21 : av1 = avma;
1810 84 : for (j1 = 0; j1 < 4; j1++, set_avma(av1))
1811 : {
1812 77 : u1 = FpX_add(u0, gmael(B,s4[6],1+j1),Q);
1813 77 : u1 = FpX_add(u1, gmael(B,s4[7],1+smodss(pj[4]-j1,4)),Q);
1814 77 : u1 = FpX_add(u1, gmael(B,s4[8],1+smodss(j1-pj[3]-pj[4],4)),Q);
1815 77 : u1 = FpX_add(u1, gmael(B,s4[9],1+smodss(pj[3]-j1,4)),Q);
1816 77 : if (s4test(u1, liftpow, gl, tau))
1817 : {
1818 14 : pk[1] = j0;
1819 14 : pk[2] = j1; goto suitef36_2;
1820 : }
1821 : }
1822 : }
1823 : }
1824 0 : return gc_NULL(ltop);
1825 14 : suitef36_2:
1826 14 : sp[1]=s4[9]; sp[2]=s4[1]; sp[3]=s4[2];
1827 14 : sp[4]=s4[7]; sp[5]=s4[3]; sp[6]=s4[8];
1828 14 : sp[8]=s4[4]; sp[7]=s4[5]; sp[9]=s4[6];
1829 21 : for (i = 0; i < 4; i++, set_avma(av))
1830 : {
1831 21 : const int w[4][6]={{0,0,1,3,0,2},{1,0,2,1,1,2},{3,3,2,0,3,1},{0,1,3,0,0,3}};
1832 : pari_sp av0, av1, av2;
1833 : GEN u0, u1, u2;
1834 : long j0, j1,j2,j3,j4,j5;
1835 21 : if (i)
1836 : {
1837 7 : rot4(sp[3],sp[5],sp[8],sp[7])
1838 7 : pk[1]=(-pk[1])&3;
1839 : }
1840 21 : liftpow = s4makelift(f36releveauto4(Bl,TQ,Q,sp), gl);
1841 21 : av0 = avma;
1842 56 : for (j0 = 0; j0 < 4; j0++, set_avma(av0))
1843 : {
1844 49 : u0 = FpX_add(gmael(B,sp[1],2), gmael(B,sp[2],1+j0),Q);
1845 49 : av1 = avma;
1846 210 : for (j1 = 0; j1 < 4; j1++, set_avma(av1))
1847 : {
1848 175 : u1 = FpX_add(u0, gmael(B,sp[3],1+j1),Q);
1849 175 : j3 = (-pk[1]-pj[3]+j0+j1-w[i][0]*pj[1]-w[i][3]*pj[2])&3;
1850 175 : u1 = FpX_add(u1, gmael(B,sp[6],1+j3),Q);
1851 175 : j5 = (-pk[1]+2*j0+2*j1-w[i][2]*pj[1]-w[i][5]*pj[2])&3;
1852 175 : u1 = FpX_add(u1, gmael(B,sp[8],1+j5),Q);
1853 175 : av2 = avma;
1854 847 : for (j2 = 0; j2 < 4; j2++, set_avma(av2))
1855 : {
1856 686 : u2 = FpX_add(u1, gmael(B,sp[4],1+j2),Q);
1857 686 : u2 = FpX_add(u2, gmael(B,sp[5],1+smodss(-j0-j1-j2,4)),Q);
1858 686 : j4 = (-pk[1]-pk[2]+pj[3]+pj[4]-j2-w[i][1]*pj[1]-w[i][4]*pj[2])&3;
1859 686 : u2 = FpX_add(u2, gmael(B,sp[7],1+j4),Q);
1860 686 : u2 = FpX_add(u2, gmael(B,sp[9],1+smodss(-j3-j4-j5,4)),Q);
1861 686 : if (s4test(u2, liftpow, gl, rho))
1862 14 : goto suitef36_3;
1863 : }
1864 : }
1865 : }
1866 : }
1867 0 : return gc_NULL(ltop);
1868 14 : suitef36_3:
1869 14 : tam = perm_inv(tau);
1870 518 : for (i = 1; i <= n; i++)
1871 : {
1872 504 : r1[tau[i]] = rho[i];
1873 504 : r2[i] = tam[rho[i]];
1874 : }
1875 14 : set_avma(ltop2); return res;
1876 : }
1877 :
1878 : /* return a vecvecsmall */
1879 : static GEN
1880 98 : galoisfindgroups(GEN lo, GEN sg, long f)
1881 : {
1882 98 : pari_sp ltop = avma;
1883 : long i, j, k;
1884 98 : GEN V = cgetg(lg(lo), t_VEC);
1885 287 : for(j=1,i=1; i<lg(lo); i++)
1886 : {
1887 189 : pari_sp av = avma;
1888 189 : GEN loi = gel(lo,i), W = cgetg(lg(loi),t_VECSMALL);
1889 476 : for (k=1; k<lg(loi); k++) W[k] = loi[k] % f;
1890 189 : W = vecsmall_uniq(W);
1891 189 : if (zv_equal(W, sg)) gel(V,j++) = loi;
1892 189 : set_avma(av);
1893 : }
1894 98 : setlg(V,j); return gerepilecopy(ltop,V);
1895 : }
1896 :
1897 : static GEN
1898 1729 : galoismakepsi(long g, GEN sg, GEN pf)
1899 : {
1900 1729 : GEN psi=cgetg(g+1,t_VECSMALL);
1901 : long i;
1902 4200 : for (i = 1; i < g; i++) psi[i] = sg[pf[i]];
1903 1729 : psi[g] = sg[1]; return psi;
1904 : }
1905 :
1906 : static GEN
1907 27506 : galoisfrobeniuslift_nilp(GEN T, GEN den, GEN L, GEN Lden,
1908 : struct galois_frobenius *gf, struct galois_borne *gb)
1909 : {
1910 27506 : pari_sp ltop=avma, av2;
1911 : struct galois_lift gl;
1912 27506 : long i, k, deg = 1, g = lg(gf->Tmod)-1;
1913 27506 : GEN F,Fp,Fe, aut, frob, res = cgetg(lg(L), t_VECSMALL);
1914 27506 : gf->psi = const_vecsmall(g,1);
1915 27506 : av2 = avma;
1916 27506 : initlift(T, den, gf->p, L, Lden, gb, &gl);
1917 27503 : if (DEBUGLEVEL >= 4)
1918 0 : err_printf("GaloisConj: p=%ld e=%ld deg=%ld fp=%ld\n",
1919 : gf->p, gl.e, deg, gf->fp);
1920 27503 : aut = galoisdolift(&gl);
1921 27506 : if (galoisfrobeniustest(aut,&gl,res))
1922 : {
1923 26229 : set_avma(av2); gf->deg = gf->fp; return res;
1924 : }
1925 :
1926 1277 : F =factoru(gf->fp);
1927 1277 : Fp = gel(F,1);
1928 1277 : Fe = gel(F,2);
1929 1277 : frob = cgetg(lg(L), t_VECSMALL);
1930 2554 : for(k = lg(Fp)-1; k>=1; k--)
1931 : {
1932 1277 : pari_sp btop=avma;
1933 1277 : GEN fres=NULL;
1934 1277 : long el = gf->fp, dg = 1, dgf = 1, e, pr;
1935 2498 : for(e=1; e<=Fe[k]; e++)
1936 : {
1937 2498 : dg *= Fp[k]; el /= Fp[k];
1938 2498 : if (DEBUGLEVEL>=4) err_printf("Trying degre %d.\n",dg);
1939 2498 : if (el==1) break;
1940 1347 : aut = galoisdoliftn(&gl, el);
1941 1347 : if (!galoisfrobeniustest(aut,&gl,frob))
1942 126 : break;
1943 1221 : dgf = dg; fres = gcopy(frob);
1944 : }
1945 1277 : if (dgf == 1) { set_avma(btop); continue; }
1946 1158 : pr = deg*dgf;
1947 1158 : if (deg == 1)
1948 : {
1949 15562 : for(i=1;i<lg(res);i++) res[i]=fres[i];
1950 : }
1951 : else
1952 : {
1953 0 : GEN cp = perm_mul(res,fres);
1954 0 : for(i=1;i<lg(res);i++) res[i] = cp[i];
1955 : }
1956 1158 : deg = pr; set_avma(btop);
1957 : }
1958 1277 : if (DEBUGLEVEL>=4 && res) err_printf("Best lift: %d\n",deg);
1959 1277 : if (deg==1) return gc_NULL(ltop);
1960 : else
1961 : {
1962 1158 : set_avma(av2); gf->deg = deg; return res;
1963 : }
1964 : }
1965 :
1966 : static GEN
1967 2233 : galoisfrobeniuslift(GEN T, GEN den, GEN L, GEN Lden,
1968 : struct galois_frobenius *gf, struct galois_borne *gb)
1969 : {
1970 2233 : pari_sp ltop=avma, av2;
1971 : struct galois_testlift gt;
1972 : struct galois_lift gl;
1973 2233 : long i, j, k, n = lg(L)-1, deg = 1, g = lg(gf->Tmod)-1;
1974 2233 : GEN F,Fp,Fe, aut, frob, res = cgetg(lg(L), t_VECSMALL);
1975 2233 : gf->psi = const_vecsmall(g,1);
1976 2233 : av2 = avma;
1977 2233 : initlift(T, den, gf->p, L, Lden, gb, &gl);
1978 2233 : if (DEBUGLEVEL >= 4)
1979 0 : err_printf("GaloisConj: p=%ld e=%ld deg=%ld fp=%ld\n",
1980 : gf->p, gl.e, deg, gf->fp);
1981 2233 : aut = galoisdolift(&gl);
1982 2233 : if (galoisfrobeniustest(aut,&gl,res))
1983 : {
1984 553 : set_avma(av2); gf->deg = gf->fp; return res;
1985 : }
1986 1680 : inittestlift(aut,gf->Tmod, &gl, >);
1987 1680 : gt.C = cgetg(gf->fp+1,t_VEC);
1988 1680 : gt.Cd= cgetg(gf->fp+1,t_VEC);
1989 9359 : for (i = 1; i <= gf->fp; i++) {
1990 7679 : gel(gt.C,i) = zero_zv(gt.g);
1991 7679 : gel(gt.Cd,i) = zero_zv(gt.g);
1992 : }
1993 :
1994 1680 : F =factoru(gf->fp);
1995 1680 : Fp = gel(F,1);
1996 1680 : Fe = gel(F,2);
1997 1680 : frob = cgetg(lg(L), t_VECSMALL);
1998 3556 : for(k=lg(Fp)-1;k>=1;k--)
1999 : {
2000 1876 : pari_sp btop=avma;
2001 1876 : GEN psi=NULL, fres=NULL, sg = identity_perm(1);
2002 1876 : long el=gf->fp, dg=1, dgf=1, e, pr;
2003 3801 : for(e=1; e<=Fe[k]; e++)
2004 : {
2005 : GEN lo, pf;
2006 : long l;
2007 1974 : dg *= Fp[k]; el /= Fp[k];
2008 1974 : if (DEBUGLEVEL>=4) err_printf("Trying degre %d.\n",dg);
2009 1974 : if (galoisfrobeniustest(gel(gt.pauto,el+1),&gl,frob))
2010 : {
2011 196 : psi = const_vecsmall(g,1);
2012 196 : dgf = dg; fres = leafcopy(frob); continue;
2013 : }
2014 1778 : lo = listznstarelts(dg, n / gf->fp);
2015 1778 : if (e!=1) lo = galoisfindgroups(lo, sg, dgf);
2016 1778 : if (DEBUGLEVEL>=4) err_printf("Galoisconj:Subgroups list:%Ps\n", lo);
2017 3773 : for (l = 1; l < lg(lo); l++)
2018 3724 : if (lg(gel(lo,l))>2 && frobeniusliftall(gel(lo,l), el, &pf,&gl,>, frob))
2019 : {
2020 1729 : sg = leafcopy(gel(lo,l));
2021 1729 : psi = galoismakepsi(g,sg,pf);
2022 1729 : dgf = dg; fres = leafcopy(frob); break;
2023 : }
2024 1778 : if (l == lg(lo)) break;
2025 : }
2026 1876 : if (dgf == 1) { set_avma(btop); continue; }
2027 1841 : pr = deg*dgf;
2028 1841 : if (deg == 1)
2029 : {
2030 20552 : for(i=1;i<lg(res);i++) res[i]=fres[i];
2031 5761 : for(i=1;i<lg(psi);i++) gf->psi[i]=psi[i];
2032 : }
2033 : else
2034 : {
2035 161 : GEN cp = perm_mul(res,fres);
2036 3059 : for(i=1;i<lg(res);i++) res[i] = cp[i];
2037 525 : for(i=1;i<lg(psi);i++) gf->psi[i] = (dgf*gf->psi[i] + deg*psi[i]) % pr;
2038 : }
2039 1841 : deg = pr; set_avma(btop);
2040 : }
2041 9359 : for (i = 1; i <= gf->fp; i++)
2042 26551 : for (j = 1; j <= gt.g; j++) guncloneNULL(gmael(gt.C,i,j));
2043 1680 : if (DEBUGLEVEL>=4 && res) err_printf("Best lift: %d\n",deg);
2044 1680 : if (deg==1) return gc_NULL(ltop);
2045 : else
2046 : {
2047 : /* Normalize result so that psi[g]=1 */
2048 1680 : ulong im = Fl_inv(gf->psi[g], deg);
2049 1680 : GEN cp = perm_powu(res, im);
2050 20552 : for(i=1;i<lg(res);i++) res[i] = cp[i];
2051 5761 : for(i=1;i<lg(gf->psi);i++) gf->psi[i] = Fl_mul(im, gf->psi[i], deg);
2052 1680 : set_avma(av2); gf->deg = deg; return res;
2053 : }
2054 : }
2055 :
2056 : /* return NULL if not Galois */
2057 : static GEN
2058 29634 : galoisfindfrobenius(GEN T, GEN L, GEN den, GEN bad, struct galois_frobenius *gf,
2059 : struct galois_borne *gb, const struct galois_analysis *ga)
2060 : {
2061 29634 : pari_sp ltop = avma, av;
2062 29634 : long Try = 0, n = degpol(T), deg, gmask = (ga->group&ga_ext_2)? 3: 1;
2063 29634 : GEN frob, Lden = makeLden(L,den,gb);
2064 29631 : long is_nilpotent = ga->group&ga_all_nilpotent;
2065 : forprime_t S;
2066 :
2067 29631 : u_forprime_init(&S, ga->p, ULONG_MAX);
2068 29634 : av = avma;
2069 29634 : deg = gf->deg = ga->deg;
2070 29767 : while ((gf->p = u_forprime_next(&S)))
2071 : {
2072 : pari_sp lbot;
2073 : GEN Ti, Tp;
2074 : long nb, d;
2075 29767 : set_avma(av);
2076 29767 : Tp = ZX_to_Flx(T, gf->p);
2077 29767 : if (!Flx_is_squarefree(Tp, gf->p)) continue;
2078 29766 : if (bad && dvdiu(bad, gf->p)) continue;
2079 29766 : Ti = gel(Flx_factor(Tp, gf->p), 1);
2080 29767 : nb = lg(Ti)-1; d = degpol(gel(Ti,1));
2081 29767 : if (nb > 1 && degpol(gel(Ti,nb)) != d) return gc_NULL(ltop);
2082 29753 : if (((gmask&1)==0 || d % deg) && ((gmask&2)==0 || odd(d))) continue;
2083 29739 : if (DEBUGLEVEL >= 1) err_printf("GaloisConj: Trying p=%ld\n", gf->p);
2084 29739 : FlxV_to_ZXV_inplace(Ti);
2085 29739 : gf->fp = d;
2086 29739 : gf->Tmod = Ti; lbot = avma;
2087 29739 : if (is_nilpotent)
2088 27506 : frob = galoisfrobeniuslift_nilp(T, den, L, Lden, gf, gb);
2089 : else
2090 2233 : frob = galoisfrobeniuslift(T, den, L, Lden, gf, gb);
2091 29739 : if (frob)
2092 : {
2093 : GEN *gptr[3];
2094 29620 : gf->Tmod = gcopy(Ti);
2095 29620 : gptr[0]=&gf->Tmod; gptr[1]=&gf->psi; gptr[2]=&frob;
2096 29620 : gerepilemanysp(ltop,lbot,gptr,3); return frob;
2097 : }
2098 119 : if (is_nilpotent) continue;
2099 0 : if ((ga->group&ga_all_normal) && d % deg == 0) gmask &= ~1;
2100 : /* The first prime degree is always divisible by deg, so we don't
2101 : * have to worry about ext_2 being used before regular supersolvable*/
2102 0 : if (!gmask) return gc_NULL(ltop);
2103 0 : if ((ga->group&ga_non_wss) && ++Try > ((3*n)>>1))
2104 : {
2105 0 : if (DEBUGLEVEL)
2106 0 : pari_warn(warner,"Galois group probably not weakly super solvable");
2107 0 : return NULL;
2108 : }
2109 : }
2110 0 : if (!gf->p) pari_err_OVERFLOW("galoisfindfrobenius [ran out of primes]");
2111 0 : return NULL;
2112 : }
2113 :
2114 : /* compute g such that tau(Pmod[#])= tau(Pmod[g]) */
2115 :
2116 : static long
2117 6576 : get_image(GEN tau, GEN P, GEN Pmod, GEN p)
2118 : {
2119 6576 : pari_sp av = avma;
2120 6576 : long g, gp = lg(Pmod)-1;
2121 6576 : tau = RgX_to_FpX(tau, p);
2122 6576 : tau = FpX_FpXQ_eval(gel(Pmod, gp), tau, P, p);
2123 6576 : tau = FpX_normalize(FpX_gcd(P, tau, p), p);
2124 10697 : for (g = 1; g <= gp; g++)
2125 10697 : if (ZX_equal(tau, gel(Pmod,g))) return gc_long(av,g);
2126 0 : return gc_long(av,0);
2127 : }
2128 :
2129 : static GEN
2130 33844 : gg_get_std(GEN G)
2131 : {
2132 33844 : return !G ? NULL: lg(G)==3 ? G: mkvec2(gel(G,1),gmael(G,5,1));
2133 : }
2134 :
2135 : static GEN galoisgen(GEN T, GEN L, GEN M, GEN den, GEN bad, struct galois_borne *gb,
2136 : const struct galois_analysis *ga);
2137 :
2138 : static GEN
2139 5372 : galoisgenfixedfield(GEN Tp, GEN Pmod, GEN PL, GEN P, GEN ip, GEN bad, struct galois_borne *gb)
2140 : {
2141 : GEN Pden, PM;
2142 : GEN tau, PG, Pg;
2143 : long g, lP;
2144 5372 : long x = varn(Tp);
2145 5372 : GEN Pp = FpX_red(P, ip);
2146 5372 : if (DEBUGLEVEL>=6)
2147 0 : err_printf("GaloisConj: Fixed field %Ps\n",P);
2148 5372 : if (degpol(P)==2 && !bad)
2149 : {
2150 4028 : PG=cgetg(3,t_VEC);
2151 4028 : gel(PG,1) = mkvec( mkvecsmall2(2,1) );
2152 4028 : gel(PG,2) = mkvecsmall(2);
2153 4028 : tau = deg1pol_shallow(gen_m1, negi(gel(P,3)), x);
2154 4028 : g = get_image(tau, Pp, Pmod, ip);
2155 4028 : if (!g) return NULL;
2156 4028 : Pg = mkvecsmall(g);
2157 : }
2158 : else
2159 : {
2160 : struct galois_analysis Pga;
2161 : struct galois_borne Pgb;
2162 : GEN mod, mod2;
2163 : long j;
2164 1351 : if (!galoisanalysis(P, &Pga, 0, NULL)) return NULL;
2165 1330 : if (bad) Pga.group &= ~ga_easy;
2166 1330 : Pgb.l = gb->l;
2167 1330 : Pden = galoisborne(P, NULL, &Pgb, degpol(P));
2168 :
2169 1330 : if (Pgb.valabs > gb->valabs)
2170 : {
2171 125 : if (DEBUGLEVEL>=4)
2172 0 : err_printf("GaloisConj: increase prec of p-adic roots of %ld.\n"
2173 0 : ,Pgb.valabs-gb->valabs);
2174 125 : PL = ZpX_liftroots(P,PL,gb->l,Pgb.valabs);
2175 : }
2176 1205 : else if (Pgb.valabs < gb->valabs)
2177 1141 : PL = FpC_red(PL, Pgb.ladicabs);
2178 1330 : PM = FpV_invVandermonde(PL, Pden, Pgb.ladicabs);
2179 1330 : PG = galoisgen(P, PL, PM, Pden, bad ? lcmii(Pgb.dis, bad): NULL, &Pgb, &Pga);
2180 1330 : if (!PG) return NULL;
2181 1323 : lP = lg(gel(PG,1));
2182 1323 : mod = Pgb.ladicabs; mod2 = shifti(mod, -1);
2183 1323 : Pg = cgetg(lP, t_VECSMALL);
2184 3871 : for (j = 1; j < lP; j++)
2185 : {
2186 2548 : pari_sp btop=avma;
2187 2548 : tau = permtopol(gmael(PG,1,j), PL, PM, Pden, mod, mod2, x);
2188 2548 : g = get_image(tau, Pp, Pmod, ip);
2189 2548 : if (!g) return NULL;
2190 2548 : Pg[j] = g;
2191 2548 : set_avma(btop);
2192 : }
2193 : }
2194 5351 : return mkvec2(PG,Pg);
2195 : }
2196 :
2197 : static GEN
2198 5372 : galoisgenfixedfield0(GEN O, GEN L, GEN sigma, GEN T, GEN bad, GEN *pt_V,
2199 : struct galois_frobenius *gf, struct galois_borne *gb)
2200 : {
2201 5372 : pari_sp btop = avma;
2202 5372 : long vT = varn(T);
2203 5372 : GEN mod = gb->ladicabs, mod2 = shifti(gb->ladicabs,-1);
2204 : GEN OL, sym, P, PL, p, Tp, Sp, Pmod, PG;
2205 5372 : OL = fixedfieldorbits(O,L);
2206 5372 : sym = fixedfieldsympol(OL, itou(gb->l));
2207 5372 : PL = sympol_eval(sym, OL, mod);
2208 5372 : P = FpX_center_i(FpV_roots_to_pol(PL, mod, vT), mod, mod2);
2209 5372 : if (!FpX_is_squarefree(P,utoipos(gf->p)))
2210 : {
2211 73 : GEN badp = lcmii(bad? bad: gb->dis, ZX_disc(P));
2212 73 : gf->p = findpsi(badp, gf->p, T, sigma, gf->deg, &gf->Tmod, &gf->psi);
2213 : }
2214 5372 : p = utoipos(gf->p);
2215 5372 : Tp = FpX_red(T,p);
2216 5372 : Sp = sympol_aut_evalmod(sym, gf->deg, sigma, Tp, p);
2217 5372 : Pmod = fixedfieldfactmod(Sp, p, gf->Tmod);
2218 5372 : PG = galoisgenfixedfield(Tp, Pmod, PL, P, p, bad, gb);
2219 5372 : if (PG == NULL) return NULL;
2220 5351 : if (DEBUGLEVEL >= 4)
2221 0 : err_printf("GaloisConj: Back to Earth:%Ps\n", gg_get_std(gel(PG,1)));
2222 5351 : if (pt_V) *pt_V = mkvec3(sym, PL, P);
2223 5351 : return gc_all(btop, pt_V ? 4: 3, &PG, &gf->Tmod, &gf->psi, pt_V);
2224 : }
2225 :
2226 : /* Let sigma^m=1, tau*sigma*tau^-1=sigma^s. Return n = sum_{0<=k<e,0} s^k mod m
2227 : * so that (sigma*tau)^e = sigma^n*tau^e. N.B. n*(1-s) = 1-s^e mod m,
2228 : * unfortunately (1-s) may not invertible mod m */
2229 : static long
2230 14636 : stpow(long s, long e, long m)
2231 : {
2232 14636 : long i, n = 1;
2233 22892 : for (i = 1; i < e; i++) n = (1 + n * s) % m;
2234 14636 : return n;
2235 : }
2236 :
2237 : static GEN
2238 6576 : wpow(long s, long m, long e, long n)
2239 : {
2240 6576 : GEN w = cgetg(n+1,t_VECSMALL);
2241 6576 : long si = s;
2242 : long i;
2243 6576 : w[1] = 1;
2244 7318 : for(i=2; i<=n; i++) w[i] = w[i-1]*e;
2245 13894 : for(i=n; i>=1; i--)
2246 : {
2247 7318 : si = Fl_powu(si,e,m);
2248 7318 : w[i] = Fl_mul(s-1, stpow(si, w[i], m), m);
2249 : }
2250 6576 : return w;
2251 : }
2252 :
2253 : static GEN
2254 6576 : galoisgenliftauto(GEN O, GEN gj, long s, long n, struct galois_test *td)
2255 : {
2256 6576 : pari_sp av = avma;
2257 : long sr, k;
2258 6576 : long deg = lg(gel(O,1))-1;
2259 6576 : GEN X = cgetg(lg(O), t_VECSMALL);
2260 6576 : GEN oX = cgetg(lg(O), t_VECSMALL);
2261 6576 : GEN B = perm_cycles(gj);
2262 6576 : long oj = lg(gel(B,1)) - 1;
2263 6576 : GEN F = factoru(oj);
2264 6576 : GEN Fp = gel(F,1);
2265 6576 : GEN Fe = gel(F,2);
2266 6576 : GEN pf = identity_perm(n);
2267 6576 : if (DEBUGLEVEL >= 6)
2268 0 : err_printf("GaloisConj: %Ps of relative order %d\n", gj, oj);
2269 12491 : for (k=lg(Fp)-1; k>=1; k--)
2270 : {
2271 6576 : long f, dg = 1, el = oj, osel = 1, a = 0;
2272 6576 : long p = Fp[k], e = Fe[k], op = oj / upowuu(p,e);
2273 : long i;
2274 6576 : GEN pf1 = NULL, w, wg, Be = cgetg(e+1,t_VEC);
2275 6576 : gel(Be,e) = cyc_pow(B, op);
2276 7318 : for(i=e-1; i>=1; i--) gel(Be,i) = cyc_pow(gel(Be,i+1), p);
2277 6576 : w = wpow(Fl_powu(s,op,deg),deg,p,e);
2278 6576 : wg = cgetg(e+2,t_VECSMALL);
2279 6576 : wg[e+1] = deg;
2280 13894 : for (i=e; i>=1; i--) wg[i] = ugcd(wg[i+1], w[i]);
2281 36591 : for (i=1; i<lg(O); i++) oX[i] = 0;
2282 13233 : for (f=1; f<=e; f++)
2283 : {
2284 : long sel, t;
2285 7318 : GEN Bel = gel(Be,f);
2286 7318 : dg *= p; el /= p;
2287 7318 : sel = Fl_powu(s,el,deg);
2288 7318 : if (DEBUGLEVEL >= 6) err_printf("GaloisConj: B=%Ps\n", Bel);
2289 7318 : sr = ugcd(stpow(sel,p,deg),deg);
2290 7318 : if (DEBUGLEVEL >= 6)
2291 0 : err_printf("GaloisConj: exp %d: s=%ld [%ld] a=%ld w=%ld wg=%ld sr=%ld\n",
2292 0 : dg, sel, deg, a, w[f], wg[f+1], sr);
2293 9536 : for (t = 0; t < sr; t++)
2294 8875 : if ((a+t*w[f])%wg[f+1]==0)
2295 : {
2296 : long i, j, k, st;
2297 58384 : for (i = 1; i < lg(X); i++) X[i] = 0;
2298 30630 : for (i = 0; i < lg(X)-1; i+=dg)
2299 46492 : for (j = 1, k = p, st = t; k <= dg; j++, k += p)
2300 : {
2301 24667 : X[k+i] = (oX[j+i] + st)%deg;
2302 24667 : st = (t + st*osel)%deg;
2303 : }
2304 8805 : pf1 = testpermutation(O, Bel, X, sel, p, sr, td);
2305 8805 : if (pf1) break;
2306 : }
2307 7318 : if (!pf1) return NULL;
2308 43134 : for (i=1; i<lg(O); i++) oX[i] = X[i];
2309 6657 : osel = sel; a = (a+t*w[f])%deg;
2310 : }
2311 5915 : pf = perm_mul(pf, perm_powu(pf1, el));
2312 : }
2313 5915 : return gerepileuptoleaf(av, pf);
2314 : }
2315 :
2316 : static GEN
2317 0 : FlxV_Flx_gcd(GEN x, GEN T, ulong p)
2318 0 : { pari_APPLY_same(Flx_normalize(Flx_gcd(gel(x,i),T,p),p)) }
2319 :
2320 : static GEN
2321 0 : Flx_FlxV_minpolymod(GEN y, GEN x, ulong p)
2322 0 : { pari_APPLY_same(Flxq_minpoly(Flx_rem(y, gel(x,i), p), gel(x,i), p)) }
2323 :
2324 : static GEN
2325 0 : FlxV_minpolymod(GEN x, GEN y, ulong p)
2326 0 : { pari_APPLY_same(Flx_FlxV_minpolymod(gel(x,i), y, p)) }
2327 :
2328 : static GEN
2329 0 : factperm(GEN x)
2330 : {
2331 0 : pari_APPLY_same(gen_indexsort(gel(x,i), (void*)cmp_Flx, cmp_nodata))
2332 : }
2333 :
2334 : /* compute (prod p_i^e_i)(1) */
2335 :
2336 : static long
2337 0 : permprodeval(GEN p, GEN e, long s)
2338 : {
2339 0 : long i, j, l = lg(p);
2340 0 : for (i=l-1; i>=1; i--)
2341 : {
2342 0 : GEN pi = gel(p,i);
2343 0 : long ei = uel(e,i);
2344 0 : for(j = 1; j <= ei; j++)
2345 0 : s = uel(pi, s);
2346 : }
2347 0 : return s;
2348 : }
2349 :
2350 : static GEN
2351 0 : pc_to_perm(GEN pc, GEN gen, long n)
2352 : {
2353 0 : long i, l = lg(pc);
2354 0 : GEN s = identity_perm(n);
2355 0 : for (i=1; i<l; i++)
2356 0 : s = perm_mul(gel(gen,pc[i]),s);
2357 0 : return s;
2358 : }
2359 :
2360 : static GEN
2361 0 : genorbit(GEN ordH, GEN permfact_Hp, long fr, long n, long k, long j)
2362 : {
2363 0 : pari_sp av = avma;
2364 0 : long l = lg(gel(permfact_Hp,1))-1, no = 1, b, i;
2365 0 : GEN W = zero_zv(l);
2366 0 : GEN orb = cgetg(l+1, t_VECSMALL);
2367 0 : GEN gen = cgetg(l+1, t_VEC);
2368 0 : GEN E = cgetg(k+1, t_VECSMALL);
2369 0 : for(b = 0; b < n; b++)
2370 : {
2371 0 : long bb = b, s;
2372 0 : for(i = 1; i <= k; i++)
2373 : {
2374 0 : uel(E,i) = bb % uel(ordH,i);
2375 0 : bb /= uel(ordH,i);
2376 : }
2377 0 : if (E[j]) continue;
2378 0 : s = permprodeval(permfact_Hp, E, fr);
2379 0 : if (s>lg(W)-1) pari_err_BUG("W1");
2380 0 : if (W[s]) continue;
2381 0 : W[s] = 1;
2382 0 : if (no > l) pari_err_BUG("genorbit");
2383 0 : uel(orb,no) = s;
2384 0 : gel(gen,no) = zv_copy(E);
2385 0 : no++;
2386 : }
2387 0 : if(no<l) pari_err_BUG("genorbit");
2388 0 : return gerepilecopy(av, mkvec2(orb,gen));
2389 : }
2390 :
2391 0 : INLINE GEN br_get(GEN br, long i, long j) { return gmael(br,j,i-j); }
2392 0 : static GEN pcgrp_get_ord(GEN G) { return gel(G,1); }
2393 0 : static GEN pcgrp_get_pow(GEN G) { return gel(G,2); }
2394 0 : static GEN pcgrp_get_br(GEN G) { return gel(G,3); }
2395 :
2396 : static GEN
2397 24247 : cyclic_pc(long n)
2398 : {
2399 24247 : return mkvec3(mkvecsmall(n),mkvec(cgetg(1,t_VECSMALL)), mkvec(cgetg(1,t_VEC)));
2400 : }
2401 :
2402 : static GEN
2403 0 : pc_normalize(GEN g, GEN G)
2404 : {
2405 0 : long i, l = lg(g)-1, o = 1;
2406 0 : GEN ord = pcgrp_get_ord(G), pw = pcgrp_get_pow(G), br = pcgrp_get_br(G);
2407 0 : for (i = 1; i < l; i++)
2408 : {
2409 0 : if (g[i] == g[i+1])
2410 : {
2411 0 : if (++o == ord[g[i]])
2412 : {
2413 0 : GEN v = vecsmall_concat(vecslice(g,1,i-o+1),gel(pw,g[i]));
2414 0 : GEN w = vecsmall_concat(v,vecslice(g,i+2,l));
2415 0 : return pc_normalize(w, G);
2416 : }
2417 : }
2418 0 : else if (g[i] > g[i+1])
2419 : {
2420 0 : GEN v = vecsmall_concat(vecslice(g,1,i-1), br_get(br,g[i],g[i+1]));
2421 0 : GEN w = vecsmall_concat(mkvecsmall2(g[i+1],g[i]),vecslice(g,i+2,l));
2422 0 : v = vecsmall_concat(v, w);
2423 0 : return pc_normalize(v, G);
2424 : }
2425 0 : else o = 1;
2426 : }
2427 0 : return g;
2428 : }
2429 :
2430 : static GEN
2431 0 : pc_inv(GEN g, GEN G)
2432 : {
2433 0 : long i, l = lg(g);
2434 0 : GEN ord = pcgrp_get_ord(G), pw = pcgrp_get_pow(G);
2435 0 : GEN v = cgetg(l, t_VEC);
2436 0 : if (l==1) return v;
2437 0 : for(i = 1; i < l; i++)
2438 : {
2439 0 : ulong gi = uel(g,i);
2440 0 : gel(v,l-i) = vecsmall_concat(pc_inv(gel(pw, gi), G),
2441 0 : const_vecsmall(uel(ord,gi)-1,gi));
2442 : }
2443 0 : return pc_normalize(shallowconcat1(v), G);
2444 : }
2445 :
2446 : static GEN
2447 0 : pc_mul(GEN g, GEN h, GEN G)
2448 : {
2449 0 : return pc_normalize(vecsmall_concat(g,h), G);
2450 : }
2451 :
2452 : static GEN
2453 0 : pc_bracket(GEN g, GEN h, GEN G)
2454 : {
2455 0 : GEN gh = pc_mul(g, h, G);
2456 0 : GEN hg = pc_mul(h, g, G);
2457 0 : long i, l1 = lg(gh), l2 = lg(hg), lm = minss(l1,l2);
2458 0 : for (i = 1; i < lm; i++)
2459 0 : if (gh[l1-i] != hg[l2-i]) break;
2460 0 : return pc_mul(vecsmall_shorten(gh,l1-i), pc_inv(vecsmall_shorten(hg,l2-i), G), G);
2461 : }
2462 :
2463 : static GEN
2464 0 : pc_exp(GEN v)
2465 : {
2466 0 : long i, l = lg(v);
2467 0 : GEN w = cgetg(l, t_VEC);
2468 0 : if (l==1) return w;
2469 0 : for (i = 1; i < l; i++)
2470 0 : gel(w,i) = const_vecsmall(v[i], i+1);
2471 0 : return shallowconcat1(w);
2472 : }
2473 : static GEN
2474 0 : vecsmall_increase(GEN x)
2475 0 : { pari_APPLY_ulong(x[i]+1) }
2476 :
2477 : static GEN
2478 0 : vecvecsmall_increase(GEN x)
2479 0 : { pari_APPLY_same(vecsmall_increase(gel(x,i))) }
2480 :
2481 : static GEN
2482 0 : pcgrp_lift(GEN G, long deg)
2483 : {
2484 0 : GEN ord = pcgrp_get_ord(G), pw = pcgrp_get_pow(G), br = pcgrp_get_br(G);
2485 0 : long i, l = lg(br);
2486 0 : GEN Ord = vecsmall_prepend(ord, deg);
2487 0 : GEN Pw = vec_prepend(vecvecsmall_increase(pw), cgetg(1,t_VECSMALL));
2488 0 : GEN Br = cgetg(l+1, t_VEC);
2489 0 : gel(Br,1) = const_vec(l-1, cgetg(1, t_VECSMALL));
2490 0 : for (i = 1; i < l; i++)
2491 0 : gel(Br,i+1) = vecvecsmall_increase(gel(br, i));
2492 0 : return mkvec3(Ord, Pw, Br);
2493 : }
2494 :
2495 : static GEN
2496 0 : brl_add(GEN x, GEN a)
2497 : {
2498 0 : pari_APPLY_same(vecsmall_concat(const_vecsmall(uel(a,i),1),gel(x,i)))
2499 : }
2500 :
2501 : static void
2502 0 : pcgrp_insert(GEN G, long j, GEN a)
2503 : {
2504 0 : GEN pw = pcgrp_get_pow(G), br = pcgrp_get_br(G);
2505 0 : gel(pw,j) = vecsmall_concat(gel(a,1),gel(pw, j));
2506 0 : gel(br,j) = brl_add(gel(br, j), gel(a,2));
2507 0 : }
2508 :
2509 : static long
2510 0 : getfr(GEN f, GEN h)
2511 : {
2512 0 : long i, l = lg(f);
2513 0 : for (i = 1; i < l; i++)
2514 0 : if (zv_equal(gel(f,i), h)) return i;
2515 0 : pari_err_BUG("galoisinit");
2516 0 : return 0;
2517 : }
2518 :
2519 : static long
2520 0 : get_pow(GEN pf, ulong o, GEN pw, GEN gen)
2521 : {
2522 0 : long i, n = lg(pf)-1;
2523 0 : GEN p1 = perm_powu(pf, o);
2524 0 : GEN p2 = pc_to_perm(pw, gen, n);
2525 0 : for(i = 0; ; i++)
2526 : {
2527 0 : if (zv_equal(p1, p2)) break;
2528 0 : p2 = perm_mul(gel(gen,1), p2);
2529 : }
2530 0 : return i;
2531 : }
2532 :
2533 : struct galois_perm
2534 : {
2535 : GEN L;
2536 : GEN M;
2537 : GEN den;
2538 : GEN mod, mod2;
2539 : long x;
2540 : GEN cache;
2541 : };
2542 :
2543 : static void
2544 0 : galoisperm_init(struct galois_perm *gp, GEN L, GEN M, GEN den, GEN mod, GEN mod2, long x)
2545 : {
2546 0 : gp->L = L;
2547 0 : gp->M = M;
2548 0 : gp->den = den;
2549 0 : gp->mod = mod;
2550 0 : gp->mod2 = mod2;
2551 0 : gp->x = x;
2552 0 : gp->cache = zerovec(lg(L)-1);
2553 0 : }
2554 :
2555 : static void
2556 0 : galoisperm_free(struct galois_perm *gp)
2557 : {
2558 0 : long i, l = lg(gp->cache);
2559 0 : for (i=1; i<l; i++)
2560 0 : if (!isintzero(gel(gp->cache,i)))
2561 0 : gunclone(gel(gp->cache,i));
2562 0 : }
2563 :
2564 : static GEN
2565 0 : permtoaut(GEN p, struct galois_perm *gp)
2566 : {
2567 0 : pari_sp av = avma;
2568 0 : if (isintzero(gel(gp->cache,p[1])))
2569 : {
2570 0 : GEN pol = permtopol(p, gp->L, gp->M, gp->den, gp->mod, gp->mod2, gp->x);
2571 0 : gel(gp->cache,p[1]) = gclone(pol);
2572 : }
2573 0 : set_avma(av);
2574 0 : return gel(gp->cache,p[1]);
2575 : }
2576 :
2577 : static GEN
2578 0 : pc_evalcache(GEN W, GEN u, GEN sp, GEN T, GEN p, struct galois_perm *gp)
2579 : {
2580 : GEN v;
2581 0 : long ns = sp[1];
2582 0 : if (!isintzero(gel(W,ns))) return gel(W,ns);
2583 0 : v = RgX_to_FpX(permtoaut(sp, gp), p);
2584 0 : gel(W,ns) = FpX_FpXQV_eval(v, u, T, p);
2585 0 : return gel(W,ns);
2586 : }
2587 :
2588 : static ulong
2589 0 : findp(GEN D, GEN P, GEN S, long o, GEN *Tmod)
2590 : {
2591 : forprime_t iter;
2592 : ulong p;
2593 0 : long n = degpol(P);
2594 0 : u_forprime_init(&iter, n*maxss(expu(n)-3, 2), ULONG_MAX);
2595 0 : while ((p = u_forprime_next(&iter)))
2596 : {
2597 : GEN F, F1, Sp;
2598 0 : if (smodis(D, p) == 0)
2599 0 : continue;
2600 0 : F = gel(Flx_factor(ZX_to_Flx(P, p), p), 1);
2601 0 : F1 = gel(F,1);
2602 0 : if (degpol(F1) != o)
2603 0 : continue;
2604 0 : Sp = RgX_to_Flx(S, p);
2605 0 : if (gequal(Flx_rem(Sp, F1, p), Flx_Frobenius(F1, p)))
2606 : {
2607 0 : *Tmod = FlxV_to_ZXV(F);
2608 0 : return p;
2609 : }
2610 : }
2611 0 : return 0;
2612 : }
2613 :
2614 : static GEN
2615 0 : nilp_froblift(GEN genG, GEN autH, long j, GEN pcgrp,
2616 : GEN idp, GEN incl, GEN H, struct galois_lift *gl, struct galois_perm *gp)
2617 : {
2618 0 : pari_sp av = avma;
2619 0 : GEN T = gl->T, p = gl->p, pe = gl->Q;
2620 0 : ulong pp = itou(p);
2621 0 : long e = gl->e;
2622 0 : GEN pf = cgetg(lg(gl->L), t_VECSMALL);
2623 0 : GEN Tp = ZX_to_Flx(T, pp);
2624 0 : GEN Hp = ZX_to_Flx(H, pp);
2625 0 : GEN ord = pcgrp_get_ord(pcgrp);
2626 0 : GEN pcp = gel(pcgrp_get_pow(pcgrp),j+1);
2627 0 : long o = uel(ord,1);
2628 0 : GEN ordH = vecslice(ord,2,lg(ord)-1);
2629 0 : long n = zv_prod(ordH), k = lg(ordH)-1, l = k-j, m = upowuu(o, l), v = varn(T);
2630 0 : GEN factTp = gel(Flx_factor(Tp, pp), 1);
2631 0 : long fp = degpol(gel(factTp, 1));
2632 0 : GEN frobp = Flxq_autpow(Flx_Frobenius(Tp, pp), fp-1, Tp, pp);
2633 0 : GEN frob = ZpX_ZpXQ_liftroot(T, Flx_to_ZX(frobp), T, p, e);
2634 0 : if (galoisfrobeniustest(frob, gl, pf))
2635 : {
2636 0 : GEN pfi = perm_inv(pf);
2637 0 : long d = get_pow(pfi, uel(ord,j+1), pcp, genG);
2638 0 : return mkvec3(pfi, mkvec2(const_vecsmall(d,1),zero_zv(l+1)), gel(factTp, 1));
2639 : }
2640 : else
2641 : {
2642 0 : GEN frobG = FpXQ_powers(frob, usqrt(degpol(T)), T, pe);
2643 0 : GEN autHp = RgXV_to_FlxV(autH,pp);
2644 0 : GEN inclp = RgX_to_Flx(incl,pp);
2645 0 : GEN factHp = gel(Flx_factor(Hp, pp),1);
2646 0 : long fr = getfr(factHp, idp);
2647 0 : GEN minHp = FlxV_minpolymod(autHp, factHp, pp);
2648 0 : GEN permfact_Hp = factperm(minHp);
2649 0 : GEN permfact_Gp = FlxV_Flx_gcd(FlxC_Flxq_eval(factHp, inclp, Tp, pp), Tp, pp);
2650 0 : GEN bezout_Gpe = bezout_lift_fact(T, FlxV_to_ZXV(permfact_Gp), p, e);
2651 0 : GEN id = gmael(Flx_factor(gel(permfact_Gp, fr),pp),1,1);
2652 0 : GEN orbgen = genorbit(ordH, permfact_Hp, fr, n, k, j);
2653 0 : GEN orb = gel(orbgen,1), gen = gel(orbgen,2);
2654 0 : long nborb = lg(orb)-1;
2655 0 : GEN A = cgetg(l+1, t_VECSMALL);
2656 0 : GEN W = zerovec(lg(gl->L)-1);
2657 0 : GEN U = zeromatcopy(nborb,degpol(T));
2658 0 : GEN br = pcgrp_get_br(pcgrp), brj = gcopy(gel(br, j+1));
2659 0 : GEN Ui = cgetg(nborb+1, t_VEC);
2660 : long a, b, i;
2661 0 : for(a = 0; a < m; a++)
2662 : {
2663 : pari_timer ti;
2664 : pari_sp av2;
2665 0 : GEN B = pol_0(v);
2666 0 : long aa = a;
2667 0 : if (DEBUGLEVEL>=4) timer_start(&ti);
2668 0 : for(i = 1; i <= l; i++)
2669 : {
2670 0 : uel(A,i) = aa % o;
2671 0 : aa /= o;
2672 : }
2673 0 : gel(br,j+1) = brl_add(brj, A);
2674 0 : for(b = 1; b <= nborb; b++)
2675 : {
2676 0 : GEN br = pc_bracket(pc_exp(gel(gen,b)), mkvecsmall(j+1), pcgrp);
2677 0 : GEN sp = pc_to_perm(br, genG, degpol(T));
2678 0 : long u = sp[1];
2679 0 : long s = permprodeval(permfact_Hp, gel(gen,b), fr);
2680 0 : if (isintzero(gmael(U,u,s)))
2681 : {
2682 0 : GEN Ub = pc_evalcache(W, frobG, sp, T, pe, gp);
2683 0 : gmael(U,u,s) = FpXQ_mul(Ub, gel(bezout_Gpe,s), T, pe);
2684 : }
2685 0 : gel(Ui, b) = gmael(U,u,s);
2686 : }
2687 0 : av2 = avma;
2688 0 : for(b = 1; b <= nborb; b++)
2689 0 : B = FpX_add(B, gel(Ui,b), pe);
2690 0 : if (DEBUGLEVEL >= 4) timer_printf(&ti,"Testing candidate %ld",a);
2691 0 : if (galoisfrobeniustest(B, gl, pf))
2692 : {
2693 0 : GEN pfi = perm_inv(pf);
2694 0 : long d = get_pow(pfi, uel(ord,j+1), pcp, genG);
2695 0 : gel(br,j+1) = brj;
2696 0 : return gerepilecopy(av,mkvec3(pfi,mkvec2(const_vecsmall(d,1),A),id));
2697 : }
2698 0 : set_avma(av2);
2699 : }
2700 0 : return gc_NULL(av);
2701 : }
2702 : }
2703 :
2704 : static GEN
2705 0 : galoisgenlift_nilp(GEN PG, GEN O, GEN V, GEN T, GEN frob, GEN sigma,
2706 : struct galois_borne *gb, struct galois_frobenius *gf, struct galois_perm *gp)
2707 : {
2708 0 : long j, n = degpol(T), deg = gf->deg;
2709 0 : ulong p = gf->p;
2710 0 : GEN L = gp->L, M = gp->M, den = gp->den;
2711 0 : GEN S = fixedfieldinclusion(O, gel(V,2));
2712 0 : GEN incl = vectopol(S, M, den, gb->ladicabs, shifti(gb->ladicabs,-1), varn(T));
2713 0 : GEN H = gel(V,3);
2714 0 : GEN PG1 = gmael(PG, 1, 1);
2715 0 : GEN PG2 = gmael(PG, 1, 2);
2716 0 : GEN PG3 = gmael(PG, 1, 3);
2717 0 : GEN PG4 = gmael(PG, 1, 4);
2718 0 : long lP = lg(PG1);
2719 0 : GEN PG5 = pcgrp_lift(gmael(PG, 1, 5), deg);
2720 0 : GEN res = cgetg(6, t_VEC), res1, res2, res3;
2721 0 : gel(res,1) = res1 = cgetg(lP + 1, t_VEC);
2722 0 : gel(res,2) = res2 = cgetg(lP + 1, t_VEC);
2723 0 : gel(res,3) = res3 = cgetg(lP + 1, t_VEC);
2724 0 : gel(res,4) = vecsmall_prepend(PG4, p);
2725 0 : gel(res,5) = PG5;
2726 0 : gel(res1, 1) = frob;
2727 0 : gel(res2, 1) = ZX_to_Flx(gel(gf->Tmod,1), p);
2728 0 : gel(res3, 1) = sigma;
2729 0 : for (j = 1; j < lP; j++)
2730 : {
2731 : struct galois_lift gl;
2732 0 : GEN Lden = makeLden(L,den,gb);
2733 : GEN pf;
2734 0 : initlift(T, den, uel(PG4,j), L, Lden, gb, &gl);
2735 0 : pf = nilp_froblift(vecslice(res1,1,j), PG3, j, PG5, gel(PG2,j), incl, H, &gl, gp);
2736 0 : if (!pf) return NULL;
2737 0 : if (DEBUGLEVEL>=2)
2738 0 : err_printf("found: %ld/%ld: %Ps: %Ps\n", n, j+1, gel(pf,2),gel(pf,1));
2739 0 : pcgrp_insert(PG5, j+1, gel(pf,2));
2740 0 : gel(res1, j+1) = gel(pf,1);
2741 0 : gel(res2, j+1) = gel(pf,3);
2742 0 : gel(res3, j+1) = gcopy(permtoaut(gel(pf,1), gp));
2743 : }
2744 0 : if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Fini!\n");
2745 0 : return res;
2746 : }
2747 :
2748 : static GEN
2749 5351 : galoisgenlift(GEN PG, GEN Pg, GEN O, GEN L, GEN M, GEN frob,
2750 : struct galois_borne *gb, struct galois_frobenius *gf)
2751 : {
2752 : struct galois_test td;
2753 : GEN res, res1;
2754 5351 : GEN PG1 = gel(PG, 1), PG2 = gel(PG, 2);
2755 5351 : long lP = lg(PG1), j, n = lg(L)-1;
2756 5351 : inittest(L, M, gb->bornesol, gb->ladicsol, &td);
2757 5351 : res = cgetg(3, t_VEC);
2758 5351 : gel(res,1) = res1 = cgetg(lP + 1, t_VEC);
2759 5351 : gel(res,2) = vecsmall_prepend(PG2, gf->deg);
2760 5351 : gel(res1, 1) = vecsmall_copy(frob);
2761 11266 : for (j = 1; j < lP; j++)
2762 : {
2763 6576 : GEN pf = galoisgenliftauto(O, gel(PG1, j), gf->psi[Pg[j]], n, &td);
2764 6576 : if (!pf) { freetest(&td); return NULL; }
2765 5915 : gel(res1, j+1) = pf;
2766 : }
2767 4690 : if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Fini!\n");
2768 4690 : freetest(&td);
2769 4690 : return res;
2770 : }
2771 :
2772 : static ulong
2773 29620 : psi_order(GEN psi, ulong d)
2774 : {
2775 29620 : long i, l = lg(psi);
2776 29620 : ulong s = 1;
2777 66590 : for (i=1; i<l; i++)
2778 36970 : s = clcm(s, d/cgcd(uel(psi, i)-1, d));
2779 29620 : return s;
2780 : }
2781 :
2782 : static GEN
2783 29823 : galoisgen(GEN T, GEN L, GEN M, GEN den, GEN bad, struct galois_borne *gb,
2784 : const struct galois_analysis *ga)
2785 : {
2786 : struct galois_test td;
2787 : struct galois_frobenius gf, ogf;
2788 29823 : pari_sp ltop = avma;
2789 29823 : long x, n = degpol(T), is_central;
2790 : ulong po;
2791 29823 : GEN sigma, res, frob, O, PG, V, ofrob = NULL;
2792 :
2793 29823 : if (!ga->deg) return NULL;
2794 29823 : x = varn(T);
2795 29823 : if (DEBUGLEVEL >= 9) err_printf("GaloisConj: denominator:%Ps\n", den);
2796 29823 : if (n == 12 && ga->ord==3 && !ga->p4)
2797 : { /* A4 is very probable: test it first */
2798 98 : pari_sp av = avma;
2799 98 : if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Testing A4 first\n");
2800 98 : inittest(L, M, gb->bornesol, gb->ladicsol, &td);
2801 98 : PG = a4galoisgen(&td);
2802 98 : freetest(&td);
2803 98 : if (PG) return gerepileupto(ltop, PG);
2804 0 : set_avma(av);
2805 : }
2806 29725 : if (n == 24 && ga->ord==3 && ga->p4)
2807 : { /* S4 is very probable: test it first */
2808 77 : pari_sp av = avma;
2809 : struct galois_lift gl;
2810 77 : if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Testing S4 first\n");
2811 77 : initlift(T, den, ga->p4, L, makeLden(L,den,gb), gb, &gl);
2812 77 : PG = s4galoisgen(&gl);
2813 77 : if (PG) return gerepileupto(ltop, PG);
2814 0 : set_avma(av);
2815 : }
2816 29648 : if (n == 36 && ga->ord==3 && ga->p4)
2817 : { /* F36 is very probable: test it first */
2818 14 : pari_sp av = avma;
2819 : struct galois_lift gl;
2820 14 : if (DEBUGLEVEL >= 4) err_printf("GaloisConj: Testing 3x3:4 first (p=%ld)\n",ga->p4);
2821 14 : initlift(T, den, ga->p4, L, makeLden(L,den,gb), gb, &gl);
2822 14 : PG = f36galoisgen(&gl);
2823 14 : if (PG) return gerepileupto(ltop, PG);
2824 0 : set_avma(av);
2825 : }
2826 29634 : frob = galoisfindfrobenius(T, L, den, bad, &gf, gb, ga);
2827 29634 : if (!frob) return gc_NULL(ltop);
2828 29620 : po = psi_order(gf.psi, gf.deg);
2829 29620 : if (!(ga->group&ga_easy) && po < (ulong) gf.deg && gf.deg/radicalu(gf.deg)%po == 0)
2830 : {
2831 0 : is_central = 1;
2832 0 : if (!bad) bad = gb->dis;
2833 0 : if (po > 1)
2834 : {
2835 0 : ofrob = frob; ogf = gf;
2836 0 : frob = perm_powu(frob, po);
2837 0 : gf.deg /= po;
2838 : }
2839 29620 : } else is_central = 0;
2840 29620 : sigma = permtopol(frob, L, M, den, gb->ladicabs, shifti(gb->ladicabs,-1), x);
2841 29618 : if (is_central && gf.fp != gf.deg)
2842 0 : { gf.p = findp(bad, T, sigma, gf.deg, &gf.Tmod); gf.fp = gf.deg;
2843 0 : gf.psi = const_vecsmall(lg(gf.Tmod)-1, 1);
2844 : }
2845 29618 : if (gf.deg == n) /* cyclic */
2846 : {
2847 24246 : GEN Tp = ZX_to_Flx(gel(gf.Tmod,1), gf.p);
2848 24247 : res = mkvec5(mkvec(frob), mkvec(Tp), mkvec(sigma), mkvecsmall(gf.p), cyclic_pc(n));
2849 24247 : return gerepilecopy(ltop, res);
2850 : }
2851 5372 : O = perm_cycles(frob);
2852 5372 : if (DEBUGLEVEL >= 9) err_printf("GaloisConj: Frobenius:%Ps\n", sigma);
2853 5372 : PG = galoisgenfixedfield0(O, L, sigma, T, is_central ? bad: NULL,
2854 : is_central ? &V: NULL, &gf, gb);
2855 5372 : if (PG == NULL) return gc_NULL(ltop);
2856 5351 : if (is_central && lg(gel(PG,1))!=3)
2857 0 : {
2858 : struct galois_perm gp;
2859 0 : galoisperm_init(&gp, L, M, den, gb->ladicabs, shifti(gb->ladicabs,-1), varn(T));
2860 0 : res = galoisgenlift_nilp(PG, O, V, T, frob, sigma, gb, &gf, &gp);
2861 0 : galoisperm_free(&gp);
2862 : }
2863 : else
2864 : {
2865 5351 : if (is_central && po > 1)
2866 : { /* backtrack powering of frob */
2867 0 : frob = ofrob; gf = ogf;
2868 0 : O = perm_cycles(ofrob);
2869 0 : sigma = permtopol(ofrob, L, M, den, gb->ladicabs, shifti(gb->ladicabs,-1), x);
2870 0 : PG = galoisgenfixedfield0(O, L, sigma, T, NULL, NULL, &gf, gb);
2871 0 : if (PG == NULL) return gc_NULL(ltop);
2872 : }
2873 5351 : res = galoisgenlift(gg_get_std(gel(PG,1)), gel(PG,2), O, L, M, frob, gb, &gf);
2874 : }
2875 5351 : if (!res) return gc_NULL(ltop);
2876 4690 : return gerepilecopy(ltop, res);
2877 : }
2878 :
2879 : /* T = polcyclo(N) */
2880 : static GEN
2881 980 : conjcyclo(GEN T, long N)
2882 : {
2883 980 : pari_sp av = avma;
2884 980 : long i, k = 1, d = eulerphiu(N), v = varn(T);
2885 980 : GEN L = cgetg(d+1,t_COL);
2886 14735 : for (i=1; i<=N; i++)
2887 13755 : if (ugcd(i, N)==1)
2888 : {
2889 6440 : GEN s = pol_xn(i, v);
2890 6440 : if (i >= d) s = ZX_rem(s, T);
2891 6440 : gel(L,k++) = s;
2892 : }
2893 980 : return gerepileupto(av, gen_sort(L, (void*)&gcmp, &gen_cmp_RgX));
2894 : }
2895 :
2896 : static GEN
2897 1246 : aut_to_groupelts(GEN aut, GEN L, ulong p)
2898 : {
2899 1246 : pari_sp av = avma;
2900 1246 : long i, d = lg(aut)-1;
2901 1246 : GEN P = ZV_to_Flv(L, p);
2902 1246 : GEN N = FlxV_Flv_multieval(aut, P, p);
2903 1246 : GEN q = perm_inv(vecsmall_indexsort(P));
2904 1246 : GEN G = cgetg(d+1, t_VEC);
2905 35945 : for (i=1; i<=d; i++)
2906 34699 : gel(G,i) = perm_mul(vecsmall_indexsort(gel(N,i)), q);
2907 1246 : return gerepilecopy(av, vecvecsmall_sort_shallow(G));
2908 : }
2909 :
2910 : static ulong
2911 7 : galois_find_totally_split(GEN P, GEN Q)
2912 : {
2913 7 : pari_sp av = avma;
2914 : forprime_t iter;
2915 : ulong p;
2916 7 : long n = degpol(P);
2917 7 : u_forprime_init(&iter, n*maxss(expu(n)-3, 2), ULONG_MAX);
2918 714 : while ((p = u_forprime_next(&iter)))
2919 : {
2920 714 : if (Flx_is_totally_split(ZX_to_Flx(P, p), p)
2921 7 : && (!Q || Flx_is_squarefree(ZX_to_Flx(Q, p), p)))
2922 7 : return gc_ulong(av, p);
2923 707 : set_avma(av);
2924 : }
2925 0 : return 0;
2926 : }
2927 :
2928 : GEN
2929 1253 : galoisinitfromaut(GEN T, GEN aut, ulong l)
2930 : {
2931 1253 : pari_sp ltop = avma;
2932 1253 : GEN nf, A, G, L, M, grp, den=NULL;
2933 : struct galois_analysis ga;
2934 : struct galois_borne gb;
2935 : long n;
2936 : pari_timer ti;
2937 :
2938 1253 : T = get_nfpol(T, &nf);
2939 1253 : n = degpol(T);
2940 1253 : if (nf)
2941 0 : { if (!den) den = nf_get_zkden(nf); }
2942 : else
2943 : {
2944 1253 : if (n <= 0) pari_err_IRREDPOL("galoisinit",T);
2945 1253 : RgX_check_ZX(T, "galoisinit");
2946 1253 : if (!ZX_is_squarefree(T))
2947 0 : pari_err_DOMAIN("galoisinit","issquarefree(pol)","=",gen_0,T);
2948 1253 : if (!gequal1(gel(T,n+2))) pari_err_IMPL("galoisinit(nonmonic)");
2949 : }
2950 1253 : if (lg(aut)-1 != n)
2951 7 : return gen_0;
2952 1246 : ga.l = l? l: galois_find_totally_split(T, NULL);
2953 1246 : if (!l) aut = RgXV_to_FlxV(aut, ga.l);
2954 1246 : gb.l = utoipos(ga.l);
2955 1246 : if (DEBUGLEVEL >= 1) timer_start(&ti);
2956 1246 : den = galoisborne(T, den, &gb, degpol(T));
2957 1246 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "galoisborne()");
2958 1246 : L = ZpX_roots(T, gb.l, gb.valabs);
2959 1246 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "ZpX_roots");
2960 1246 : M = FpV_invVandermonde(L, den, gb.ladicabs);
2961 1246 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "FpV_invVandermonde()");
2962 1246 : A = aut_to_groupelts(aut, L, ga.l);
2963 1246 : G = groupelts_to_group(A);
2964 1246 : if (!G) G = trivialgroup();
2965 1239 : else A = group_elts(G,n);
2966 1246 : grp = cgetg(9, t_VEC);
2967 1246 : gel(grp,1) = T;
2968 1246 : gel(grp,2) = mkvec3(utoipos(ga.l), utoipos(gb.valabs), gb.ladicabs);
2969 1246 : gel(grp,3) = L;
2970 1246 : gel(grp,4) = M;
2971 1246 : gel(grp,5) = den;
2972 1246 : gel(grp,6) = A;
2973 1246 : gel(grp,7) = gel(G,1);
2974 1246 : gel(grp,8) = gel(G,2);
2975 1246 : return gerepilecopy(ltop, grp);
2976 : }
2977 :
2978 : GEN
2979 1239 : galoissplittinginit(GEN T, GEN D)
2980 : {
2981 1239 : pari_sp av = avma;
2982 1239 : GEN R = nfsplitting0(T, D, 3), P = gel(R,1), aut = gel(R,2);
2983 1232 : ulong p = itou(gel(R,3));
2984 1232 : return gerepileupto(av, galoisinitfromaut(P, aut, p));
2985 : }
2986 :
2987 : /* T: polynomial or nf, den multiple of common denominator of solutions or
2988 : * NULL (unknown). If T is nf, and den unknown, use den = denom(nf.zk) */
2989 : static GEN
2990 96885 : galoisconj4_main(GEN T, GEN den, long flag)
2991 : {
2992 96885 : pari_sp ltop = avma;
2993 : GEN nf, G, L, M, aut, grp;
2994 : struct galois_analysis ga;
2995 : struct galois_borne gb;
2996 : long n;
2997 : pari_timer ti;
2998 :
2999 96885 : T = get_nfpol(T, &nf);
3000 96885 : n = poliscyclo(T);
3001 96886 : if (n) return flag? galoiscyclo(n, varn(T)): conjcyclo(T, n);
3002 95472 : n = degpol(T);
3003 95472 : if (nf)
3004 54096 : { if (!den) den = nf_get_zkden(nf); }
3005 : else
3006 : {
3007 41376 : if (n <= 0) pari_err_IRREDPOL("galoisinit",T);
3008 41376 : RgX_check_ZX(T, "galoisinit");
3009 41367 : if (!ZX_is_squarefree(T))
3010 7 : pari_err_DOMAIN("galoisinit","issquarefree(pol)","=",gen_0,T);
3011 41370 : if (!gequal1(gel(T,n+2))) pari_err_IMPL("galoisinit(nonmonic)");
3012 : }
3013 95459 : if (n == 1)
3014 : {
3015 21 : if (!flag) { G = cgetg(2, t_COL); gel(G,1) = pol_x(varn(T)); return G;}
3016 21 : ga.l = 3;
3017 21 : ga.deg = 1;
3018 21 : den = gen_1;
3019 : }
3020 95438 : else if (!galoisanalysis(T, &ga, 1, NULL)) return gc_NULL(ltop);
3021 :
3022 28514 : if (den)
3023 : {
3024 17915 : if (typ(den) != t_INT) pari_err_TYPE("galoisconj4 [2nd arg integer]", den);
3025 17915 : den = absi_shallow(den);
3026 : }
3027 28514 : gb.l = utoipos(ga.l);
3028 28514 : if (DEBUGLEVEL >= 1) timer_start(&ti);
3029 28514 : den = galoisborne(T, den, &gb, degpol(T));
3030 28513 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "galoisborne()");
3031 28513 : L = ZpX_roots(T, gb.l, gb.valabs);
3032 28514 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "ZpX_roots");
3033 28514 : M = FpV_invVandermonde(L, den, gb.ladicabs);
3034 28514 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "FpV_invVandermonde()");
3035 28514 : if (n == 1)
3036 : {
3037 21 : G = cgetg(3, t_VEC);
3038 21 : gel(G,1) = cgetg(1, t_VEC);
3039 21 : gel(G,2) = cgetg(1, t_VECSMALL);
3040 : }
3041 : else
3042 28493 : G = gg_get_std(galoisgen(T, L, M, den, NULL, &gb, &ga));
3043 28514 : if (DEBUGLEVEL >= 6) err_printf("GaloisConj: %Ps\n", G);
3044 28514 : if (!G) return gc_NULL(ltop);
3045 27825 : if (DEBUGLEVEL >= 1) timer_start(&ti);
3046 27825 : grp = cgetg(9, t_VEC);
3047 27825 : gel(grp,1) = T;
3048 27825 : gel(grp,2) = mkvec3(utoipos(ga.l), utoipos(gb.valabs), gb.ladicabs);
3049 27825 : gel(grp,3) = L;
3050 27825 : gel(grp,4) = M;
3051 27825 : gel(grp,5) = den;
3052 27825 : gel(grp,6) = group_elts(G,n);
3053 27825 : gel(grp,7) = gel(G,1);
3054 27825 : gel(grp,8) = gel(G,2);
3055 27825 : if (flag) return gerepilecopy(ltop, grp);
3056 8610 : aut = galoisvecpermtopol(grp, gal_get_group(grp), gb.ladicabs, shifti(gb.ladicabs,-1));
3057 8610 : settyp(aut, t_COL);
3058 8610 : if (DEBUGLEVEL >= 1) timer_printf(&ti, "Computation of polynomials");
3059 8610 : return gerepileupto(ltop, gen_sort(aut, (void*)&gcmp, &gen_cmp_RgX));
3060 : }
3061 :
3062 : /* Heuristic computation of #Aut(T), pinit = first prime to be tested */
3063 : long
3064 35944 : numberofconjugates(GEN T, long pinit)
3065 : {
3066 35944 : pari_sp av = avma;
3067 35944 : long c, nbtest, nbmax, n = degpol(T);
3068 : ulong p;
3069 : forprime_t S;
3070 :
3071 35944 : if (n == 1) return 1;
3072 35944 : nbmax = (n < 10)? 20: (n<<1) + 1;
3073 35944 : nbtest = 0;
3074 : #if 0
3075 : c = ZX_sturm(T); c = ugcd(c, n-c); /* too costly: finite primes are cheaper */
3076 : #else
3077 35944 : c = n;
3078 : #endif
3079 35944 : u_forprime_init(&S, pinit, ULONG_MAX);
3080 339334 : while((p = u_forprime_next(&S)))
3081 : {
3082 339332 : GEN L, Tp = ZX_to_Flx(T,p);
3083 : long i, nb;
3084 339333 : if (!Flx_is_squarefree(Tp, p)) continue;
3085 : /* unramified */
3086 280860 : nbtest++;
3087 280860 : L = Flx_nbfact_by_degree(Tp, &nb, p); /* L[i] = #factors of degree i */
3088 280871 : if (L[n/nb] == nb) {
3089 234344 : if (c == n && nbtest > 10) break; /* probably Galois */
3090 : }
3091 : else
3092 : {
3093 82423 : c = ugcd(c, L[1]);
3094 288353 : for (i = 2; i <= n; i++)
3095 230262 : if (L[i]) { c = ugcd(c, L[i]*i); if (c == 1) break; }
3096 82423 : if (c == 1) break;
3097 : }
3098 256490 : if (nbtest == nbmax) break;
3099 244926 : if (DEBUGLEVEL >= 6)
3100 0 : err_printf("NumberOfConjugates [%ld]:c=%ld,p=%ld\n", nbtest,c,p);
3101 244926 : set_avma(av);
3102 : }
3103 35945 : if (DEBUGLEVEL >= 2) err_printf("NumberOfConjugates:c=%ld,p=%ld\n", c, p);
3104 35945 : return gc_long(av,c);
3105 : }
3106 : static GEN
3107 0 : galoisconj4(GEN nf, GEN d)
3108 : {
3109 0 : pari_sp av = avma;
3110 : GEN G, T;
3111 0 : G = galoisconj4_main(nf, d, 0);
3112 0 : if (G) return G; /* Success */
3113 0 : set_avma(av); T = get_nfpol(nf, &nf);
3114 0 : G = cgetg(2, t_COL); gel(G,1) = pol_x(varn(T)); return G; /* Fail */
3115 :
3116 : }
3117 :
3118 : /* d multiplicative bound for the automorphism's denominators */
3119 : static GEN
3120 70181 : galoisconj_monic(GEN nf, GEN d)
3121 : {
3122 70181 : pari_sp av = avma;
3123 70181 : GEN G, NF, T = get_nfpol(nf,&NF);
3124 70181 : if (degpol(T) == 2)
3125 : { /* fast shortcut */
3126 24653 : GEN b = gel(T,3);
3127 24653 : long v = varn(T);
3128 24653 : G = cgetg(3, t_COL);
3129 24653 : gel(G,1) = deg1pol_shallow(gen_m1, negi(b), v);
3130 24652 : gel(G,2) = pol_x(v);
3131 24652 : return G;
3132 : }
3133 45528 : G = galoisconj4_main(nf, d, 0);
3134 45527 : if (G) return G; /* Success */
3135 35937 : set_avma(av); return galoisconj1(nf);
3136 : }
3137 :
3138 : GEN
3139 70180 : galoisconj(GEN nf, GEN d)
3140 : {
3141 : pari_sp av;
3142 70180 : GEN NF, S, L, T = get_nfpol(nf,&NF);
3143 70181 : if (NF) return galoisconj_monic(NF, d);
3144 70 : RgX_check_QX(T, "galoisconj");
3145 70 : av = avma;
3146 70 : T = Q_primpart(T);
3147 70 : if (ZX_is_monic(T)) return galoisconj_monic(T, d);
3148 0 : S = galoisconj_monic(poltomonic(T,&L), NULL);
3149 0 : return gerepileupto(av, gdiv(RgXV_unscale(S, L),L));
3150 : }
3151 :
3152 : /* FIXME: obsolete, use galoisconj(nf, d) directly */
3153 : GEN
3154 63 : galoisconj0(GEN nf, long flag, GEN d, long prec)
3155 : {
3156 : (void)prec;
3157 63 : switch(flag) {
3158 56 : case 2:
3159 56 : case 0: return galoisconj(nf, d);
3160 7 : case 1: return galoisconj1(nf);
3161 0 : case 4: return galoisconj4(nf, d);
3162 : }
3163 0 : pari_err_FLAG("nfgaloisconj");
3164 : return NULL; /*LCOV_EXCL_LINE*/
3165 : }
3166 :
3167 : /******************************************************************************/
3168 : /* Galois theory related algorithms */
3169 : /******************************************************************************/
3170 : GEN
3171 31052 : checkgal(GEN gal)
3172 : {
3173 31052 : if (typ(gal) == t_POL) pari_err_TYPE("checkgal [apply galoisinit first]",gal);
3174 31052 : if (typ(gal) != t_VEC || lg(gal) != 9) pari_err_TYPE("checkgal",gal);
3175 31045 : return gal;
3176 : }
3177 :
3178 : GEN
3179 51371 : galoisinit(GEN nf, GEN den)
3180 : {
3181 : GEN G;
3182 51371 : if (is_vec_t(typ(nf)) && lg(nf)==3 && is_vec_t(typ(gel(nf,2))))
3183 14 : return galoisinitfromaut(gel(nf,1), gel(nf,2), 0);
3184 51357 : G = galoisconj4_main(nf, den, 1);
3185 51344 : return G? G: gen_0;
3186 : }
3187 :
3188 : static GEN
3189 17927 : galoispermtopol_i(GEN gal, GEN perm, GEN mod, GEN mod2)
3190 : {
3191 17927 : switch (typ(perm))
3192 : {
3193 17682 : case t_VECSMALL:
3194 17682 : return permtopol(perm, gal_get_roots(gal), gal_get_invvdm(gal),
3195 : gal_get_den(gal), mod, mod2,
3196 17682 : varn(gal_get_pol(gal)));
3197 245 : case t_VEC: case t_COL: case t_MAT:
3198 245 : return galoisvecpermtopol(gal, perm, mod, mod2);
3199 : }
3200 0 : pari_err_TYPE("galoispermtopol", perm);
3201 : return NULL; /* LCOV_EXCL_LINE */
3202 : }
3203 :
3204 : GEN
3205 17927 : galoispermtopol(GEN gal, GEN perm)
3206 : {
3207 17927 : pari_sp av = avma;
3208 : GEN mod, mod2;
3209 17927 : gal = checkgal(gal);
3210 17927 : mod = gal_get_mod(gal);
3211 17927 : mod2 = shifti(mod,-1);
3212 17927 : return gerepilecopy(av, galoispermtopol_i(gal, perm, mod, mod2));
3213 : }
3214 :
3215 : GEN
3216 91 : galoiscosets(GEN O, GEN perm)
3217 : {
3218 91 : long i, j, k, u, f, l = lg(O);
3219 91 : GEN RC, C = cgetg(l,t_VECSMALL), o = gel(O,1);
3220 91 : pari_sp av = avma;
3221 91 : f = lg(o); u = o[1]; RC = zero_zv(lg(perm)-1);
3222 371 : for(i=1,j=1; j<l; i++)
3223 : {
3224 280 : GEN p = gel(perm,i);
3225 280 : if (RC[ p[u] ]) continue;
3226 763 : for(k=1; k<f; k++) RC[ p[ o[k] ] ] = 1;
3227 224 : C[j++] = i;
3228 : }
3229 91 : set_avma(av); return C;
3230 : }
3231 :
3232 : static GEN
3233 91 : fixedfieldfactor(GEN L, GEN O, GEN perm, GEN M, GEN den, GEN mod, GEN mod2,
3234 : long x,long y)
3235 : {
3236 91 : pari_sp ltop = avma;
3237 91 : long i, j, k, l = lg(O), lo = lg(gel(O,1));
3238 91 : GEN V, res, cosets = galoiscosets(O,perm), F = cgetg(lo+1,t_COL);
3239 :
3240 91 : gel(F, lo) = gen_1;
3241 91 : if (DEBUGLEVEL>=4) err_printf("GaloisFixedField:cosets=%Ps \n",cosets);
3242 91 : if (DEBUGLEVEL>=6) err_printf("GaloisFixedField:den=%Ps mod=%Ps \n",den,mod);
3243 91 : V = cgetg(l,t_COL); res = cgetg(l,t_VEC);
3244 315 : for (i = 1; i < l; i++)
3245 : {
3246 224 : pari_sp av = avma;
3247 224 : GEN G = cgetg(l,t_VEC), Lp = vecpermute(L, gel(perm, cosets[i]));
3248 938 : for (k = 1; k < l; k++)
3249 714 : gel(G,k) = FpV_roots_to_pol(vecpermute(Lp, gel(O,k)), mod, x);
3250 763 : for (j = 1; j < lo; j++)
3251 : {
3252 1834 : for(k = 1; k < l; k++) gel(V,k) = gmael(G,k,j+1);
3253 539 : gel(F,j) = vectopol(V, M, den, mod, mod2, y);
3254 : }
3255 224 : gel(res,i) = gerepileupto(av,gtopolyrev(F,x));
3256 : }
3257 91 : return gerepileupto(ltop,res);
3258 : }
3259 :
3260 : static void
3261 7469 : chk_perm(GEN perm, long n)
3262 : {
3263 7469 : if (typ(perm) != t_VECSMALL || lg(perm)!=n+1)
3264 0 : pari_err_TYPE("galoisfixedfield", perm);
3265 7469 : }
3266 :
3267 : static int
3268 13279 : is_group(GEN g)
3269 : {
3270 13279 : if (typ(g) == t_VEC && lg(g) == 3)
3271 : {
3272 2611 : GEN a = gel(g,1), o = gel(g,2);
3273 2611 : return typ(a)==t_VEC && typ(o)==t_VECSMALL && lg(a) == lg(o);
3274 : }
3275 10668 : return 0;
3276 : }
3277 :
3278 : GEN
3279 5810 : galoisfixedfield(GEN gal, GEN perm, long flag, long y)
3280 : {
3281 5810 : pari_sp ltop = avma;
3282 : GEN T, L, P, S, PL, O, res, mod, mod2, OL, sym;
3283 : long vT, n, i;
3284 5810 : if (flag<0 || flag>2) pari_err_FLAG("galoisfixedfield");
3285 5810 : gal = checkgal(gal); T = gal_get_pol(gal);
3286 5810 : vT = varn(T);
3287 5810 : L = gal_get_roots(gal); n = lg(L)-1;
3288 5810 : mod = gal_get_mod(gal);
3289 5810 : if (typ(perm) == t_VEC)
3290 : {
3291 4683 : if (is_group(perm)) perm = gel(perm, 1);
3292 11025 : for (i = 1; i < lg(perm); i++) chk_perm(gel(perm,i), n);
3293 4683 : O = vecperm_orbits(perm, n);
3294 : }
3295 : else
3296 : {
3297 1127 : chk_perm(perm, n);
3298 1127 : O = perm_cycles(perm);
3299 : }
3300 5810 : mod2 = shifti(mod,-1);
3301 5810 : OL = fixedfieldorbits(O, L);
3302 5810 : sym = fixedfieldsympol(OL, itou(gal_get_p(gal)));
3303 5810 : PL = sympol_eval(sym, OL, mod);
3304 5810 : P = FpX_center_i(FpV_roots_to_pol(PL, mod, vT), mod, mod2);
3305 5810 : if (flag==1) return gerepilecopy(ltop,P);
3306 1057 : S = fixedfieldinclusion(O, PL);
3307 1057 : S = vectopol(S, gal_get_invvdm(gal), gal_get_den(gal), mod, mod2, vT);
3308 1057 : if (flag==0)
3309 966 : res = cgetg(3, t_VEC);
3310 : else
3311 : {
3312 : GEN PM, Pden;
3313 : struct galois_borne Pgb;
3314 91 : long val = itos(gal_get_e(gal));
3315 91 : Pgb.l = gal_get_p(gal);
3316 91 : Pden = galoisborne(P, NULL, &Pgb, degpol(T)/degpol(P));
3317 91 : if (Pgb.valabs > val)
3318 : {
3319 7 : if (DEBUGLEVEL>=4)
3320 0 : err_printf("GaloisConj: increase p-adic prec by %ld.\n", Pgb.valabs-val);
3321 7 : PL = ZpX_liftroots(P, PL, Pgb.l, Pgb.valabs);
3322 7 : L = ZpX_liftroots(T, L, Pgb.l, Pgb.valabs);
3323 7 : mod = Pgb.ladicabs; mod2 = shifti(mod,-1);
3324 : }
3325 91 : PM = FpV_invVandermonde(PL, Pden, mod);
3326 91 : if (y < 0) y = 1;
3327 91 : if (varncmp(y, vT) <= 0)
3328 0 : pari_err_PRIORITY("galoisfixedfield", T, "<=", y);
3329 91 : setvarn(P, y);
3330 91 : res = cgetg(4, t_VEC);
3331 91 : gel(res,3) = fixedfieldfactor(L,O,gal_get_group(gal), PM,Pden,mod,mod2,vT,y);
3332 : }
3333 1057 : gel(res,1) = gcopy(P);
3334 1057 : gel(res,2) = gmodulo(S, T);
3335 1057 : return gerepileupto(ltop, res);
3336 : }
3337 :
3338 : /* gal a galois group output the underlying wss group */
3339 : GEN
3340 3346 : galois_group(GEN gal) { return mkvec2(gal_get_gen(gal), gal_get_orders(gal)); }
3341 :
3342 : GEN
3343 4270 : checkgroup(GEN g, GEN *S)
3344 : {
3345 4270 : if (is_group(g)) { *S = NULL; return g; }
3346 3213 : g = checkgal(g);
3347 3206 : *S = gal_get_group(g); return galois_group(g);
3348 : }
3349 :
3350 : static GEN
3351 8351 : group_is_elt(GEN G)
3352 : {
3353 8351 : long i, n = lg(G)-1;
3354 8351 : if (n==0) pari_err_DIM("checkgroupelts");
3355 8351 : if (lg(G)==9 && typ(gel(G,1))==t_POL)
3356 6783 : if (lg(gal_get_gen(G))==1 && lg(gal_get_group(G))>2)
3357 14 : return gal_get_group(G);
3358 8337 : if (typ(G)==t_VEC && typ(gel(G,1))==t_VECSMALL)
3359 : {
3360 6244 : for (i = 1; i <= n; i++)
3361 : {
3362 5943 : if (typ(gel(G,i)) != t_VECSMALL)
3363 0 : pari_err_TYPE("checkgroupelts (element)", gel(G,i));
3364 5943 : if (lg(gel(G,i)) != lg(gel(G,1)))
3365 14 : pari_err_DIM("checkgroupelts [length of permutations]");
3366 : }
3367 301 : return G;
3368 : }
3369 8022 : return NULL;
3370 : }
3371 :
3372 : GEN
3373 4634 : checkgroupelts(GEN G)
3374 : {
3375 4634 : GEN S = group_is_elt(G);
3376 4620 : if (S) return S;
3377 4326 : if (is_group(G))
3378 : { /* subgroup of S_n */
3379 371 : if (lg(gel(G,1))==1) return mkvec(mkvecsmall(1));
3380 371 : return group_elts(G, group_domain(G));
3381 : }
3382 3955 : if (lg(G)==9 && typ(gel(G,1))==t_POL)
3383 3913 : return gal_get_group(G); /* galoisinit */
3384 42 : pari_err_TYPE("checkgroupelts",G);
3385 : return NULL; /* LCOV_EXCL_LINE */
3386 : }
3387 :
3388 : GEN
3389 224 : galoisisabelian(GEN gal, long flag)
3390 : {
3391 224 : pari_sp av = avma;
3392 224 : GEN S, G = checkgroup(gal,&S);
3393 224 : if (!group_isabelian(G)) { set_avma(av); return gen_0; }
3394 203 : switch(flag)
3395 : {
3396 49 : case 0: return gerepileupto(av, group_abelianHNF(G,S));
3397 49 : case 1: set_avma(av); return gen_1;
3398 105 : case 2: return gerepileupto(av, group_abelianSNF(G,S));
3399 0 : default: pari_err_FLAG("galoisisabelian");
3400 : }
3401 : return NULL; /* LCOV_EXCL_LINE */
3402 : }
3403 :
3404 : long
3405 56 : galoisisnormal(GEN gal, GEN sub)
3406 : {
3407 56 : pari_sp av = avma;
3408 56 : GEN S, G = checkgroup(gal, &S), H = checkgroup(sub, &S);
3409 56 : long res = group_subgroup_isnormal(G, H);
3410 56 : set_avma(av);
3411 56 : return res;
3412 : }
3413 :
3414 : static GEN
3415 308 : conjclasses_count(GEN conj, long nb)
3416 : {
3417 308 : long i, l = lg(conj);
3418 308 : GEN c = zero_zv(nb);
3419 4039 : for (i = 1; i < l; i++) c[conj[i]]++;
3420 308 : return c;
3421 : }
3422 : GEN
3423 308 : galoisconjclasses(GEN G)
3424 : {
3425 308 : pari_sp av = avma;
3426 308 : GEN c, e, cc = group_to_cc(G);
3427 308 : GEN elts = gel(cc,1), conj = gel(cc,2), repr = gel(cc,3);
3428 308 : long i, l = lg(conj), lc = lg(repr);
3429 308 : c = conjclasses_count(conj, lc-1);
3430 308 : e = cgetg(lc, t_VEC);
3431 3143 : for (i = 1; i < lc; i++) gel(e,i) = cgetg(c[i]+1, t_VEC);
3432 4039 : for (i = 1; i < l; i++)
3433 : {
3434 3731 : long ci = conj[i];
3435 3731 : gmael(e, ci, c[ci]) = gel(elts, i);
3436 3731 : c[ci]--;
3437 : }
3438 308 : return gerepilecopy(av, e);
3439 : }
3440 :
3441 : static GEN
3442 826 : groupelts_to_group_or_elts(GEN elts)
3443 : {
3444 826 : GEN G = groupelts_to_group(elts);
3445 826 : return G ? G: gcopy(elts);
3446 : }
3447 :
3448 : static GEN
3449 14 : vec_groupelts_to_group_or_elts(GEN x)
3450 840 : { pari_APPLY_same(groupelts_to_group_or_elts(gel(x,i))) }
3451 :
3452 : GEN
3453 3213 : galoissubgroups(GEN gal)
3454 : {
3455 3213 : pari_sp av = avma;
3456 3213 : GEN S = group_is_elt(gal), G;
3457 3213 : if (S) return gerepileupto(av,
3458 : vec_groupelts_to_group_or_elts(groupelts_solvablesubgroups(S)));
3459 3199 : G = checkgroup(gal, &S);
3460 3199 : return gerepileupto(av, group_subgroups(G));
3461 : }
3462 :
3463 : GEN
3464 84 : galoissubfields(GEN G, long flag, long v)
3465 : {
3466 84 : pari_sp av = avma;
3467 84 : GEN L = galoissubgroups(G);
3468 84 : long i, l = lg(L);
3469 84 : GEN S = cgetg(l, t_VEC);
3470 1309 : for (i = 1; i < l; ++i) gel(S,i) = galoisfixedfield(G, gmael(L,i,1), flag, v);
3471 84 : return gerepileupto(av, S);
3472 : }
3473 :
3474 : GEN
3475 28 : galoisexport(GEN gal, long format)
3476 : {
3477 28 : pari_sp av = avma;
3478 28 : GEN S, G = checkgroup(gal,&S);
3479 28 : return gerepileupto(av, group_export(G,format));
3480 : }
3481 :
3482 : GEN
3483 504 : galoisidentify(GEN gal)
3484 : {
3485 504 : pari_sp av = avma;
3486 : long idx, card;
3487 504 : GEN S = group_is_elt(gal), G;
3488 504 : G = S ? S: checkgroup(gal,&S);
3489 497 : idx = group_ident(G,S);
3490 497 : card = S ? lg(S)-1: group_order(G);
3491 497 : set_avma(av); return mkvec2s(card, idx);
3492 : }
3493 :
3494 : /* index of conjugacy class containing g */
3495 : static long
3496 36939 : cc_id(GEN cc, GEN g)
3497 : {
3498 36939 : GEN conj = gel(cc,2);
3499 36939 : long k = signe(gel(cc,4))? g[1]: vecvecsmall_search(gel(cc,1), g);
3500 36939 : return conj[k];
3501 : }
3502 :
3503 : static GEN
3504 4186 : Qevproj_RgX(GEN c, long d, GEN pro)
3505 4186 : { return RgV_to_RgX(Qevproj_down(RgX_to_RgC(c,d), pro), varn(c)); }
3506 : /* c in Z[X] / (X^o-1), To = polcyclo(o), T = polcyclo(expo), e = expo/o
3507 : * return c(X^e) mod T as an element of Z[X] / (To) */
3508 : static GEN
3509 3920 : chival(GEN c, GEN T, GEN To, long e, GEN pro, long phie)
3510 : {
3511 3920 : c = ZX_rem(c, To);
3512 3920 : if (e != 1) c = ZX_rem(RgX_inflate(c,e), T);
3513 3920 : if (pro) c = Qevproj_RgX(c, phie, pro);
3514 3920 : return c;
3515 : }
3516 : /* chi(g^l) = sum_{k=0}^{o-1} a_k zeta_o^{l*k} for all l;
3517 : * => a_k = 1/o sum_{l=0}^{o-1} chi(g^l) zeta_o^{-k*l}. Assume o > 1 */
3518 : static GEN
3519 861 : chiFT(GEN cp, GEN jg, GEN vze, long e, long o, ulong p, ulong pov2)
3520 : {
3521 861 : const long var = 1;
3522 861 : ulong oinv = Fl_inv(o,p);
3523 : long k, l;
3524 861 : GEN c = cgetg(o+2, t_POL);
3525 5642 : for (k = 0; k < o; k++)
3526 : {
3527 4781 : ulong a = 0;
3528 51478 : for (l=0; l<o; l++)
3529 : {
3530 46697 : ulong z = vze[Fl_mul(k,l,o)*e + 1];/* zeta_o^{-k*l} */
3531 46697 : a = Fl_add(a, Fl_mul(uel(cp,jg[l+1]), z, p), p);
3532 : }
3533 4781 : gel(c,k+2) = stoi(Fl_center(Fl_mul(a,oinv,p), p, pov2)); /* a_k */
3534 : }
3535 861 : c[1] = evalvarn(var) | evalsigne(1); return ZX_renormalize(c,o+2);
3536 : }
3537 : static GEN
3538 546 : cc_chartable(GEN cc)
3539 : {
3540 : GEN al, elts, rep, ctp, ct, dec, id, vjg, H, vord, operm;
3541 : long i, j, k, f, l, expo, lcl, n;
3542 : ulong p, pov2;
3543 :
3544 546 : elts = gel(cc,1); n = lg(elts)-1;
3545 546 : if (n == 1) return mkvec2(mkmat(mkcol(gen_1)), gen_1);
3546 532 : rep = gel(cc,3);
3547 532 : lcl = lg(rep);
3548 532 : vjg = cgetg(lcl, t_VEC);
3549 532 : vord = cgetg(lcl,t_VECSMALL);
3550 532 : id = identity_perm(lg(gel(elts,1))-1);
3551 532 : expo = 1;
3552 4879 : for(j=1;j<lcl;j++)
3553 : {
3554 4347 : GEN jg, h = id, g = gel(elts,rep[j]);
3555 : long o;
3556 4347 : vord[j] = o = perm_orderu(g);
3557 4347 : expo = ulcm(expo, o);
3558 4347 : gel(vjg,j) = jg = cgetg(o+1,t_VECSMALL);
3559 27671 : for (l=1; l<=o; l++)
3560 : {
3561 23324 : jg[l] = cc_id(cc, h); /* index of conjugacy class of g^(l-1) */
3562 23324 : if (l < o) h = perm_mul(h, g);
3563 : }
3564 : }
3565 : /* would sort conjugacy classes by inc. order */
3566 532 : operm = vecsmall_indexsort(vord);
3567 :
3568 : /* expo > 1, exponent of G */
3569 532 : p = unextprime(2*n+1);
3570 1043 : while (p%expo != 1) p = unextprime(p+1);
3571 : /* compute character table modulo p: idempotents of Z(KG) */
3572 532 : al = conjclasses_algcenter(cc, utoipos(p));
3573 532 : dec = algsimpledec_ss(al,1);
3574 532 : ctp = cgetg(lcl,t_VEC);
3575 4879 : for(i=1; i<lcl; i++)
3576 : {
3577 4347 : GEN e = ZV_to_Flv(gmael3(dec,i,3,1), p); /*(1/n)[(dim chi)chi(g): g in G]*/
3578 4347 : ulong d = usqrt(Fl_mul(e[1], n, p)); /* = chi(1) <= sqrt(n) < sqrt(p) */
3579 4347 : gel(ctp,i) = Flv_Fl_mul(e,Fl_div(n,d,p), p); /*[chi(g): g in G]*/
3580 : }
3581 : /* Find minimal f such that table is defined over Q(zeta(f)): the conductor
3582 : * of the class field Q(\zeta_e)^H defined by subgroup
3583 : * H = { k in (Z/e)^*: g^k ~ g, for all g } */
3584 532 : H = coprimes_zv(expo);
3585 3458 : for (k = 2; k < expo; k++)
3586 : {
3587 2926 : if (!H[k]) continue;
3588 2548 : for (j = 2; j < lcl; j++) /* skip g ~ 1 */
3589 2366 : if (umael(vjg,j,(k % vord[j])+1) != umael(vjg,j,2)) { H[k] = 0; break; }
3590 : }
3591 532 : f = znstar_conductor_bits(Flv_to_F2v(H));
3592 : /* lift character table to Z[zeta_f] */
3593 532 : pov2 = p>>1;
3594 532 : ct = cgetg(lcl, t_MAT);
3595 532 : if (f == 1)
3596 : { /* rational representation */
3597 938 : for (j=1; j<lcl; j++) gel(ct,j) = cgetg(lcl,t_COL);
3598 938 : for(j=1; j<lcl; j++)
3599 : {
3600 791 : GEN jg = gel(vjg,j); /* jg[l+1] = class of g^l */
3601 791 : long t = lg(jg) > 2? jg[2]: jg[1];
3602 6706 : for(i=1; i<lcl; i++)
3603 : {
3604 5915 : GEN cp = gel(ctp,i); /* cp[i] = chi(g_i) mod \P */
3605 5915 : gcoeff(ct,j,i) = stoi(Fl_center(cp[t], p, pov2));
3606 : }
3607 : }
3608 : }
3609 : else
3610 : {
3611 385 : const long var = 1;
3612 385 : ulong ze = Fl_powu(pgener_Fl(p),(p-1)/expo, p); /* seen as zeta_e^(-1) */
3613 385 : GEN vze = Fl_powers(ze, expo-1, p); /* vze[i] = ze^(i-1) */
3614 385 : GEN vzeZX = const_vec(p, gen_0);
3615 385 : GEN T = polcyclo(expo, var), vT = const_vec(expo,NULL), pro = NULL;
3616 385 : long phie = degpol(T), id1 = gel(vjg,1)[1]; /* index of 1_G, always 1 ? */
3617 385 : gel(vT, expo) = T;
3618 385 : if (f != expo)
3619 : {
3620 147 : long phif = eulerphiu(f);
3621 147 : GEN zf = ZX_rem(pol_xn(expo/f,var), T), zfj = zf;
3622 147 : GEN M = cgetg(phif+1, t_MAT);
3623 147 : gel(M,1) = col_ei(phie,1);
3624 518 : for (j = 2; j <= phif; j++)
3625 : {
3626 371 : gel(M,j) = RgX_to_RgC(zfj, phie);
3627 371 : if (j < phif) zfj = ZX_rem(ZX_mul(zfj, zf), T);
3628 : }
3629 147 : pro = Qevproj_init(M);
3630 : }
3631 385 : gel(vzeZX,1) = pol_1(var);
3632 3416 : for (i = 2; i <= expo; i++)
3633 : {
3634 3031 : GEN t = ZX_rem(pol_xn(expo-(i-1), var), T);
3635 3031 : if (pro) t = Qevproj_RgX(t, phie, pro);
3636 3031 : gel(vzeZX, vze[i]) = t;
3637 : }
3638 3941 : for(i=1; i<lcl; i++)
3639 : { /* loop over characters */
3640 3556 : GEN cp = gel(ctp,i), C, cj; /* cp[j] = chi(g_j) mod \P */
3641 3556 : long dim = cp[id1];
3642 3556 : gel(ct, i) = C = const_col(lcl-1, NULL);
3643 3556 : gel(C,operm[1]) = utoi(dim); /* chi(1_G) */
3644 40978 : for (j=lcl-1; j > 1; j--)
3645 : { /* loop over conjugacy classes, decreasing order: skip 1_G */
3646 37422 : long e, jperm = operm[j], o = vord[jperm];
3647 37422 : GEN To, jg = gel(vjg,jperm); /* jg[l+1] = class of g^l */
3648 :
3649 37422 : if (gel(C, jperm)) continue; /* done already */
3650 35903 : if (dim == 1) { gel(C, jperm) = gel(vzeZX, cp[jg[2]]); continue; }
3651 861 : e = expo / o;
3652 861 : cj = chiFT(cp, jg, vze, e, o, p, pov2);
3653 861 : To = gel(vT, o); if (!To) To = gel(vT,o) = polcyclo(o, var);
3654 861 : gel(C, jperm) = chival(cj, T, To, e, pro, phie);
3655 3920 : for (k = 2; k < o; k++)
3656 : {
3657 3059 : GEN ck = RgX_inflate(cj, k); /* chi(g^k) */
3658 3059 : gel(C, jg[k+1]) = chival(ck, T, To, e, pro, phie);
3659 : }
3660 : }
3661 : }
3662 : }
3663 532 : ct = gen_sort_shallow(ct,(void*)cmp_universal,cmp_nodata);
3664 1736 : i = 1; while (!vec_isconst(gel(ct,i))) i++;
3665 532 : if (i > 1) swap(gel(ct,1), gel(ct,i));
3666 532 : return mkvec2(ct, utoipos(f));
3667 : }
3668 : GEN
3669 553 : galoischartable(GEN gal)
3670 : {
3671 553 : pari_sp av = avma;
3672 553 : GEN cc = group_to_cc(gal);
3673 546 : return gerepilecopy(av, cc_chartable(cc));
3674 : }
3675 :
3676 : static void
3677 1491 : checkgaloischar(GEN ch, GEN repr)
3678 : {
3679 1491 : if (gvar(ch) == 0) pari_err_PRIORITY("galoischarpoly",ch,"=",0);
3680 1491 : if (!is_vec_t(typ(ch))) pari_err_TYPE("galoischarpoly", ch);
3681 1491 : if (lg(repr) != lg(ch)) pari_err_DIM("galoischarpoly");
3682 1491 : }
3683 :
3684 : static long
3685 1547 : galoischar_dim(GEN ch)
3686 : {
3687 1547 : pari_sp av = avma;
3688 1547 : long d = gtos(simplify_shallow(lift_shallow(gel(ch,1))));
3689 1547 : return gc_long(av,d);
3690 : }
3691 :
3692 : static GEN
3693 12355 : galoischar_aut_charpoly(GEN cc, GEN ch, GEN p, long d)
3694 : {
3695 12355 : GEN q = p, V = cgetg(d+2, t_POL);
3696 : long i;
3697 12355 : V[1] = evalsigne(1)|evalvarn(0);
3698 25970 : for (i = 1; i <= d; i++)
3699 : {
3700 13615 : gel(V,i+1) = gel(ch, cc_id(cc,q));
3701 13615 : if (i < d) q = perm_mul(q, p);
3702 : }
3703 12355 : return liftpol_shallow(RgXn_expint(RgX_neg(V),d+1));
3704 : }
3705 :
3706 : static GEN
3707 1491 : galoischar_charpoly(GEN cc, GEN ch, long o)
3708 : {
3709 1491 : GEN chm, V, elts = gel(cc,1), repr = gel(cc,3);
3710 1491 : long i, d, l = lg(ch), v = gvar(ch);
3711 1491 : checkgaloischar(ch, repr);
3712 1491 : chm = v < 0 ? ch: gmodulo(ch, polcyclo(o, v));
3713 1491 : V = cgetg(l, t_COL); d = galoischar_dim(ch);
3714 13846 : for (i = 1; i < l; i++)
3715 12355 : gel(V,i) = galoischar_aut_charpoly(cc, chm, gel(elts,repr[i]), d);
3716 1491 : return V;
3717 : }
3718 :
3719 : GEN
3720 1435 : galoischarpoly(GEN gal, GEN ch, long o)
3721 : {
3722 1435 : pari_sp av = avma;
3723 1435 : GEN cc = group_to_cc(gal);
3724 1435 : return gerepilecopy(av, galoischar_charpoly(cc, ch, o));
3725 : }
3726 :
3727 : static GEN
3728 56 : cc_char_det(GEN cc, GEN ch, long o)
3729 : {
3730 56 : long i, l = lg(ch), d = galoischar_dim(ch);
3731 56 : GEN V = galoischar_charpoly(cc, ch, o);
3732 280 : for (i = 1; i < l; i++) gel(V,i) = leading_coeff(gel(V,i));
3733 56 : return odd(d)? gneg(V): V;
3734 : }
3735 :
3736 : GEN
3737 56 : galoischardet(GEN gal, GEN ch, long o)
3738 : {
3739 56 : pari_sp av = avma;
3740 56 : GEN cc = group_to_cc(gal);
3741 56 : return gerepilecopy(av, cc_char_det(cc, ch, o));
3742 : }
|