/* pol^2 mod (x^2+x+1, N) */ static GEN sqrmod3(GEN pol, Red *R) { GEN a,b,bma,A,B; long lv = lg(pol); if (lv==2) return pol; if (lv==3) return sqrconst(pol, R); a = gel(pol,3); b = gel(pol,2); bma = subii(b,a); A = centermodii(mulii(a,addii(b,bma)), R->N, R->N2); B = centermodii(mulii(bma,addii(a,b)), R->N, R->N2); return makepoldeg1(A,B); }
/* S1 * u - P1 * round(P^-1 S u). K non-zero coords in u given by ind */ static GEN get_trace(GEN ind, trace_data *T) { long i, j, l, K = lg(ind)-1; GEN z, s, v; s = gel(T->S1, ind[1]); if (K == 1) return s; /* compute s = S1 u */ for (j=2; j<=K; j++) s = gadd(s, gel(T->S1, ind[j])); /* compute v := - round(P^1 S u) */ l = lg(s); v = cgetg(l, t_VECSMALL); for (i=1; i<l; i++) { double r, t = 0.; /* quick approximate computation */ for (j=1; j<=K; j++) t += T->PinvSdbl[ ind[j] ][i]; r = floor(t + 0.5); if (fabs(t + 0.5 - r) < 0.0001) { /* dubious, compute exactly */ z = gen_0; for (j=1; j<=K; j++) z = addii(z, ((GEN**)T->dPinvS)[ ind[j] ][i]); v[i] = - itos( diviiround(z, T->d) ); } else v[i] = - (long)r; } return gadd(s, ZM_zc_mul(T->P1, v)); }
GEN F2xq_ellcard(GEN a, GEN a6, GEN T) { pari_sp av = avma; long n = F2x_degree(T); GEN q = int2u(n), c; if (typ(a)==t_VECSMALL) { GEN t = F2xq_elltrace_Harley(a6, T); c = addii(q, F2xq_trace(a,T) ? addui(1,t): subui(1,t)); } else if (n==1) { long a4i = lgpol(gel(a,2)), a6i = lgpol(a6); return utoi(a4i? (a6i? 1: 5): 3); } else if (n==2) { GEN a3 = gel(a,1), a4 = gel(a,2), x = polx_F2x(T[1]), x1 = pol1_F2x(T[1]); GEN a613 = F2xq_mul(F2x_add(x1, a6),a3,T), a43= F2xq_mul(a4,a3,T); long f0= F2xq_trace(F2xq_mul(a6,a3,T),T); long f1= F2xq_trace(F2x_add(a43,a613),T); long f2= F2xq_trace(F2x_add(F2xq_mul(a43,x,T),a613),T); long f3= F2xq_trace(F2x_add(F2xq_mul(a43,F2x_add(x,x1),T),a613),T); c = utoi(9-2*(f0+f1+f2+f3)); } else { struct _F2xqE e; long m = (n+1)>>1; GEN q1 = addis(q, 1); GEN v = n==4 ? mkvec4s(13,17,21,25) : odd(n) ? mkvec3(subii(q1,int2u(m)),q1,addii(q1,int2u(m))): mkvec5(subii(q1,int2u(m+1)),subii(q1,int2u(m)),q1, addii(q1,int2u(m)),addii(q1,int2u(m+1))); e.a2=a; e.a6=a6; e.T=T; c = gen_select_order(v,(void*)&e, &F2xqE_group); if (n==4 && equaliu(c, 21)) /* Ambiguous case */ { GEN d = F2xq_powu(polx_F2x(T[1]),3,T), a3 = gel(a,1); e.a6 = F2x_add(a6,F2xq_mul(d,F2xq_sqr(a3,T),T)); /* twist */ c = subui(34, gen_select_order(mkvec2s(13,25),(void*)&e, &F2xqE_group)); } } return gerepileuptoint(av, c); }
/* 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); }
/* assume x in Fq, return Tr_{Fq/Fp}(x) as a t_INT */ static GEN trace(GEN x, GEN Trq, GEN p) { long i, l; GEN s; if (typ(x) == t_INT) return modii(mulii(x, gel(Trq,1)), p); l = lg(x)-1; if (l == 1) return gen_0; x++; s = mulii(gel(x,1), gel(Trq,1)); for (i=2; i<l; i++) s = addii(s, mulii(gel(x,i), gel(Trq,i))); return modii(s, p); }
/* pol^2 mod (polcyclo(5),N) */ static GEN sqrmod5(GEN pol, Red *R) { GEN c2,b,c,d,A,B,C,D; long lv = lg(pol); if (lv==2) return pol; if (lv==3) return sqrconst(pol, R); c = gel(pol,3); c2 = shifti(c,1); d = gel(pol,2); if (lv==4) { A = sqri(d); B = mulii(c2, d); C = sqri(c); A = centermodii(A, R->N, R->N2); B = centermodii(B, R->N, R->N2); C = centermodii(C, R->N, R->N2); return mkpoln(3,A,B,C); } b = gel(pol,4); if (lv==5) { A = mulii(b, subii(c2,b)); B = addii(sqri(c), mulii(b, subii(shifti(d,1),b))); C = subii(mulii(c2,d), sqri(b)); D = mulii(subii(d,b), addii(d,b)); } else { /* lv == 6 */ GEN a = gel(pol,5), a2 = shifti(a,1); /* 2a(d - c) + b(2c - b) */ A = addii(mulii(a2, subii(d,c)), mulii(b, subii(c2,b))); /* c(c - 2a) + b(2d - b) */ B = addii(mulii(c, subii(c,a2)), mulii(b, subii(shifti(d,1),b))); /* (a-b)(a+b) + 2c(d - a) */ C = addii(mulii(subii(a,b),addii(a,b)), mulii(c2,subii(d,a))); /* 2a(b - c) + (d-b)(d+b) */ D = addii(mulii(a2, subii(b,c)), mulii(subii(d,b), addii(d,b))); } A = centermodii(A, R->N, R->N2); B = centermodii(B, R->N, R->N2); C = centermodii(C, R->N, R->N2); D = centermodii(D, R->N, R->N2); return mkpoln(4,A,B,C,D); }
} // Return value: Did the user break out of the loop? // Not stack clean. int palhelper(long digits, GEN a, GEN b, GEN code) { GEN p10 = powuu(10, (digits+1)>>1); GEN aLeft = divii(a, p10); GEN bLeft = divii(b, p10); GEN cur; // TODO: Handle case of digits odd (middle digit) pari_sp btop = avma, lim = stack_lim(btop,1); cur = addii(mulii(aLeft, p10), rev(aLeft, 10)); if (cmpii(cur, a) < 0) { aLeft = addis(aLeft, 1); cur = addii(mulii(aLeft, p10), rev(aLeft, 10)); } push_lex(cur, code); while (cmpii(aLeft, bLeft) < 0) { closure_evalvoid(code); if (loop_break()) { pop_lex(1); return(1); } //cur = get_lex(-1); // Allow the user to modify the variable aLeft = addis(aLeft, 1);
int ratlift(GEN x, GEN m, GEN *a, GEN *b, GEN amax, GEN bmax) { GEN d,d1,v,v1,q,r; pari_sp av = avma, av1, lim; long lb,lr,lbb,lbr,s,s0; ulong vmax; ulong xu,xu1,xv,xv1; /* Lehmer stage recurrence matrix */ int lhmres; /* Lehmer stage return value */ if ((typ(x) | typ(m) | typ(amax) | typ(bmax)) != t_INT) pari_err(arither1); if (signe(bmax) <= 0) pari_err(talker, "ratlift: bmax must be > 0, found\n\tbmax=%Z\n", bmax); if (signe(amax) < 0) pari_err(talker, "ratilft: amax must be >= 0, found\n\tamax=%Z\n", amax); /* check 2*amax*bmax < m */ if (cmpii(shifti(mulii(amax, bmax), 1), m) >= 0) pari_err(talker, "ratlift: must have 2*amax*bmax < m, found\n\tamax=%Z\n\tbmax=%Z\n\tm=%Z\n", amax,bmax,m); /* we _could_ silently replace x with modii(x,m) instead of the following, * but let's leave this up to the caller */ avma = av; s = signe(x); if (s < 0 || cmpii(x,m) >= 0) pari_err(talker, "ratlift: must have 0 <= x < m, found\n\tx=%Z\n\tm=%Z\n", x,m); /* special cases x=0 and/or amax=0 */ if (s == 0) { if (a != NULL) *a = gen_0; if (b != NULL) *b = gen_1; return 1; } else if (signe(amax)==0) return 0; /* assert: m > x > 0, amax > 0 */ /* check here whether a=x, b=1 is a solution */ if (cmpii(x,amax) <= 0) { if (a != NULL) *a = icopy(x); if (b != NULL) *b = gen_1; return 1; } /* There is no special case for single-word numbers since this is * mainly meant to be used with large moduli. */ (void)new_chunk(lgefint(bmax) + lgefint(amax)); /* room for a,b */ d = m; d1 = x; v = gen_0; v1 = gen_1; /* assert d1 > amax, v1 <= bmax here */ lb = lgefint(bmax); lbb = bfffo(*int_MSW(bmax)); s = 1; av1 = avma; lim = stack_lim(av, 1); /* general case: Euclidean division chain starting with m div x, and * with bounds on the sequence of convergents' denoms v_j. * Just to be different from what invmod and bezout are doing, we work * here with the all-nonnegative matrices [u,u1;v,v1]=prod_j([0,1;1,q_j]). * Loop invariants: * (a) (sign)*[-v,v1]*x = [d,d1] (mod m) (componentwise) * (sign initially +1, changes with each Euclidean step) * so [a,b] will be obtained in the form [-+d,v] or [+-d1,v1]; * this congruence is a consequence of * (b) [x,m]~ = [u,u1;v,v1]*[d1,d]~, * where u,u1 is the usual numerator sequence starting with 1,0 * instead of 0,1 (just multiply the eqn on the left by the inverse * matrix, which is det*[v1,-u1;-v,u], where "det" is the same as the * "(sign)" in (a)). From m = v*d1 + v1*d and * (c) d > d1 >= 0, 0 <= v < v1, * we have d >= m/(2*v1), so while v1 remains smaller than m/(2*amax), * the pair [-(sign)*d,v] satisfies (1) but violates (2) (d > amax). * Conversely, v1 > bmax indicates that no further solutions will be * forthcoming; [-(sign)*d,v] will be the last, and first, candidate. * Thus there's at most one point in the chain division where a solution * can live: v < bmax, v1 >= m/(2*amax) > bmax, and this is acceptable * iff in fact d <= amax (e.g. m=221, x=34 or 35, amax=bmax=10 fail on * this count while x=32,33,36,37 succeed). However, a division may leave * a zero residue before we ever reach this point (consider m=210, x=35, * amax=bmax=10), and our caller may find that gcd(d,v) > 1 (numerous * examples -- keep m=210 and consider any of x=29,31,32,33,34,36,37,38, * 39,40,41). * Furthermore, at the start of the loop body we have in fact * (c') 0 <= v < v1 <= bmax, d > d1 > amax >= 0, * (and are never done already). * * Main loop is similar to those of invmod() and bezout(), except for * having to determine appropriate vmax bounds, and checking termination * conditions. The signe(d1) condition is only for paranoia */ while (lgefint(d) > 3 && signe(d1)) { /* determine vmax for lgcdii so as to ensure v won't overshoot. * If v+v1 > bmax, the next step would take v1 beyond the limit, so * since [+-d1,v1] is not a solution, we give up. Otherwise if v+v1 * is way shorter than bmax, use vmax=MAXULUNG. Otherwise, set vmax * to a crude lower approximation of bmax/(v+v1), or to 1, which will * allow the inner loop to do one step */ r = addii(v,v1); lr = lb - lgefint(r); lbr = bfffo(*int_MSW(r)); if (cmpii(r,bmax) > 0) /* done, not found */ { avma = av; return 0; } else if (lr > 1) /* still more than a word's worth to go */ { vmax = MAXULONG; } else /* take difference of bit lengths */ { lr = (lr << TWOPOTBITS_IN_LONG) - lbb + lbr; if ((ulong)lr > BITS_IN_LONG) vmax = MAXULONG; else if (lr == 0) vmax = 1UL; else vmax = 1UL << (lr-1); /* the latter is pessimistic but faster than a division */ } /* do a Lehmer-Jebelean round */ lhmres = lgcdii((ulong *)d, (ulong *)d1, &xu, &xu1, &xv, &xv1, vmax); if (lhmres != 0) /* check progress */ { /* apply matrix */ if ((lhmres == 1) || (lhmres == -1)) { s = -s; if (xv1 == 1) { /* re-use v+v1 computed above */ v=v1; v1=r; r = subii(d,d1); d=d1; d1=r; } else { r = subii(d, mului(xv1,d1)); d=d1; d1=r; r = addii(v, mului(xv1,v1)); v=v1; v1=r; } } else { r = subii(muliu(d,xu), muliu(d1,xv)); d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r; r = addii(muliu(v,xu), muliu(v1,xv)); v1 = addii(muliu(v,xu1), muliu(v1,xv1)); v = r; if (lhmres&1) { setsigne(d,-signe(d)); s = -s; } else if (signe(d1)) { setsigne(d1,-signe(d1)); } } /* check whether we're done. Assert v <= bmax here. Examine v1: * if v1 > bmax, check d and return 0 or 1 depending on the outcome; * if v1 <= bmax, check d1 and return 1 if d1 <= amax, otherwise * proceed. */ if (cmpii(v1,bmax) > 0) /* certainly done */ { avma = av; if (cmpii(d,amax) <= 0) /* done, found */ { if (a != NULL) { *a = icopy(d); setsigne(*a,-s); /* sign opposite to s */ } if (b != NULL) *b = icopy(v); return 1; } else /* done, not found */ return 0; } else if (cmpii(d1,amax) <= 0) /* also done, found */ { avma = av; if (a != NULL) { if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); /* same sign as s */ } else *a = gen_0; } if (b != NULL) *b = icopy(v1); return 1; } } /* lhmres != 0 */ if (lhmres <= 0 && signe(d1)) { q = dvmdii(d,d1,&r); #ifdef DEBUG_LEHMER fprintferr("Full division:\n"); printf(" q = "); output(q); sleep (1); #endif d=d1; d1=r; r = addii(v,mulii(q,v1)); v=v1; v1=r; s = -s; /* check whether we are done now. Since we weren't before the div, it * suffices to examine v1 and d1 -- the new d (former d1) cannot cut it */ if (cmpii(v1,bmax) > 0) /* done, not found */ { avma = av; return 0; } else if (cmpii(d1,amax) <= 0) /* done, found */ { avma = av; if (a != NULL) { if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); /* same sign as s */ } else *a = gen_0; } if (b != NULL) *b = icopy(v1); return 1; } } if (low_stack(lim, stack_lim(av,1))) { GEN *gptr[4]; gptr[0]=&d; gptr[1]=&d1; gptr[2]=&v; gptr[3]=&v1; if(DEBUGMEM>1) pari_warn(warnmem,"ratlift"); gerepilemany(av1,gptr,4); } } /* end while */ /* Postprocessing - final sprint. Since we usually underestimate vmax, * this function needs a loop here instead of a simple conditional. * Note we can only get here when amax fits into one word (which will * typically not be the case!). The condition is bogus -- d1 is never * zero at the start of the loop. There will be at most a few iterations, * so we don't bother collecting garbage */ while (signe(d1)) { /* Assertions: lgefint(d)==lgefint(d1)==3. * Moreover, we aren't done already, or we would have returned by now. * Recompute vmax... */ #ifdef DEBUG_RATLIFT fprintferr("rl-fs: d,d1=%Z,%Z\n", d, d1); fprintferr("rl-fs: v,v1=%Z,%Z\n", v, v1); #endif r = addii(v,v1); lr = lb - lgefint(r); lbr = bfffo(*int_MSW(r)); if (cmpii(r,bmax) > 0) /* done, not found */ { avma = av; return 0; } else if (lr > 1) /* still more than a word's worth to go */ { vmax = MAXULONG; /* (cannot in fact happen) */ } else /* take difference of bit lengths */ { lr = (lr << TWOPOTBITS_IN_LONG) - lbb + lbr; if ((ulong)lr > BITS_IN_LONG) vmax = MAXULONG; else if (lr == 0) vmax = 1UL; else vmax = 1UL << (lr-1); /* as above */ } #ifdef DEBUG_RATLIFT fprintferr("rl-fs: vmax=%lu\n", vmax); #endif /* single-word "Lehmer", discarding the gcd or whatever it returns */ (void)rgcduu((ulong)*int_MSW(d), (ulong)*int_MSW(d1), vmax, &xu, &xu1, &xv, &xv1, &s0); #ifdef DEBUG_RATLIFT fprintferr("rl-fs: [%lu,%lu; %lu,%lu] %s\n", xu, xu1, xv, xv1, s0 < 0 ? "-" : "+"); #endif if (xv1 == 1) /* avoid multiplications */ { /* re-use v+v1 computed above */ v=v1; v1=r; r = subii(d,d1); d=d1; d1=r; s = -s; } else if (xu == 0) /* and xv==1, xu1==1, xv1 > 1 */ { r = subii(d, mului(xv1,d1)); d=d1; d1=r; r = addii(v, mului(xv1,v1)); v=v1; v1=r; s = -s; } else { r = subii(muliu(d,xu), muliu(d1,xv)); d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r; r = addii(muliu(v,xu), muliu(v1,xv)); v1 = addii(muliu(v,xu1), muliu(v1,xv1)); v = r; if (s0 < 0) { setsigne(d,-signe(d)); s = -s; } else if (signe(d1)) /* sic: might vanish now */ { setsigne(d1,-signe(d1)); } } /* check whether we're done, as above. Assert v <= bmax. Examine v1: * if v1 > bmax, check d and return 0 or 1 depending on the outcome; * if v1 <= bmax, check d1 and return 1 if d1 <= amax, otherwise proceed. */ if (cmpii(v1,bmax) > 0) /* certainly done */ { avma = av; if (cmpii(d,amax) <= 0) /* done, found */ { if (a != NULL) { *a = icopy(d); setsigne(*a,-s); /* sign opposite to s */ } if (b != NULL) *b = icopy(v); return 1; } else /* done, not found */ return 0; } else if (cmpii(d1,amax) <= 0) /* also done, found */ { avma = av; if (a != NULL) { if (signe(d1)) { *a = icopy(d1); setsigne(*a,s); /* same sign as s */ } else *a = gen_0; } if (b != NULL) *b = icopy(v1); return 1; } } /* while */ /* get here when we have run into d1 == 0 before returning... in fact, * this cannot happen. */ pari_err(talker, "ratlift failed to catch d1 == 0\n"); /* NOTREACHED */ return 0; }