GEN gcdii(GEN a, GEN b) { long v, w; pari_sp av; GEN t; switch (absi_cmp(a,b)) { case 0: return absi(a); case -1: swap(a,b); } if (!signe(b)) return absi(a); /* here |a|>|b|>0. Try single precision first */ if (lgefint(a)==3) return igcduu((ulong)a[2], (ulong)b[2]); if (lgefint(b)==3) { ulong u = resiu(a,(ulong)b[2]); if (!u) return absi(b); return igcduu((ulong)b[2], u); } /* larger than gcd: "avma=av" gerepile (erasing t) is valid */ av = avma; (void)new_chunk(lgefint(b)+1); /* HACK */ t = remii(a,b); if (!signe(t)) { avma=av; return absi(b); } a = b; b = t; v = vali(a); a = shifti(a,-v); setabssign(a); w = vali(b); b = shifti(b,-w); setabssign(b); if (w < v) v = w; switch(absi_cmp(a,b)) { case 0: avma=av; a=shifti(a,v); return a; case -1: swap(a,b); } if (is_pm1(b)) { avma=av; return int2n(v); } { /* general case */ /*This serve two purposes: 1) mpn_gcd destroy its input and need an extra * limb 2) this allows us to use icopy instead of gerepile later. NOTE: we * must put u before d else the final icopy could fail. */ GEN res= cgeti(lgefint(a)+1); GEN ca = icopy_ef(a,lgefint(a)+1); GEN cb = icopy_ef(b,lgefint(b)+1); long l = mpn_gcd(LIMBS(res), LIMBS(ca), NLIMBS(ca), LIMBS(cb), NLIMBS(cb)); res[1] = evalsigne(1)|evallgefint(l+2); avma=av; return shifti(res,v); } }
/* return 0 if |g[i]| > M[i] for some i; 1 otherwise */ static long ok_coeffs(GEN g,GEN M) { long i, lg = lg(g)-1; /* g is monic, and cst term is ok */ for (i=3; i<lg; i++) if (absi_cmp(gel(g,i), gel(M,i)) > 0) return 0; return 1; }
/* Return a subfield, gen_0 [ change p ] or NULL [ not a subfield ] */ static GEN subfield(GEN A, blockdata *B) { long N, i, j, d, lf, m = lg(A)-1; GEN M, pe, pol, fhk, g, e, d_1_term, delta, listdelta, whichdelta; GEN T = B->S->T, p = B->S->p, firstroot = B->S->firstroot; pol= (GEN)B->DATA[1]; N = degpol(pol); d = N/m; /* m | N */ pe = (GEN)B->DATA[2]; fhk= (GEN)B->DATA[3]; M = (GEN)B->DATA[8]; delta = cgetg(m+1,t_VEC); whichdelta = cgetg(N+1, t_VECSMALL); d_1_term = gen_0; for (i=1; i<=m; i++) { GEN Ai = gel(A,i), p1 = (GEN)fhk[Ai[1]]; for (j=2; j<=d; j++) p1 = Fq_mul(p1, (GEN)fhk[Ai[j]], T, pe); gel(delta,i) = p1; if (DEBUGLEVEL>2) fprintferr("delta[%ld] = %Z\n",i,p1); /* g = prod (X - delta[i]) * if g o h = 0 (pol), we'll have h(Ai[j]) = delta[i] for all j */ /* fk[k] belongs to block number whichdelta[k] */ for (j=1; j<=d; j++) whichdelta[Ai[j]] = i; if (typ(p1) == t_POL) p1 = constant_term(p1); d_1_term = addii(d_1_term, p1); } d_1_term = centermod(d_1_term, pe); /* Tr(g) */ if (absi_cmp(d_1_term, gel(M,3)) > 0) { if (DEBUGLEVEL>1) fprintferr("d-1 test failed\n"); return NULL; } g = FqV_roots_to_pol(delta, T, pe, 0); g = centermod(polsimplify(g), pe); /* assume g in Z[X] */ if (DEBUGLEVEL>2) fprintferr("pol. found = %Z\n",g); if (!ok_coeffs(g,M)) { if (DEBUGLEVEL>1) fprintferr("coeff too big for pol g(x)\n"); return NULL; } if (!FpX_is_squarefree(g, p)) { if (DEBUGLEVEL>1) fprintferr("changing f(x): p divides disc(g)\n"); compute_data(B); return subfield(A, B); } lf = lg(firstroot); listdelta = cgetg(lf, t_VEC); for (i=1; i<lf; i++) listdelta[i] = delta[whichdelta[firstroot[i]]]; if (DEBUGLEVEL) fprintferr("candidate = %Z\n", g); e = embedding(g, B->DATA, B->S, B->PD->den, listdelta); if (!e) return NULL; if (DEBUGLEVEL) fprintferr("embedding = %Z\n", e); return _subfield(g, e); }