Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2017 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314/* This file is based on ratpoints-2.1.3 by Michael Stoll, see15* http://www.mathe2.uni-bayreuth.de/stoll/programs/16* Original copyright / license: */17/***********************************************************************18* ratpoints-2.1.3 *19* Copyright (C) 2008, 2009 Michael Stoll *20* - A program to find rational points on hyperelliptic curves *21* *22* This program is free software: you can redistribute it and/or *23* modify it under the terms of the GNU General Public License *24* as published by the Free Software Foundation, either version 2 of *25* the License, or (at your option) any later version. *26***********************************************************************/2728#include "pari.h"29#include "paripriv.h"3031#define pel(a,b) gel((a),(b)+2)3233#define RATPOINTS_ARRAY_SIZE 256 /* Array size in longs */34#define RATPOINTS_DEFAULT_SP1 9 /* Default value for sp1 */35#define RATPOINTS_DEFAULT_SP2 16 /* Default value for sp2 */36#define RATPOINTS_DEFAULT_NUM_PRIMES 28 /* Default value for num_primes */37#define RATPOINTS_DEFAULT_BIT_PRIMES 7 /* Default value for bit_primes */38#define RATPOINTS_DEFAULT_MAX_FORBIDDEN 30 /* Default value for max_forbidden */3940typedef struct {double low; double up;} ratpoints_interval;4142/* Define the flag bits for the flags component: */43#define RATPOINTS_NO_REVERSE 0x0004UL4445#define RATPOINTS_FLAGS_INPUT_MASK (RATPOINTS_NO_REVERSE)4647/* Flags bits for internal purposes */48#define RATPOINTS_REVERSED 0x0100UL49#define RATPOINTS_CHECK_DENOM 0x0200UL50#define RATPOINTS_USE_SQUARES 0x0400UL51#define RATPOINTS_USE_SQUARES1 0x0800UL5253#define LONG_MASK (~(-(1UL<<TWOPOTBITS_IN_LONG)))5455#define CEIL(a,b) (((a) <= 0) ? -(-(a) / (b)) : 1 + ((a)-1) / (b))5657/* Some Macros for working with SSE registers */58#ifdef HAS_SSE259#include <emmintrin.h>6061#define AND(a,b) ((ratpoints_bit_array)__builtin_ia32_andps((__v4sf)(a), (__v4sf)(b)))62#define EXT0(a) ((ulong)__builtin_ia32_vec_ext_v2di((__v2di)(a), 0))63#define EXT1(a) ((ulong)__builtin_ia32_vec_ext_v2di((__v2di)(a), 1))64#define TEST(a) (EXT0(a) || EXT1(a))65#define RBA(a) ((__v2di){((long) a), ((long) a)})6667/* Use SSE 128 bit registers for the bit arrays */68typedef __v2di ratpoints_bit_array;6970#define RBA_LENGTH (128)71#define RBA_SHIFT (7)72#define RBA_ALIGN (sizeof(ratpoints_bit_array))73#define RBA_MASK (~(-(1UL<<RBA_SHIFT)))7475#else76/* Use ulong for the bit arrays */77typedef ulong ratpoints_bit_array;78#define AND(a,b) ((a)&(b))79#define EXT0(a) (a)80#define TEST(a) (a)81#define RBA(a) (a)8283#define RBA_LENGTH BITS_IN_LONG84#define RBA_SHIFT TWOPOTBITS_IN_LONG85#define RBA_ALIGN (sizeof(long))86#define RBA_MASK LONG_MASK8788#endif8990typedef struct { long p; long offset; ratpoints_bit_array *ptr; } sieve_spec;9192typedef enum { num_all, num_even, num_odd, num_none } bit_selection;9394typedef struct {95long p; int *is_f_square;96const long *inverses;97long offset; ratpoints_bit_array** sieve;98} ratpoints_sieve_entry;99100typedef struct { long p;101ulong *start;102ulong *end;103ulong *curr; }104forbidden_entry;105106typedef struct {107GEN cof, listprime;108ratpoints_interval *domain;109long height, b_low, b_high, sp1, sp2, array_size;110long num_inter, num_primes, bit_primes, max_forbidden;111ulong flags;112/* from here: private data */113GEN bc;114ratpoints_sieve_entry *se_buffer;115ratpoints_sieve_entry *se_next;116ratpoints_bit_array *ba_buffer;117ratpoints_bit_array *ba_next;118int *int_buffer, *int_next;119forbidden_entry *forb_ba;120long *forbidden;121GEN inverses, offsets, den_info, divisors;122ulong **sieves0;123} ratpoints_args;124125#ifdef HAS_SSE2126#define CODE_INIT_SIEVE_COPY for (a = 0; a < p; a++) si[a+p] = si[a];127#else128#define CODE_INIT_SIEVE_COPY129#endif130131static ratpoints_bit_array *132#if defined(__GNUC__)133__attribute__((noinline))134#endif135sieve_init1(long p, ratpoints_sieve_entry *se1, long b1, ratpoints_args *args1)136{137ratpoints_sieve_entry *se = se1;138ratpoints_args *args = args1;139register int *isfs = se->is_f_square;140register long b = b1;141long lmp = BITS_IN_LONG % p;142long ldp = BITS_IN_LONG / p;143long p1 = (ldp + 1) * p;144long diff_shift = p1 & LONG_MASK;145long diff = BITS_IN_LONG - diff_shift;146register ulong help0;147register long a;148register long d = se->inverses[b];149register long ab = 0; /* a/b mod p */150register ulong test = 1UL;151register ulong he0 = 0UL;152for (a = 0; a < p; a++)153{154if (isfs[ab]) he0 |= test;155ab += d;156if (ab >= p) ab -= p;157test <<= 1;158}159help0 = he0;160{161register ulong help1;162/* repeat bit pattern floor(BITS_IN_LONG/p) times */163register ulong pattern = help0;164register long i;165/* the p * (floor(BITS_IN_LONG/p) + 1) - BITS_IN_LONG166= p - (BITS_IN_LONG mod p)167upper bits into help[b][1] :168shift away the BITS_IN_LONG mod p lower bits */169help1 = pattern >> lmp;170for (i = p; i < BITS_IN_LONG; i <<= 1)171help0 |= help0 << i;172{ /* fill the bit pattern from help0/help1 into sieve[b][].173sieve[b][a0] has the same semantics as help0/help1,174but here, a0 runs from 0 to p-1 and all bits are filled. */175register long a;176ulong *si = (ulong *)args->ba_next;177178args->ba_next += p;179/* copy the first chunk into sieve[b][] */180si[0] = help0;181/* now keep repeating the bit pattern,182rotating it in help0/help1 */183for (a = 1 ; a < p; a++)184{185register ulong temp = help0 >> diff;186help0 = help1 | (help0 << diff_shift);187si[a] = help0;188help1 = temp;189}190CODE_INIT_SIEVE_COPY191/* set sieve array */192se->sieve[b] = (ratpoints_bit_array *)si;193return (ratpoints_bit_array *)si;194}195}196}197198/* This is for p > BITS_IN_LONG */199static ratpoints_bit_array *200#if defined(__GNUC__)201__attribute__((noinline))202#endif203sieve_init2(long p, ratpoints_sieve_entry *se1, long b1, ratpoints_args *args1)204{205ratpoints_sieve_entry *se = se1;206ratpoints_args *args = args1;207register int *isfs = se->is_f_square;208register long b = b1;209/* long ldp = 0; = BITS_IN_LONG / p */210/* long p1 = p; = (ldp + 1) * p; */211long wp = p >> TWOPOTBITS_IN_LONG;212long diff_shift = p & LONG_MASK;213long diff = BITS_IN_LONG - diff_shift;214ulong help[(p>>TWOPOTBITS_IN_LONG) + 2];215216/* initialize help */217{218register ulong *he = &help[0];219register ulong *he1 = &he[(p>>TWOPOTBITS_IN_LONG) + 2];220while (he1 != he) { he1--; *he1 = 0UL; }221}222{ register ulong work = 0UL;223register long a;224register long ab = 0; /* a/b mod p */225register long d = se->inverses[b];226register long n = 0;227register ulong test = 1UL;228for (a = 0; a < p; )229{230if (isfs[ab]) work |= test;231ab += d;232if (ab >= p) ab -= p;233test <<= 1;234a++;235if ((a & LONG_MASK) == 0)236{ help[n] = work; n++; work = 0UL; test = 1UL; }237}238help[n] = work;239}240241{ /* fill the bit pattern from help[] into sieve[b][].242sieve[b][a0] has the same semantics as help[b][a0],243but here, a0 runs from 0 to p-1 and all bits are filled. */244register ulong *si = (ulong *)args->ba_next;245register long a1;246register long a;247248args->ba_next += p;249/* copy the first chunk from help[] into sieve[num][b][] */250for (a = 0; a < wp; a++) si[a] = help[a];251/* now keep repeating the bit pattern, rotating it in help */252for (a1 = a ; a < p; a++)253{254register long t = (a1 == wp) ? 0 : a1+1;255help[a1] |= help[t]<<diff_shift;256si[a] = help[a1];257a1 = t;258help[a1] >>= diff;259}260CODE_INIT_SIEVE_COPY261/* set sieve array */262se->sieve[b] = (ratpoints_bit_array *)si;263return (ratpoints_bit_array *)si;264}265}266267static GEN268gen_squares(GEN listprime)269{270long nbprime = lg(listprime)-1;271GEN sq = cgetg(nbprime+1, t_VEC);272long n;273for (n = 1; n <= nbprime; n++)274{275ulong i, p = uel(listprime,n);276GEN w = zero_zv(p), work = w+1;277work[0] = 1;278/* record nonzero squares mod p, p odd */279for (i = 1; i < p; i += 2) work[(i*i) % p] = 1;280gel(sq, n) = w;281}282return sq;283}284285static GEN286gen_offsets(GEN P)287{288long n, l = lg(P);289GEN of = cgetg(l, t_VEC);290for (n = 1; n < l; n++)291{292ulong p = uel(P,n);293uel(of, n) = Fl_inv((2*RBA_LENGTH)%p, p);294}295return of;296}297298static GEN299gen_inverses(GEN P)300{301long n, l = lg(P);302GEN iv = cgetg(l, t_VEC);303for (n = 1; n < l; n++)304{305ulong i, p = uel(P,n);306GEN w = cgetg(p, t_VECSMALL);307for (i = 1; i < p; i++) uel(w, i) = Fl_inv(i, p);308gel(iv, n) = w;309}310return iv;311}312313static ulong **314gen_sieves0(GEN listprime)315{316long n;317long nbprime = lg(listprime)-1;318ulong ** si = (ulong**) new_chunk(nbprime+1);319for (n = 1; n <= nbprime; n++)320{321ulong i, p = uel(listprime,n);322ulong *w = (ulong *) stack_malloc_align(2*p*sizeof(ulong), RBA_ALIGN);323for (i = 0; i < p; i++) uel(w,i) = ~0UL;324for (i = 0; i < BITS_IN_LONG; i++)325uel(w,(p*i)>>TWOPOTBITS_IN_LONG) &= ~(1UL<<((p*i) & LONG_MASK));326for (i = 0; i < p; i++) uel(w,i+p) = uel(w,i);327si[n] = w;328}329return si;330}331332static void333gen_sieve(ratpoints_args *args)334{335GEN listprimes = args->listprime;336args->offsets = gen_offsets(listprimes);337args->inverses = gen_inverses(listprimes);338args->sieves0 = gen_sieves0(listprimes);339}340341static GEN342ZX_positive_region(GEN P, long h, long bitprec)343{344long prec = nbits2prec(bitprec);345GEN it = mkvec2(stoi(-h),stoi(h));346GEN R = ZX_Uspensky(P, it, 1, bitprec);347long nR = lg(R)-1;348long s = signe(ZX_Z_eval(P,gel(it,1)));349long i=1, j;350GEN iv, st, en;351if (s<0 && nR==0) return NULL;352iv = cgetg(((nR+1+(s>=0))>>1)+1, t_VEC);353if (s>=0) st = itor(gel(it,1),prec);354else { st = gel(R,i); i++; }355for (j=1; i<nR; j++)356{357gel(iv, j) = mkvec2(st, gel(R,i));358st = gel(R,i+1);359i+=2;360}361if (i==nR) en = gel(R,i); else en = itor(gel(it,2),prec);362gel(iv,j) = mkvec2(st, en);363return iv;364}365366static long367posint(ratpoints_interval *ivlist, GEN P, long h)368{369GEN R = ZX_positive_region(P, h, 53);370const double eps = 1e-5;371long nR, i;372373if (!R) return 0;374nR = lg(R)-1;375i = 1;376for (i=1; i<=nR; i++)377{378ivlist[i-1].low = rtodbl(gmael(R,i,1))-eps;379ivlist[i-1].up = rtodbl(gmael(R,i,2))+eps;380}381return nR;382}383384static long385ratpoints_compute_sturm(ratpoints_args *args)386{387ratpoints_interval *ivlist = args->domain;388args->num_inter = posint(ivlist, args->cof, (long) ivlist[0].up);389return args->num_inter;390}391392/**************************************************************************393* Try to avoid divisions *394**************************************************************************/395INLINE long396mod(long a, long b)397{398long b1 = b << 4; /* b1 = 16*b */399400if (a < -b1) { a %= b; if (a < 0) { a += b; } return a ; }401if (a < 0) { a += b1; }402else { if (a >= b1) { return a % b; } }403b1 >>= 1; /* b1 = 8*b */404if (a >= b1) { a -= b1; }405b1 >>= 1; /* b1 = 4*b */406if (a >= b1) { a -= b1; }407b1 >>= 1; /* b1 = 2*b */408if (a >= b1) { a -= b1; }409if (a >= b) { a -= b; }410return a;411}412413static void414set_bc(long b, ratpoints_args *args)415{416GEN w0 = gen_1;417GEN c = args->cof, bc;418long k, degree = degpol(c);419bc = cgetg(degree+2, t_POL);420for (k = degree-1; k >= 0; k--)421{422w0 = muliu(w0, b);423gel(bc,k+2) = mulii(gel(c,k+2), w0);424}425args->bc = bc;426}427428/**************************************************************************429* Check a `survivor' of the sieve if it really gives a point. *430**************************************************************************/431432static long433_ratpoints_check_point(long a, long b, ratpoints_args *args, int *quit,434int process(long, long, GEN, void*, int*), void *info)435{436pari_sp av = avma;437GEN w0, w2, c = args->cof, bc = args->bc;438long k, degree = degpol(c);439int reverse = args->flags & RATPOINTS_REVERSED;440441/* Compute F(a, b), where F is the homogenized version of f442of smallest possible even degree */443w2 = gel(c, degree+2);444for (k = degree-1; k >= 0; k--)445{446w2 = mulis(w2, a);447w2 = addii(w2, gel(bc,k+2));448}449if (odd(degree)) w2 = muliu(w2, b);450/* check if f(x,z) is a square; if so, process the point(s) */451if (signe(w2) >= 0 && Z_issquareall(w2, &w0))452{453if (reverse)454{455if (a >= 0) (void)process(b, a, w0, info, quit);456else (void)process(-b, -a, w0, info, quit);457}458else (void)process(a, b, w0, info, quit);459if (!*quit && signe(w0) != 0)460{461GEN nw0 = negi(w0);462if (reverse)463{464if (a >= 0) (void)process(b, a, nw0, info, quit);465else (void)process(-b, -a, nw0, info, quit);466}467else (void)process(a, b, nw0, info, quit);468}469return 1;470}471set_avma(av);472return 0;473}474475/**************************************************************************476* The inner loop of the sieving procedure *477**************************************************************************/478static long479_ratpoints_sift0(long b, long w_low, long w_high,480ratpoints_args *args, bit_selection which_bits,481ratpoints_bit_array *survivors, sieve_spec *sieves, int *quit,482int process(long, long, GEN, void*, int*), void *info)483{484long range = w_high - w_low;485long sp1 = args->sp1;486long sp2 = args->sp2;487long i, n, nb = 0, absb = labs(b);488ratpoints_bit_array *surv0;489490/* now do the sieving (fast!) */491for (n = 0; n < sp1; n++)492{493ratpoints_bit_array *sieve_n = sieves[n].ptr;494register long p = sieves[n].p;495long r = mod(-w_low-sieves[n].offset, p);496register ratpoints_bit_array *surv = survivors;497498if (w_high < w_low + r)499{ /* if we get here, r > 0, since w_high >= w_low always */500register ratpoints_bit_array *siv1 = &sieve_n[p-r];501register ratpoints_bit_array *siv0 = siv1 + range;502503while (siv1 != siv0) { *surv = AND(*surv, *siv1++); surv++; }504}505else506{507register ratpoints_bit_array *siv1 = &sieve_n[p-r];508register ratpoints_bit_array *surv_end = &survivors[range - p];509register long i;510for (i = r; i; i--) { *surv = AND(*surv, *siv1++); surv++; }511siv1 -= p;512while (surv <= surv_end)513{514for (i = p; i; i--) { *surv = AND(*surv, *siv1++); surv++; }515siv1 -= p;516}517surv_end += p;518while (surv < surv_end) { *surv = AND(*surv, *siv1++); surv++; }519}520} /* for n */521/* 2nd phase of the sieve: test each surviving bit array with more primes */522surv0 = &survivors[0];523for (i = w_low; i < w_high; i++)524{525register ratpoints_bit_array nums = *surv0++;526sieve_spec *ssp = &sieves[sp1];527register long n;528529for (n = sp2-sp1; n && TEST(nums); n--)530{531register long p = ssp->p;532nums = AND(nums, ssp->ptr[mod(i + ssp->offset, p)]);533ssp++;534}535536/* Check the survivors of the sieve if they really give points */537if (TEST(nums))538{539long a0, a, d;540#ifdef HAS_SSE2541long da = (which_bits == num_all) ? RBA_LENGTH/2 : RBA_LENGTH;542#endif543/* a will be the numerator corresponding to the selected bit */544if (which_bits == num_all)545{546d = 1; a0 = i * RBA_LENGTH;547}548else549{550d = 2; a0 = i * 2 * RBA_LENGTH;551if (which_bits == num_odd) a0++;552}553{554#ifdef HAS_SSE2555ulong nums0 = EXT0(nums);556ulong nums1 = EXT1(nums);557#else558ulong nums0 = nums;559#endif560561for (a = a0; nums0; a += d, nums0 >>= 1)562{ /* test one bit */563if (odd(nums0) && ugcd(labs(a), absb)==1)564{565if (!args->bc) set_bc(b, args);566nb += _ratpoints_check_point(a, b, args, quit, process, info);567if (*quit) return nb;568}569}570#ifdef HAS_SSE2571for (a = a0 + da; nums1; a += d, nums1 >>= 1)572{ /* test one bit */573if (odd(nums1) && ugcd(labs(a), absb)==1)574{575if (!args->bc) set_bc(b, args);576nb += _ratpoints_check_point(a, b, args, quit, process, info);577if (*quit) return nb;578}579}580#endif581}582}583}584return nb;585}586587#define MAX_DIVISORS 512588/* Maximal length of array for squarefree divisors of leading coefficient */589590typedef struct { double r; ratpoints_sieve_entry *ssp; } entry;591592static const int squares16[16] = {1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0};593/* Says if a is a square mod 16, for a = 0..15 */594595/**************************************************************************596* Initialization and cleanup of ratpoints_args structure *597**************************************************************************/598599static ratpoints_sieve_entry*600alloc_sieve(long nbprime, long maxprime)601{602long i;603ratpoints_sieve_entry * s = (ratpoints_sieve_entry*)604stack_malloc(nbprime*sizeof(ratpoints_sieve_entry));605for (i=0; i<nbprime; i++)606s[i].sieve = (ratpoints_bit_array**) new_chunk(maxprime);607return s;608}609610/* NOTE: args->degree must be set */611static void612find_points_init(ratpoints_args *args, long bit_primes)613{614long need = 0;615long n, nbprime,maxprime;616args->listprime = primes_interval_zv(3, 1<<bit_primes);617nbprime = lg(args->listprime)-1;618maxprime = args->listprime[nbprime];619620/* allocate space for se_buffer */621args->se_buffer = alloc_sieve(nbprime, maxprime);622args->se_next = args->se_buffer;623for (n = 1; n <= nbprime; n++)624{625ulong p = args->listprime[n];626need += p*p;627}628args->ba_buffer = (ratpoints_bit_array*)629stack_malloc_align(need*sizeof(ratpoints_bit_array),RBA_ALIGN);630args->ba_next = args->ba_buffer;631632/* allocate space for int_buffer */633args->int_buffer = (int *) stack_malloc(nbprime*(maxprime+1)*sizeof(int));634args->int_next = args->int_buffer;635636args->forb_ba = (forbidden_entry*)637stack_malloc((nbprime + 1)*sizeof(forbidden_entry));638args->forbidden = new_chunk(nbprime + 1);639gen_sieve(args);640return;641}642643/* f = leading coeff; b = b1*b2, b1 maximal with (b1, 2*f) = 1;644* return Jacobi symbol (f, b1) */645INLINE int646rpjacobi(long b, GEN lcf)647{648ulong f;649b >>= vals(b);650f = umodiu(lcf, b);651return krouu(f, u_ppo(b,f));652}653654/************************************************************************655* Set up information on possible denominators *656* when polynomial is of odd degree with leading coefficient != +-1 *657************************************************************************/658659static void660setup_us1(ratpoints_args *args, GEN w0)661{662GEN F = Z_issmooth_fact(w0, 1000), P, E, S, D;663long i, l;664665if (!F) return;666P = gel(F,1); l = lg(P);667E = gel(F,2);668D = cgetg(1+(1<<(l-1)), t_VECSMALL);669/* factorization is complete, set up array of squarefree divisors */670D[1] = 1;671for (i = 1; i < l; i++)672{ /* multiply all divisors known so far by next prime */673long k, n = 1<<(i-1);674for (k=0; k<n; k++) uel(D,1+n+k) = uel(D,1+k) * P[i];675}676S = cgetg(l, t_VECSMALL);677/* set slopes in den_info */678for (i = 1; i < l; i++)679{ /* compute min{n : (d-k)*n > v_p(f_d) - v_p(f_k), k = 0,...,d-1} */680GEN c = args->cof;681long p = P[i], v = E[i];682long k, n = 1, d = degpol(c);683684for (k = d - 1; k >= 0; k--)685{686long t = 1 + v - Z_lval(gel(c,k+2), p);687long m = CEIL(t, d - k);688689if (m > n) n = m;690}691S[i] = n;692}693args->divisors = D;694args->flags |= RATPOINTS_USE_SQUARES1;695args->den_info = mkvec3(P, E, S);696}697698/************************************************************************699* Consider 2-adic information *700************************************************************************/701702static bit_selection703get_2adic_info(ratpoints_args *args, ulong *den_bits,704ratpoints_bit_array *num_bits)705{706GEN c = args->cof;707long degree = degpol(c);708int is_f_square16[24];709long *cmp = new_chunk(degree+1);710long npe = 0, npo = 0;711bit_selection result;712long n, a, b;713714/* compute coefficients mod 16 */715for (n = 0; n <= degree; n++) cmp[n] = Mod16(gel(c,n+2));716for (a = 0 ; a < 16; a++)717{718ulong s = cmp[degree];719long n;720for (n = degree - 1 ; n >= 0 ; n--) s = s*a + cmp[n];721s &= 0xf;722if ((is_f_square16[a] = squares16[s])) { if (odd(a)) npo++; else npe++; }723}724725/* even denominators:726is_f_square16[16+k] says if f((2k+1)/2) is a square, k = 0..3727is_f_square16[20+k] says if f((2k+1)/4) is a square, k = 0,1728is_f_square16[22] says if f(odd/8) is a square729is_f_square16[23] says if f(odd/2^n), n >= 4, can be a square */730{731long np1 = 0, np2 = 0, np3 = 0, np4 = 0;732733if (odd(degree))734{735long a, cf = 4*cmp[degree-1];736737if (degree >= 2) cf += 8*cmp[degree-2];738for (a = 0; a < 4; a++)739{ /* Compute 2 c[d] k^d + 4 c[d-1] k^(d-1) + 8 c[d-2] k^(d-2), k = 2a+1.740Note that k^d = k mod 8, k^(d-1) = 1 mod 8. */741long k = 2*a+1;742long s = (2*k*cmp[degree] + cf) & 0xf;743if ((is_f_square16[16+a] = squares16[s])) np1++;744}745if ((is_f_square16[20] = squares16[(4*cmp[degree]) & 0xf])) np2++;746if ((is_f_square16[21] = squares16[(12*cmp[degree]) & 0xf])) np2++;747if ((is_f_square16[22] = squares16[(8*cmp[degree]) & 0xf])) np3++;748is_f_square16[23] = 1; np4++;749}750else751{752long a, cf = (degree >= 2) ? 4*cmp[degree-2] : 0;753754if (degree >= 3) cf += 8*cmp[degree-3];755for (a = 0; a < 4; a++)756{ /* compute c[d] k^d + 2 c[d-1] k^(d-1) + ... + 8 c[d-3] k^(d-3),757k = 2a+1. Note that k^d = k^2 mod 16, k^(d-1) = k mod 8. */758long k = 2*a+1;759long s = ((cmp[degree]*k + 2*cmp[degree-1])*k + cf) & 0xf;760if ((is_f_square16[16+a] = squares16[s])) np1++;761}762if ((is_f_square16[20] = squares16[(cmp[degree]+4*cmp[degree-1]) & 0xf]))763np2++;764if ((is_f_square16[21] = squares16[(cmp[degree]+12*cmp[degree-1]) & 0xf]))765np2++;766if ((is_f_square16[22] = squares16[(cmp[degree]+8*cmp[degree-1]) & 0xf]))767np3++;768if ((is_f_square16[23] = squares16[cmp[degree]])) np4++;769}770771/* set den_bits */772{ ulong db = 0;773long i;774775if (npe + npo > 0) db |= 0xaaaaUL; /* odd denominators */776if (np1 > 0) db |= 0x4444UL; /* v_2(den) = 1 */777if (np2 > 0) db |= 0x1010UL; /* v_2(den) = 2 */778if (np3 > 0) db |= 0x0100UL; /* v_2(den) = 3 */779if (np4 > 0) db |= 0x0001UL; /* v_2(den) >= 4 */780if (db == 0) { *den_bits = 0UL; return num_none; }781782for (i = 16; i < BITS_IN_LONG; i <<= 1) db |= db << i;783*den_bits = db;784}785result = (npe == 0) ? (npo == 0) ? num_none : num_odd786: (npo == 0) ? num_even : num_all;787}788789/* set up num_bits[16] */790791/* odd denominators */792switch(result)793{794case num_all:795for (b = 1; b < 16; b += 2)796{797ulong work = 0, bit = 1;798long i, invb = b; /* inverse of b mod 16 */799if (b & 2) invb ^= 8;800if (b & 4) invb ^= 8;801for (i = 0; i < 16; i++)802{803if (is_f_square16[(invb*i) & 0xf]) work |= bit;804bit <<= 1;805}806/* now repeat the 16 bits */807for (i = 16; i < BITS_IN_LONG; i <<= 1) work |= work << i;808num_bits[b] = RBA(work);809}810break;811812case num_odd:813for (b = 1; b < 16; b += 2)814{815ulong work = 0, bit = 1;816long i, invb = b; /* inverse of b mod 16 */817if (b & 2) invb ^= 8;818if (b & 4) invb ^= 8;819for (i = 1; i < 16; i += 2)820{821if (is_f_square16[(invb*i) & 0xf]) work |= bit;822bit <<= 1;823}824/* now repeat the 8 bits */825for (i = 8; i < BITS_IN_LONG; i <<= 1) { work |= work << i; }826num_bits[b] = RBA(work);827}828break;829830case num_even:831for (b = 1; b < 16; b += 2)832{833ulong work = 0, bit = 1;834long i, invb = b; /* inverse of b mod 16 */835if (b & 2) invb ^= 8;836if (b & 4) invb ^= 8;837for (i = 0; i < 16; i += 2)838{839if (is_f_square16[(invb*i) & 0xf]) work |= bit;840bit <<= 1;841}842/* now repeat the 8 bits */843for (i = 8; i < BITS_IN_LONG; i <<= 1) work |= work << i;844num_bits[b] = RBA(work);845}846break;847848case num_none:849for (b = 1; b < 16; b += 2) num_bits[b] = RBA(0UL);850break;851}852853/* v_2(den) = 1 : only odd numerators */854for (b = 1; b < 8; b += 2)855{856ulong work = 0, bit = 1;857long i;858for (i = 1; i < 16; i += 2)859{860if (is_f_square16[16 + (((b*i)>>1) & 0x3)]) work |= bit;861bit <<= 1;862}863/* now repeat the 8 bits */864for (i = 8; i < BITS_IN_LONG; i <<= 1) work |= work << i;865num_bits[2*b] = RBA(work);866}867868/* v_2(den) = 2 : only odd numerators */869for (b = 1; b < 4; b += 2)870{871ulong work = 0, bit = 1;872long i;873for (i = 1; i < 8; i += 2)874{875if (is_f_square16[20 + (((b*i)>>1) & 0x1)]) work |= bit;876bit <<= 1;877}878/* now repeat the 4 bits */879for (i = 4; i < BITS_IN_LONG; i <<= 1) work |= work << i;880num_bits[4*b] = RBA(work);881}882883/* v_2(den) = 3, >= 4 : only odd numerators */884num_bits[8] = (is_f_square16[22]) ? RBA(~(0UL)) : RBA(0UL);885num_bits[0] = (is_f_square16[23]) ? RBA(~(0UL)) : RBA(0UL);886887return result;888}889890/**************************************************************************891* This is a comparison function needed for sorting in order to determine *892* the `best' primes for sieving. *893**************************************************************************/894895static int896compare_entries(const void *a, const void *b)897{898double diff = ((entry *)a)->r - ((entry *)b)->r;899return (diff > 0) ? 1 : (diff < 0) ? -1 : 0;900}901902/************************************************************************903* Collect the sieving information *904************************************************************************/905906static long907sieving_info(ratpoints_args *args,908ratpoints_sieve_entry **sieve_list)909{910GEN c = args->cof;911GEN inverses = args->inverses, squares;912GEN offsets = args->offsets;913ulong ** sieves0 = args->sieves0;914long degree = degpol(c);915long fba = 0, fdc = 0;916long pn, pnp = 0;917long n;918long nbprime = lg(args->listprime)-1;919entry *prec = (entry*) stack_malloc(nbprime*sizeof(entry));920/* This array is used for sorting in order to921determine the `best' sieving primes. */922923forbidden_entry *forb_ba = args->forb_ba;924long *forbidden = args->forbidden;925ulong bound = (1UL)<<(BITS_IN_LONG - args->bit_primes);926pari_sp av = avma;927squares = gen_squares(args->listprime);928929/* initialize sieve in se_buffer */930for (pn = 1; pn <= args->num_primes; pn++)931{932long coeffs_mod_p[degree+1]; /* The coefficients of f reduced modulo p */933ulong a, p = args->listprime[pn], np;934long n;935int *is_f_square = args->int_next;936937args->int_next += p + 1; /* need space for (p+1) int's */938939/* compute coefficients mod p */940for (n = 0; n <= degree; n++) coeffs_mod_p[n] = umodiu(pel(c,n), p);941942np = umael(squares,pn,coeffs_mod_p[0]+1);943is_f_square[0] = np;944for (a = 1 ; a < p; a++)945{946ulong s = coeffs_mod_p[degree];947if ((degree+1)*args->bit_primes <= BITS_IN_LONG)948{949for (n = degree - 1 ; n >= 0 ; n--) s = s*a + coeffs_mod_p[n];950/* here, s < p^(degree+1) <= max. long */951s %= p;952}953else954{955for (n = degree - 1 ; n >= 0 ; n--)956{957s = s*a + coeffs_mod_p[n];958if (s+1 >= bound) s %= p;959}960s %= p;961}962if ((is_f_square[a] = mael(squares,pn,s+1))) np++;963}964is_f_square[p] = odd(degree) || mael(squares,pn,coeffs_mod_p[degree]+1);965966/* check if there are no solutions mod p */967if (np == 0 && !is_f_square[p]) return gc_long(av,p);968969/* Fill arrays with info for p */970if (np < p)971{ /* only when there is some information */972ulong i;973ratpoints_sieve_entry *se = args->se_next;974double r = is_f_square[p] ? ((double)(np*(p-1) + p))/((double)(p*p))975: (double)np/(double)p;976prec[pnp].r = r;977args->se_next ++;978se->p = p;979se->is_f_square = is_f_square;980se->inverses = gel(inverses,pn);981se->offset = offsets[pn];982se->sieve[0] = (ratpoints_bit_array *)sieves0[pn];983for (i = 1; i < p; i++) se->sieve[i] = NULL;984prec[pnp].ssp = se;985pnp++;986}987988if ((args->flags & RATPOINTS_CHECK_DENOM)989&& fba + fdc < args->max_forbidden990&& !is_f_square[p])991{ /* record forbidden divisors of the denominator */992if (coeffs_mod_p[degree] == 0)993{ /* leading coeff. divisible by p */994GEN r;995long v = Z_lvalrem(pel(c,degree), p, &r);996997if (odd(v) || !mael(squares,pn, umodiu(r,p)+1))998{ /* Can only get something when valuation is odd999or when valuation is even and lcf is not a p-adic square.1000Compute smallest n such that if v(den) >= n, the leading1001term determines the valuation. Then we must have v(den) < n. */1002long k, n = 1;1003for (k = degree-1; k >= 0; k--)1004{1005if (coeffs_mod_p[k] == 0)1006{1007long t = 1 + v - Z_lval(pel(c,k), p);1008long m = CEIL(t, (degree-k));1009if (m > n) n = m;1010}1011}1012if (n == 1)1013{1014forb_ba[fba].p = p;1015forb_ba[fba].start = sieves0[pn];1016forb_ba[fba].end = sieves0[pn]+p;1017forb_ba[fba].curr = forb_ba[fba].start;1018fba++;1019}1020else1021{1022forbidden[fdc] = upowuu(p, n);1023fdc++;1024}1025}1026}1027else /* leading coefficient is a nonsquare mod p */1028{ /* denominator divisible by p is excluded */1029forb_ba[fba].p = p;1030forb_ba[fba].start = sieves0[pn];1031forb_ba[fba].end = sieves0[pn]+p;1032forb_ba[fba].curr = forb_ba[fba].start;1033fba++;1034}1035}1036} /* end for pn */10371038/* update sp2 and sp1 if necessary */1039if (args->sp2 > pnp) args->sp2 = pnp;1040if (args->sp1 > args->sp2) args->sp1 = args->sp2;10411042/* sort the array to get at the best primes */1043qsort(prec, pnp, sizeof(entry), compare_entries);10441045/* put the sorted entries into sieve_list */1046for (n = 0; n < args->sp2; n++) sieve_list[n] = prec[n].ssp;10471048/* terminate array of forbidden divisors */1049if (args->flags & RATPOINTS_CHECK_DENOM)1050{1051long n;10521053for (n = args->num_primes+1;1054fba + fdc < args->max_forbidden && n <= nbprime; n++)1055{1056ulong p = args->listprime[n];10571058if (p*p > (ulong) args->b_high) break;1059if (kroiu(pel(c,degree), p) == -1)1060{1061forb_ba[fba].p = p;1062forb_ba[fba].start = sieves0[n];1063forb_ba[fba].end = sieves0[n]+p;1064forb_ba[fba].curr = forb_ba[fba].start;1065fba++;1066}1067}1068forb_ba[fba].p = 0; /* terminating zero */1069forbidden[fdc] = 0; /* terminating zero */1070args->max_forbidden = fba + fdc; /* note actual number */1071}10721073if (fba + fdc == 0) args->flags &= ~RATPOINTS_CHECK_DENOM;1074return gc_long(av,0);1075}10761077/**************************************************************************1078* The sieving procedure itself *1079**************************************************************************/1080static void1081sift(long b, ratpoints_bit_array *survivors, ratpoints_args *args,1082bit_selection which_bits, ratpoints_bit_array bits16,1083ratpoints_sieve_entry **sieve_list, long *bp_list, int *quit,1084int process(long, long, GEN, void*, int*), void *info)1085{1086pari_sp av = avma;1087sieve_spec ssp[args->sp2];1088int do_setup = 1;1089long k, height = args->height, nb;10901091if (odd(b) == 0) which_bits = num_odd; /* even denominator */10921093/* Note that b is new */1094args->bc = NULL;1095nb = 0;10961097for (k = 0; k < args->num_inter; k++)1098{1099ratpoints_interval inter = args->domain[k];1100long low, high;11011102/* Determine relevant interval [low, high] of numerators. */1103if (b*inter.low <= -height)1104low = -height;1105else1106{1107if (b*inter.low > height) break;1108low = ceil(b*inter.low);1109}1110if (b*inter.up >= height)1111high = height;1112else1113{1114if (b*inter.up < -height) continue;1115high = floor(b*inter.up);1116}11171118if (do_setup)1119{ /* set up the sieve information */1120long n;11211122do_setup = 0; /* only do it once for every b */1123for (n = 0; n < args->sp2; n++)1124{1125ratpoints_sieve_entry *se = sieve_list[n];1126long p = se->p;1127long bp = bp_list[n];1128ratpoints_bit_array *sptr;11291130if (which_bits != num_all) /* divide by 2 mod p */1131bp = odd(bp) ? (bp+p) >> 1 : bp >> 1;1132sptr = se->sieve[bp];11331134ssp[n].p = p;1135ssp[n].offset = (which_bits == num_odd) ? se->offset : 0;11361137/* copy if already initialized, else initialize */1138ssp[n].ptr = sptr ? sptr : (p<BITS_IN_LONG?sieve_init1(p, se, bp, args)1139:sieve_init2(p, se, bp, args));1140}1141}11421143switch(which_bits)1144{1145case num_all: break;1146case num_none: break;1147case num_odd: low >>= 1; high--; high >>= 1; break;1148case num_even: low++; low >>= 1; high >>= 1; break;1149}11501151/* now turn the bit interval into [low, high[ */1152high++;11531154if (low < high)1155{1156long w_low, w_high, w_low0, w_high0, range = args->array_size;11571158/* Now the range of longwords (= bit_arrays) */1159w_low = low >> RBA_SHIFT;1160w_high = (high + (long)(RBA_LENGTH-1)) >> RBA_SHIFT;1161w_low0 = w_low;1162w_high0 = w_low0 + range;1163for ( ; w_low0 < w_high; w_low0 = w_high0, w_high0 += range)1164{1165long i;1166if (w_high0 > w_high) { w_high0 = w_high; range = w_high0 - w_low0; }1167/* initialise the bits */1168for (i = range; i; i--) survivors[i-1] = bits16;1169/* boundary words */1170if (w_low0 == w_low)1171{1172long sh = low - RBA_LENGTH * w_low;1173ulong *survl = (ulong *)survivors;11741175#ifdef HAS_SSE21176if (sh >= BITS_IN_LONG)1177{1178survl[0] = 0UL;1179survl[1] &= (~0UL)<<(sh - BITS_IN_LONG);1180}1181else1182survl[0] &= ~(0UL)<<sh;1183#else1184survl[0] &= ~(0UL)<<sh;1185#endif1186}1187if (w_high0 == w_high)1188{1189long sh = RBA_LENGTH * w_high - high;1190ulong *survl = (ulong *)&survivors[range-1];11911192#ifdef HAS_SSE21193if (sh >= BITS_IN_LONG)1194{1195survl[0] &= ~(0UL)>>(sh - BITS_IN_LONG);1196survl[1] = 0UL;1197}1198else1199survl[1] &= ~(0UL)>>sh;1200#else1201survl[0] &= ~(0UL)>>sh;1202#endif1203}1204nb += _ratpoints_sift0(b, w_low0, w_high0, args, which_bits,1205survivors, &ssp[0], quit, process, info);1206if (*quit) return;1207}1208}1209}1210if (nb==0) set_avma(av);1211}12121213/**************************************************************************1214* Find points by looping over the denominators and sieving numerators *1215**************************************************************************/1216static void1217find_points_work(ratpoints_args *args,1218int process(long, long, GEN, void*, int*), void *info)1219{1220int quit = 0;1221GEN c = args->cof;1222long degree = degpol(c);1223long nbprime = lg(args->listprime)-1;1224long height = args->height;12251226int point_at_infty = 0; /* indicates if there are points at infinity */1227int lcfsq = Z_issquare(pel(c,degree));12281229forbidden_entry *forb_ba = args->forb_ba;1230long *forbidden = args->forbidden;1231/* The forbidden divisors, a zero-terminated array.1232Used when degree is even and leading coefficient is not a square */12331234/* These are used when degree is odd and leading coeff. is not +-1 */12351236ratpoints_sieve_entry **sieve_list = (ratpoints_sieve_entry**)1237stack_malloc(nbprime*sizeof(ratpoints_sieve_entry*));1238bit_selection which_bits = num_all;1239ulong den_bits;1240ratpoints_bit_array num_bits[16];12411242args->flags &= RATPOINTS_FLAGS_INPUT_MASK;1243args->flags |= RATPOINTS_CHECK_DENOM;12441245/* initialize memory management */1246args->se_next = args->se_buffer;1247args->ba_next = args->ba_buffer;1248args->int_next = args->int_buffer;12491250/* Some sanity checks */1251args->num_inter = 0;12521253if (args->num_primes > nbprime) args->num_primes = nbprime;1254if (args->sp2 > args->num_primes) args->sp2 = args->num_primes;1255if (args->sp1 > args->sp2) args->sp1 = args->sp2;12561257if (args->b_low < 1) args->b_low = 1;1258if (args->b_high < 1) args->b_high = height;1259if (args->b_high > height) args->b_high = height;1260if (args->max_forbidden < 0)1261args->max_forbidden = RATPOINTS_DEFAULT_MAX_FORBIDDEN;1262if (args->max_forbidden > nbprime)1263args->max_forbidden = nbprime;1264if (args->array_size <= 0) args->array_size = RATPOINTS_ARRAY_SIZE;1265{1266long s = 2*CEIL(height, BITS_IN_LONG);1267if (args->array_size > s) args->array_size = s;1268}1269/* Don't reverse if intervals are specified or limits for the denominator1270are given */1271if (args->num_inter > 0 || args->b_low > 1 || args->b_high < height)1272args->flags |= RATPOINTS_NO_REVERSE;12731274/* Check if reversal of polynomial might be better:1275* case 1: degree is even, but trailing coefficient is zero1276* case 2: degree is even, leading coefficient is a square, but1277* trailing coefficient is not1278* case 3: degree is odd, |leading coefficient| > 1,1279* trailing coefficient is zero, |coeff. of x| = 1 */1280if (!(args->flags & RATPOINTS_NO_REVERSE))1281{1282if (!odd(degree))1283{1284if (signe(pel(c,0)) == 0)1285{ /* case 1 */1286long n;1287args->flags |= RATPOINTS_REVERSED;1288for (n = 0; n < degree>>1; n++) swap(pel(c,n), pel(c,degree-n));1289degree--;1290setlg(c,degree+3);1291}1292else if (lcfsq && !Z_issquare(pel(c,0)))1293{ /* case 2 */1294long n;1295args->flags |= RATPOINTS_REVERSED;1296for (n = 0; n < degree>>1; n++) swap(pel(c,n), pel(c,degree-n));1297lcfsq = 0;1298}1299}1300else1301{ /* odd degree, case 3*/1302if (!is_pm1(pel(c,degree)) && !signe(pel(c,0)) && is_pm1(pel(c,1)))1303{1304long n;1305args->flags |= RATPOINTS_REVERSED;1306for (n = 1; n < degree>>1; n++) swap(pel(c,n),pel(c,degree+1-n));1307}1308}1309}13101311/* Deal with the intervals */1312if (args->num_inter == 0)1313{ /* default interval (effectively ]-oo,oo[) if none is given */1314args->domain = (ratpoints_interval*) stack_malloc(2*degree*sizeof(ratpoints_interval));1315args->domain[0].low = -height; args->domain[0].up = height;1316args->num_inter = 1;1317}13181319ratpoints_compute_sturm(args);13201321/* Point(s) at infinity? */1322if (odd(degree) || lcfsq)1323{1324args->flags &= ~RATPOINTS_CHECK_DENOM;1325point_at_infty = 1;1326}13271328/* Can use only squares as denoms if degree is odd and poly is +-monic */1329if (odd(degree))1330{1331GEN w1 = pel(c,degree);1332if (is_pm1(w1))1333args->flags |= RATPOINTS_USE_SQUARES;1334else /* set up information on divisors of leading coefficient */1335setup_us1(args, absi_shallow(w1));1336}13371338/* deal with f mod powers of 2 */1339which_bits = get_2adic_info(args, &den_bits, &num_bits[0]);1340/* which_bits says whether to consider even and/or odd numerators1341* when the denominator is odd.1342*1343* Bit k in den_bits is 0 if b congruent to k mod BITS_IN_LONG need1344* not be considered as a denominator.1345*1346* Bit k in num_bits[b] is 0 is numerators congruent to1347* k (which_bits = den_all)1348* 2k (which_bits = den_even)1349* 2k+1 (which_bits = den_odd)1350* need not be considered for denominators congruent to b mod 16. */13511352/* set up the sieve data structure */1353if (sieving_info(args, sieve_list)) return;13541355/* deal with point(s) at infinity */1356if (point_at_infty)1357{1358long a = 1, b = 0;13591360if (args->flags & RATPOINTS_REVERSED) { a = 0; b = 1; }1361if (odd(degree))1362(void)process(a, b, gen_0, info, &quit);1363else1364{1365GEN w0 = sqrti(pel(c,degree));1366(void)process(a, b, w0, info, &quit);1367(void)process(a, b, negi(w0), info, &quit);1368}1369if (quit) return;1370}1371/* now do the sieving */1372{1373ratpoints_bit_array *survivors = (ratpoints_bit_array *)1374stack_malloc_align((args->array_size)*sizeof(ratpoints_bit_array), RBA_ALIGN);1375if (args->flags & (RATPOINTS_USE_SQUARES | RATPOINTS_USE_SQUARES1))1376{1377if (args->flags & RATPOINTS_USE_SQUARES)1378/* need only take squares as denoms */1379{1380long b, bb;1381long bp_list[args->sp2];1382long last_b = args->b_low;1383long n;1384for (n = 0; n < args->sp2; n++)1385bp_list[n] = mod(args->b_low, sieve_list[n]->p);13861387for (b = 1; bb = b*b, bb <= args->b_high; b++)1388if (bb >= args->b_low)1389{1390ratpoints_bit_array bits = num_bits[bb & 0xf];1391if (TEST(bits))1392{1393long n;1394long d = bb - last_b;13951396/* fill bp_list */1397for (n = 0; n < args->sp2; n++)1398bp_list[n] = mod(bp_list[n] + d, sieve_list[n]->p);1399last_b = bb;14001401sift(bb, survivors, args, which_bits, bits,1402sieve_list, &bp_list[0], &quit, process, info);1403if (quit) break;1404}1405}1406}1407else /* args->flags & RATPOINTS_USE_SQUARES1 */1408{1409GEN den_info = args->den_info;1410GEN divisors = args->divisors;1411long ld = lg(divisors);1412long k;1413long b, bb;1414long bp_list[args->sp2];14151416for (k = 1; k < ld; k++)1417{1418long d = divisors[k];1419long last_b = d;1420long n;1421if (d > args->b_high) continue;1422for (n = 0; n < args->sp2; n++)1423bp_list[n] = mod(d, sieve_list[n]->p);14241425for (b = 1; bb = d*b*b, bb <= args->b_high; b++)1426{1427if (bb >= args->b_low)1428{1429int flag = 1;1430ratpoints_bit_array bits = num_bits[bb & 0xf];14311432if (EXT0(bits))1433{1434long i, n, l = lg(gel(den_info,1));1435long d = bb - last_b;14361437/* fill bp_list */1438for (n = 0; n < args->sp2; n++)1439bp_list[n] = mod(bp_list[n] + d, sieve_list[n]->p);1440last_b = bb;14411442for(i = 1; i < l; i++)1443{1444long v = z_lval(bb, mael(den_info,1,i));1445if((v >= mael(den_info,3,i))1446&& odd(v + (mael(den_info,2,i)))) { flag = 0; break; }1447}1448if (flag)1449{1450sift(bb, survivors, args, which_bits, bits,1451sieve_list, &bp_list[0], &quit, process, info);1452if (quit) break;1453}1454}1455}1456}1457if (quit) break;1458}1459}1460}1461else1462{1463if (args->flags & RATPOINTS_CHECK_DENOM)1464{1465long *forb;1466long b;1467long bp_list[args->sp2];1468long last_b = args->b_low;1469ulong b_bits;1470long n;1471for (n = 0; n < args->sp2; n++)1472bp_list[n] = mod(args->b_low, sieve_list[n]->p);1473{1474forbidden_entry *fba = &forb_ba[0];1475long b_low = args->b_low;1476long w_low = (b_low-1) >> TWOPOTBITS_IN_LONG;14771478b_bits = den_bits;1479while (fba->p)1480{1481fba->curr = fba->start + mod(w_low, fba->p);1482b_bits &= *(fba->curr);1483fba++;1484}1485b_bits >>= (b_low-1) & LONG_MASK;1486}14871488for (b = args->b_low; b <= args->b_high; b++)1489{1490ratpoints_bit_array bits = num_bits[b & 0xf];14911492if ((b & LONG_MASK) == 0)1493{ /* next b_bits */1494forbidden_entry *fba = &forb_ba[0];14951496b_bits = den_bits;1497while (fba->p)1498{1499fba->curr++;1500if (fba->curr == fba->end) fba->curr = fba->start;1501b_bits &= *(fba->curr);1502fba++;1503}1504}1505else1506b_bits >>= 1;15071508if (odd(b_bits) && EXT0(bits))1509{ /* check if denominator is excluded */1510for (forb = &forbidden[0] ; *forb && (b % (*forb)); forb++)1511continue;1512if (*forb == 0 && rpjacobi(b, pel(c,degree)) == 1)1513{1514long n, d = b - last_b;15151516/* fill bp_list */1517for (n = 0; n < args->sp2; n++)1518{1519long bp = bp_list[n] + d;1520long p = sieve_list[n]->p;15211522while (bp >= p) bp -= p;1523bp_list[n] = bp;1524}1525last_b = b;15261527sift(b, survivors, args, which_bits, bits,1528sieve_list, &bp_list[0], &quit, process, info);1529if (quit) break;1530}1531}1532}1533} /* if (args->flags & RATPOINTS_CHECK_DENOM) */1534else1535{1536long b, n;1537long bp_list[args->sp2];1538long last_b = args->b_low;1539for (n = 0; n < args->sp2; n++)1540bp_list[n] = mod(args->b_low, sieve_list[n]->p);1541for (b = args->b_low; b <= args->b_high; b++)1542{1543ratpoints_bit_array bits = num_bits[b & 0xf];1544if (EXT0(bits))1545{1546long n;1547long d = b - last_b;15481549/* fill bp_list */1550for (n = 0; n < args->sp2; n++)1551{1552long bp = bp_list[n] + d;1553long p = sieve_list[n]->p;15541555while (bp >= p) bp -= p;1556bp_list[n] = bp;1557}1558last_b = b;15591560sift(b, survivors, args, which_bits, bits,1561sieve_list, &bp_list[0], &quit, process, info);1562if (quit) break;1563}1564}1565}1566}1567}1568}15691570static GEN1571vec_append_grow(GEN z, long i, GEN x)1572{1573long n = lg(z)-1;1574if (i > n)1575{1576n <<= 1;1577z = vec_lengthen(z,n);1578}1579gel(z,i) = x;1580return z;1581}15821583struct points1584{1585GEN z;1586long i, f;1587};15881589static int1590process(long a, long b, GEN y, void *info0, int *quit)1591{1592struct points *p = (struct points *) info0;1593if (b==0 && (p->f&2L)) return 0;1594*quit = (p->f&1);1595p->z = vec_append_grow(p->z, ++p->i, mkvec3(stoi(a),y,stoi(b)));1596return 1;1597}15981599static int1600args_h(ratpoints_args *args, GEN D)1601{1602long H, h, l = 1;1603GEN L;1604switch(typ(D))1605{1606case t_INT: if (signe(D) <= 0) return 0;1607H = h = itos(D); break;1608case t_VEC: if (lg(D) != 3) return 0;1609H = gtos(gel(D,1));1610L = gel(D,2);1611if (typ(L)==t_INT) { h = itos(L); break; }1612if (typ(L)==t_VEC && lg(L)==3)1613{1614l = gtos(gel(L,1));1615h = gtos(gel(L,2)); break;1616}1617default: return 0;1618}1619args->height = H;1620args->b_low = l;1621args->b_high = h; return 1;1622}16231624static GEN1625ZX_hyperellratpoints(GEN P, GEN h, long flag)1626{1627pari_sp av = avma;1628ratpoints_args args;1629struct points data;1630ulong flags = 0;16311632if (!ZX_is_squarefree(P))1633pari_err_DOMAIN("hyperellratpoints","issquarefree(pol)","=",gen_0, P);1634if (!args_h(&args, h))1635{1636pari_err_TYPE("hyperellratpoints", h);1637return NULL;/*LCOV_EXCL_LINE*/1638}1639find_points_init(&args, RATPOINTS_DEFAULT_BIT_PRIMES);16401641args.cof = shallowcopy(P);1642args.num_inter = 0;1643args.sp1 = RATPOINTS_DEFAULT_SP1;1644args.sp2 = RATPOINTS_DEFAULT_SP2;1645args.array_size = RATPOINTS_ARRAY_SIZE;1646args.num_primes = RATPOINTS_DEFAULT_NUM_PRIMES;1647args.bit_primes = RATPOINTS_DEFAULT_BIT_PRIMES;1648args.max_forbidden = RATPOINTS_DEFAULT_MAX_FORBIDDEN;1649args.flags = flags;1650data.z = cgetg(17,t_VEC);1651data.i = 0;1652data.f = flag;1653find_points_work(&args, process, (void *)&data);16541655setlg(data.z, data.i+1);1656return gerepilecopy(av, data.z);1657}16581659/* The ordinates of the points returned need to be divided by den1660* by the caller to get the actual solutions */1661static GEN1662QX_hyperellratpoints(GEN P, GEN h, long flag, GEN *den)1663{1664GEN Q = Q_remove_denom(P, den);1665if (*den) Q = ZX_Z_mul(Q, *den);1666return ZX_hyperellratpoints(Q, h, flag);1667}16681669static GEN1670ZX_homogenous_evalpow(GEN Q, GEN A, GEN B)1671{1672pari_sp av = avma;1673long i, d = degpol(Q);1674GEN s = gel(Q, d+2);1675for (i = d-1; i >= 0; i--)1676s = addii(mulii(s, A), mulii(gel(B,d+1-i), gel(Q,i+2)));1677return gerepileuptoint(av, s);1678}16791680static GEN1681to_RgX(GEN a, long v) { return typ(a)==t_POL? a: scalarpol(a,v); }16821683static int1684hyperell_check(GEN PQ, GEN *P, GEN *Q)1685{1686*P = *Q = NULL;1687if (typ(PQ) == t_POL)1688{1689if (!RgX_is_QX(PQ)) return 0;1690*P = PQ;1691}1692else1693{1694long v = gvar(PQ);1695if (v == NO_VARIABLE || typ(PQ) != t_VEC || lg(PQ) != 3) return 0;1696*P = to_RgX(gel(PQ,1), v); if (!RgX_is_QX(*P)) return 0;1697*Q = to_RgX(gel(PQ,2), v); if (!RgX_is_QX(*Q)) return 0;1698if (!signe(*Q)) *Q = NULL;1699}1700return 1;1701}17021703GEN1704hyperellratpoints(GEN PQ, GEN h, long flag)1705{1706pari_sp av = avma;1707GEN P, Q, H, L, den;1708long i, l, dy, dQ;17091710if (flag<0 || flag>1) pari_err_FLAG("ellratpoints");1711if (!hyperell_check(PQ, &P, &Q)) pari_err_TYPE("hyperellratpoints",PQ);1712if (!Q)1713{1714L = QX_hyperellratpoints(P, h, flag|2L, &den);1715dy = (degpol(P)+1)>>1;1716l = lg(L);1717for (i = 1; i < l; i++)1718{1719GEN Li = gel(L,i), x = gel(Li,1), y = gel(Li,2), z = gel(Li,3);1720GEN zdy = powiu(z, dy);1721if (den) zdy = mulii(zdy, den);1722gel(L,i) = mkvec2(gdiv(x,z), gdiv(y, zdy));1723}1724return gerepilecopy(av, L);1725}1726H = RgX_add(RgX_muls(P,4), RgX_sqr(Q));1727dy = (degpol(H)+1)>>1; dQ = degpol(Q);1728L = QX_hyperellratpoints(H, h, flag|2L, &den);1729l = lg(L);1730for (i = 1; i < l; i++)1731{1732GEN Li = gel(L,i), x = gel(Li,1), y = gel(Li,2), z = gel(Li,3);1733GEN B = gpowers(z, dQ);1734GEN Qx = gdiv(ZX_homogenous_evalpow(Q, x, B), gel(B, dQ+1));1735GEN zdy = powiu(z, dy);1736if (den) zdy = mulii(zdy, den);1737gel(L,i) = mkvec2(gdiv(x,z), gmul2n(gsub(gdiv(y,zdy),Qx),-1));1738}1739return gerepilecopy(av, L);1740}17411742GEN1743ellratpoints(GEN E, GEN h, long flag)1744{1745pari_sp av = avma;1746GEN L, a1, a3, den;1747long i, l;1748checkell_Q(E);1749if (flag<0 || flag>1) pari_err_FLAG("ellratpoints");1750if (!RgV_is_QV(vecslice(E,1,5))) pari_err_TYPE("ellratpoints",E);1751a1 = ell_get_a1(E);1752a3 = ell_get_a3(E);1753L = QX_hyperellratpoints(ec_bmodel(E), h, flag|2L, &den);1754l = lg(L);1755for (i = 1; i < l; i++)1756{1757GEN P, Li = gel(L,i), x = gel(Li,1), y = gel(Li,2), z = gel(Li,3);1758if (!signe(z))1759P = ellinf();1760else1761{1762GEN z2 = sqri(z);1763if (den) y = gdiv(y, den);1764y = gsub(y, gadd(gmul(a1, mulii(x,z)), gmul(a3,z2)));1765P = mkvec2(gdiv(x,z), gdiv(y,shifti(z2,1)));1766}1767gel(L,i) = P;1768}1769return gerepilecopy(av, L);1770}177117721773