1 // mwprocs.cc: implementation of class mw for Mordell-Weil basis
2 //////////////////////////////////////////////////////////////////////////
3 //
4 // Copyright 1990-2012 John Cremona
5 //
6 // This file is part of the eclib package.
7 //
8 // eclib is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 2 of the License, or (at your
11 // option) any later version.
12 //
13 // eclib is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 // for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with eclib; if not, write to the Free Software Foundation,
20 // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 //
22 //////////////////////////////////////////////////////////////////////////
23 
24 
25 //#define DEBUG_QSIEVE
26 
27 #include <eclib/interface.h>
28 #include <eclib/compproc.h>
29 
30 #include <eclib/method.h>
31 
32 #include <eclib/points.h>
33 #include <eclib/polys.h>
34 #include <eclib/curvemod.h>
35 #include <eclib/pointsmod.h>
36 #include <eclib/ffmod.h>
37 #include <eclib/divpol.h>
38 #include <eclib/tlss.h>
39 #include <eclib/elog.h>
40 #include <eclib/saturate.h>
41 
42 #include <eclib/sieve_search.h>
43 
44 #include <eclib/mwprocs.h>
45 
46 //
47 // some locally called general functions, belong in library maybe:
48 //
49 
50 // unlikely to be called by anything but find_inf:
roots_of_cubic(const Curve & E)51 vector<bigcomplex> roots_of_cubic(const Curve& E)
52 {
53   bigint a1,a2,a3,a4,a6;
54   E.getai(a1,a2,a3,a4,a6);
55 
56   bigfloat ra1=I2bigfloat(a1),
57            ra2=I2bigfloat(a2),
58            ra3=I2bigfloat(a3),
59            ra4=I2bigfloat(a4),
60            ra6=I2bigfloat(a6);
61 
62   bigcomplex c1 = ra2 + ra1*(ra1/4) ;
63   bigcomplex c2 = ra4 + ra1*(ra3/2) ;
64   bigcomplex c3 = ra6 + ra3*(ra3/4) ;
65   return solvecubic(c1,c2,c3);
66 }
67 
min_real(vector<bigcomplex> array)68 bigfloat min_real(vector<bigcomplex> array)
69 {
70 //cout<<"In min_real() with array:\t"<<array<<endl;
71   bigfloat minr, r; int first=1; minr=0;
72   for (unsigned int i=0; i<array.size(); i++)
73     { if(abs(imag(array[i]))<0.001)  // then the root is regarded as real
74 	{
75 	  r = real(array[i]);
76 	  if (first||(minr > r)) {minr = r; first=0;}
77 	}
78     }
79 //cout<<"minr finally " << minr << "\n";
80   return minr;
81 }
82 
83 int order_real_roots(vector<double>& bnd, vector<bigcomplex> roots);
84 //checks (and returns) how many roots are actually real, and puts those in
85 //bnd, in increasing order, by calling set_the_bound
86 int set_the_bounds(vector<double>& bnd, bigfloat x0, bigfloat x1, bigfloat x2);
87 //This transforms (if possible) x0, x1 and x1 into double;  the search
88 //should be made on [x0,x1]U[x2,infty] so if x1 or x2 overflows, the search
89 //is on [x0,infty].  The function returns 3 in the first case, 1 in the second.
90 //If x0 overflows, it returns 0.  A warning is printed out.
91 
92 #define matentry(m,i,j) *((m)+((i)*MAXRANK)+(j))
93 
94 bigfloat det(bigfloat *m, long m_size);
95    // fwd declaration: det and detminor jointly recursive
96 
get_minor(bigfloat * m,long m_size,long i0,long j0)97 bigfloat* get_minor(bigfloat *m, long m_size, long i0, long j0)
98 {
99   long i, j, ii, jj;
100   bigfloat *minor = new bigfloat[MAXRANK*MAXRANK];
101   for (i=0; i<m_size-1; i++)
102     {
103       ii=i; if(i>=i0)ii++;
104       for (j=0; j<m_size-1; j++)
105       {
106 	jj=j; if(j>=j0) jj++;
107 	matentry(minor,i,j) = matentry(m,ii,jj);
108       }
109     }
110   return minor;
111 }
112 
113 
det_minor(bigfloat * m,long m_size,long i0,long j0)114 bigfloat det_minor(bigfloat *m, long m_size, long i0, long j0)
115 {
116   bigfloat *minor = get_minor(m,m_size,i0,j0);
117   bigfloat det_return = det(minor, m_size-1);
118   delete [] minor;
119   return det_return;
120 }
121 
det(bigfloat * m,long m_size)122 bigfloat det(bigfloat *m, long m_size)
123 {
124   switch (m_size) {
125   case 0:
126     return to_bigfloat(1); break;
127   case 1:
128     return matentry(m,0,0); break;
129   case 2:
130     return matentry(m,0,0)*matentry(m,1,1) - matentry(m,1,0)*matentry(m,0,1);
131     break;
132   default:
133     // use recursion
134 /*  // Old naive minor-expansion method:
135     bigfloat ans = 0;
136     long sign = 1, j;
137     for (j=0; j<m_size; j++)
138       { ans += sign * matentry(m,0,j) * det_minor(m, m_size, 0, j);
139 	sign *= -1;
140       }
141     return ans;
142 */
143 // New Gaussian method (20/1/95)
144     long i,j,i0;
145     bigfloat ans=to_bigfloat(1), pivot=matentry(m,0,0), piv, temp,
146       eps=to_bigfloat(1.0e-6);
147     for(i0=0; i0<m_size && abs(pivot)<eps; i0++) pivot=matentry(m,i0,0);
148     if(i0==m_size) return to_bigfloat(0); // first column all 0
149     if(i0>0)  // swap rows 0, i0:
150       {
151 	ans=to_bigfloat(-1);
152 	for(j=0; j<m_size; j++)
153 	  {
154 	    temp=matentry(m,i0,j);
155 	    matentry(m,i0,j)=matentry(m,0,j);
156 	    matentry(m,0,j)=temp;
157 	  }
158       }
159     // eliminate first column
160     pivot=matentry(m,0,0);
161     for(i=1; i<m_size; i++)
162       {
163 	piv=matentry(m,i,0)/pivot;
164 	for(j=0; j<m_size; j++)
165 	  matentry(m,i,j) = matentry(m,i,j)-matentry(m,0,j)*piv;
166       }
167     return ans*pivot*det_minor(m,m_size,0,0);
168     break;
169   }
170   return to_bigfloat(1);  // shouldn't get here in fact
171 }
172 
173 
174 //#define DEBUG 1
175 
cleardenoms(vector<bigfloat> alpha)176 vector<long> cleardenoms(vector<bigfloat> alpha)
177 {
178   long len = alpha.size();
179   vector<long> nlist(len);  // returned
180   vector<long> dlist(len);
181   long i, lcmd = 1;
182   bigfloat x, last=alpha[len-1];
183   for (i=0; i < len-1; i++)  // i doesn't include rank (new value)
184     { x = alpha[i] / last;
185       ratapprox(x, nlist[i], dlist[i]);
186       lcmd = (lcmd*dlist[i]) / ::gcd(lcmd, dlist[i]);    // ie lcm(d, dlist[i])
187                                         // ie we find the lcm of whole of dlist
188 #ifdef DEBUG
189       cout<<"ratapprox: of "<< x <<" is "<<nlist[i]<<" / "<<dlist[i]<<endl;
190       cout<<"  lcm of denoms so far: "<<lcmd<<endl;
191 #endif
192     }
193   for (i=0; i < len-1; i++)
194     nlist[i] *= (lcmd / dlist[i]);  // clear the denominators
195   nlist[len-1] = lcmd;
196   return nlist;
197 }
198 
mw(Curvedata * EE,int verb,int pp,int maxr)199 mw::mw(Curvedata *EE, int verb, int pp, int maxr)
200   :E(EE), rank(0), maxrank(maxr), reg(to_bigfloat(1)), verbose(verb), process_points(pp), satsieve(EE,verb)
201 {
202 #ifdef DEBUG
203   verbose=1;
204 #endif
205   height_pairs = new bigfloat[MAXRANK*MAXRANK];
206 }
207 
~mw()208 mw::~mw()
209 {
210    delete [] height_pairs;
211 }
212 
213 // NB We cannot use the default parameter mechanism as this must fit
214 // the template for the virtual function declared in class
215 // point_processor!
process(const bigint & x,const bigint & y,const bigint & z)216 int mw::process(const bigint& x, const bigint& y, const bigint& z)
217 {
218   return process(x,y,z,MAXSATPRIME);
219 }
220 
process(const bigint & x,const bigint & y,const bigint & z,int sat)221 int mw::process(const bigint& x, const bigint& y, const bigint& z, int sat)
222 {
223 #ifdef DEBUG
224   cout<<"mw::process with x = "<< x <<", y = "<<y<<", z = "<<z<<endl;
225 #endif
226   bigint rz; isqrt(z,rz);
227   bigint x1=x*rz, y1=y, z1=z*rz;
228   if(iso)
229     {
230       y1 -= (a1*x1+4*a3*z1);
231       x1 *= 2;
232       z1 *= 8;
233     }
234   Point P(E, x1,y1,z1);
235   if(P.isvalid()) return process(P,sat);
236 
237   // error:
238   cout<<"Raw point       x,y,z = "<<x<<", "<<y<<", "<<z<<endl;
239   cout<<"converted point x,y,z = "<<x1<<", "<<y1<<", "<<z1<<"\t";
240   cout<<"--not on curve!"<<endl;
241  return 0;
242 }
243 
process(const vector<Point> & Plist,int sat)244 int mw::process(const vector<Point>& Plist, int sat)
245 {
246   // process the points without saturation, do that at the end
247 
248   if(verbose)
249     cout<<"Processing "<<Plist.size()<<" points ..."<<endl;
250 
251   int flag=0;
252   for(vector<Point>::const_iterator P=Plist.begin(); P!=Plist.end(); P++)
253     flag = (process(*P,0));
254 
255   if(verbose)
256     cout<<"Finished processing the points (which had rank "<<rank<<")"<<endl;
257 
258   if((sat>0)&&(rank>0))
259     {
260       if (verbose) cout<<"saturating up to "<<sat<<"..."<<flush;
261       satsieve.set_points(basis);
262       long index;
263       vector<long> unsat;
264       int sat_ok = satsieve.saturate(unsat, index, sat);
265       if(verbose)
266         {
267           cout<<"done";
268           if (!sat_ok)
269             {
270               cout<<" (saturation failed for "<<unsat<<")";
271             }
272           cout<<endl;
273         }
274       if(index>1)
275 	{
276 	  basis = satsieve.getgens();
277 	  if(verbose)
278 	    cout<<"Gained index "<<index<<", new generators = "<<basis<<endl;
279 	}
280 // compute the height pairing matrix and regulator
281       int i, j;
282       for (i=0; i < rank; i++)
283 	{
284 	  mat_entry(i,i) = height(basis[i]);
285 	  for (j=0; j < i; j++)
286 	    {
287 	      mat_entry(i,j)
288 		= mat_entry(j,i)
289 		= height_pairing(basis[i], basis[j]);
290 	    }
291 	}
292       reg = det(height_pairs,rank);
293       if(verbose)
294 	cout<<"Regulator =  "<<reg<<endl;
295     }
296   return flag;
297 }
298 
process(const Point & PP,int sat)299 int mw::process(const Point& PP, int sat)
300 {
301 #ifdef DEBUG
302   cout<<"mw::process with P = "<< PP <<endl;
303 #endif
304   Point P = PP;  // so we can process const points
305   long ord = order(P);
306   long i, j, rank1=rank+1;
307 #ifdef DEBUG
308   cout<<"P = "<< P <<" has order "<<ord<<endl;
309   bigfloat hP=height(P);
310   cout<<"P = "<< P <<" has height "<<hP<<endl;
311 #endif
312 
313   if (verbose)
314     {cout<<"P"<<rank1<<" = "<<P;
315 #ifdef DEBUG
316     cout<<" (height "<<height(P)<<")";
317 #endif
318     cout << "\t" << flush;
319 #ifdef DEBUG
320     cout << "\n";
321     if(!P.isvalid()) cout << "###Warning### Not on curve!\n";
322 #endif
323     }
324 
325   if (ord > 0)
326     {
327       if (verbose) cout<<" is torsion point, order "<<ord<<endl;
328       return 0;
329     } // we're not interested in torsion points
330 
331   if(!process_points)
332     {
333       basis.push_back(P); rank++;
334       if(verbose) cout<<"P = "<<P<<", ht(P) = "<<height(P)<<endl;
335       return 0;
336     }
337 
338   if (rank==0)  // first non-torsion point
339     {
340       reg = height(P);
341       mat_entry(0,0) = reg;  // ie height_pairs[0][0] = reg
342       basis.push_back(P); rank=1;
343       if (verbose) cout<<"  is generator number 1\n";
344 #ifdef DEBUG
345       cout << "first non-torsion point, reg so far = "<<reg<<"\n";
346       //      cout << "returning "<<(maxrank<2)<<endl;
347 #endif
348       if(sat>0)
349 	{
350           satsieve.set_points(basis);
351           if (verbose) cout<<"saturating up to "<<sat<<"..."<<flush;
352           long index;
353           vector<long> unsat;
354           int sat_ok = satsieve.saturate(unsat, index, sat);
355           if(verbose)
356             {
357               cout<<"done";
358               if (!sat_ok)
359                 {
360                   cout<<" (saturation failed for "<<unsat<<")";
361                 }
362               cout<<endl;
363             }
364           if(index>1)
365             {
366               basis = satsieve.getgens();
367               if(verbose) cout<<"Gained index "<<index<<", new generator = "<<basis[0]<<endl;
368               reg = height(basis[0]);
369               mat_entry(0,0) = reg;
370             }
371 	}
372       return (maxrank<2); // 1 if max reached
373     }
374 
375   // otherwise general procedure:
376 
377 #ifdef DEBUG
378   cout<<"additional non-torsion point..."<<endl;
379 #endif
380   //  update the height pairing matrix (at least for now)
381   // but don't add point yet
382   mat_entry(rank,rank) = height(P); // also sets height in P
383   for (i=0; i < rank; i++)
384     {
385       Point Q = basis[i];
386       bigfloat hp = height_pairing(Q, P);
387       mat_entry(i,rank) = hp;
388       mat_entry(rank,i) = hp;
389     }
390 
391   // compute cofactors of new last column
392   vector<bigfloat> alpha(rank1);  // to store cofactors
393   long detsign = ( odd(rank) ? +1 : -1 ); //set for flip before first use
394   for (i=0; i < rank; i++)
395     {
396       detsign = -detsign;
397       alpha[i] = det_minor(height_pairs, rank1, i, rank) * detsign;
398 #ifdef DEBUG
399       cout<<"alpha["<<i<<"] = "<<alpha[i]<<"\n";
400 #endif
401     }
402   alpha[rank] = reg;  // ie the previous value, before this point
403 #ifdef DEBUG
404   cout<<"alpha["<<rank<<"] = "<<alpha[rank]<<"\n";
405 #endif
406 
407   // find the new determinant
408   bigfloat newreg = to_bigfloat(0);
409   for (i=0; i <= rank; i++) newreg += mat_entry(i,rank) * alpha[i];
410 #ifdef DEBUG
411   cout<<"After adding P, new height pairing matrix:\n";
412   for(i=0; i<=rank; i++)
413     {
414       for(j=0; j<=rank; j++) cout << mat_entry(i,j) << "\t";
415       cout << "\n";
416     }
417   cout<<"\nreg is now " << newreg << "\t";
418 #endif
419 
420   // test for simple case, new point is indep previous
421   if ( abs(newreg/reg) > 1.0e-4 )
422     {
423       reg = newreg;
424 #ifdef DEBUG
425       cout << "treating as NON-zero" << "\n";
426 #endif
427       basis.push_back(P); rank=rank1;
428       if (verbose) cout<<"  is generator number "<<rank<<endl;
429       if(sat>0)
430 	{
431           satsieve.reset_points(basis);
432           if (verbose) cout<<"saturating up to "<<sat<<"..."<<flush;
433           long index;
434           vector<long> unsat;
435           int sat_ok = satsieve.saturate(unsat, index, sat);
436           if(verbose)
437             {
438               cout<<"done, index = "<<index<<".";
439               if (!sat_ok)
440                 {
441                   cout<<" (saturation failed for "<<unsat<<")";
442                 }
443               cout<<endl;
444             }
445           if(index>1)
446             {
447               basis = satsieve.getgens();
448               if(verbose) cout<<"Gained index "<<index<<", new generators = "<<basis<<endl;
449               // completely recompute the height pairing matrix
450               for (i=0; i < rank; i++)
451                 {
452                   mat_entry(i,i) = height(basis[i]);
453                   for (j=0; j < i; j++)
454                     {
455                       mat_entry(i,j)
456                         = mat_entry(j,i)
457                         = height_pairing(basis[i], basis[j]);
458                     }
459                 }
460               reg /= (index*index);
461             }
462 	}
463 #ifdef DEBUG
464       cout << "about to return, rank = "<<rank<<", maxrank = "<<maxrank<<": returning "<<(maxrank==rank)<<endl;
465 #endif
466       return (maxrank==rank); // 1 if max reached
467     }
468 
469   // otherwise, express new point as lin-comb of the previous Now that
470   // we are saturating as we go, this should not happen (unless the
471   // index is divisible by a prime > sat)
472 #ifdef DEBUG
473   cout << "treating as ZERO" << "\n";
474   cout << "Finding a linear relation between P and current basis\n";
475 #endif
476 
477   vector<long> nlist = cleardenoms(alpha);
478   long index = nlist[rank];
479 
480 #ifdef DEBUG
481   cout<<"index = "<<index<<endl;
482 #endif
483 
484   // test simple case when new is just Z-linear comb of old
485   if ( index == 1 )
486     { if (verbose)
487 	{
488 	  cout<<" = "<<-nlist[0]<<"*P1";
489 	  for(i=1; i<rank; i++)
490 	     cout<<" + "<<-nlist[i]<<"*P"<<(i+1);
491 	  cout<<" (mod torsion)\n";
492 	}
493 // Check:
494     Point Q = P;
495     for(i=0; i<rank; i++) Q += nlist[i]*basis[i];
496     int oQ = order(Q);
497     if(oQ==-1) // infinite order, problem!
498       {
499 	cout<<"Problem in mw::process(), bad linear combination!\n";
500 	cout<<"Difference = "<<Q<<" with height "<<height(Q)<<endl;
501       }
502     else if(verbose>1)
503       {
504 	cout<<"Difference = "<<Q<<" with height "<<height(Q)<<endl;
505       }
506 
507     return 0;  // with regulator and basis (and h_p matrix) unchanged
508     } // end of if(index==1)
509 
510   // otherwise add P to the list now, compute to gain index
511   basis.push_back(P);
512 
513   if (verbose)
514     {
515       for (i=0; i < rank; i++)
516 	cout<<nlist[i]<<"*P"<<(i+1)<<" + ";
517       cout<<index<<"*"<<"P"<<(rank1)<<" = 0 (mod torsion)\n";
518     }
519 // Check:
520   Point Q = index*P;
521   for(i=0; i<rank; i++) Q += nlist[i]*basis[i];
522   int oQ = order(Q);
523   if(oQ==-1) // infinite order, problem!
524     {
525       cout<<"Problem in mw::process(), bad linear combination!\n";
526       cout<<"Difference = "<<Q<<" with height "<<height(Q)<<endl;
527     }
528   else if(verbose>1)
529     {
530       cout<<"Difference = "<<Q<<" with height "<<height(Q)<<endl;
531     }
532 
533 
534   // find minimum coeff. |ai|
535   long min = 0, ni;
536   long imin = -1;
537   for (i=0; i <= rank; i++)
538     { ni = abs(nlist[i]);
539       if (  (ni>0) && ( (imin==-1) || (ni<min) )  )
540 	{ min = ni; imin = i; }
541     }
542 
543   // find aj with ai ndiv aj, write aj = ai*q + r with 0<r<|ai|
544   // since then ai*Pi + aj*Pj = ai(Pi + q*Pj) + r*Pj,
545   // replace generator Pi with Pi + q*Pj
546   // and replace aj by r, and i by j
547   // after finite no. steps obtain some minimal ai = 1
548   // then we can just discard Pi.
549 
550   long r, q;
551   while ( min > 1 )
552     {
553       for (i=0; i <= rank; i++)
554       {
555 	r = mod(nlist[i], min);
556 	q = (nlist[i] - r) / nlist[imin];
557 	if ( r!=0 )
558 	{
559 	  basis[imin] += q*basis[i];
560 	  imin=i; min=abs(r); nlist[imin]=r;
561 #ifdef DEBUG
562 	  if (verbose)
563 	    { for (j=0; j < rank; j++)
564 		cout<<nlist[j]<<"*"<<basis[j]<<" + ";
565 	      cout<<nlist[rank]<<"*"<<basis[rank]<<" = 0 (mod torsion)\n";
566 	    }
567 #endif
568   	  break;  // out of the for loop, back into the while
569 	}
570       } // ends for
571     } // ends while
572 
573   if (verbose)
574     cout<<"Gaining index "<<index<<"; ";
575 
576   // delete basis[imin]
577   basis.erase(basis.begin()+imin);
578   //  for(j=imin; j<rank; j++) basis[j]=basis[j+1];
579 
580   // completely recompute the height pairing matrix
581   for (i=0; i < rank; i++)  // 19/8/02: this was <=rank
582     { mat_entry(i,i) = height(basis[i]);
583       for (j=0; j < i; j++)
584 	{
585 	  mat_entry(i,j)
586 	    = mat_entry(j,i)
587 	    = height_pairing(basis[i], basis[j]);
588 	}
589     }
590 
591   reg /= (index*index);
592   if (verbose)
593     {
594       cout<<"\nNew set of generators: \n";
595       for(i=0; i<rank; i++)
596 	{
597 	  if(i)cout<<", ";
598 	  cout<<"P"<<(i+1)<<" = "<< basis[i];
599 	}
600       cout<<endl;
601     }
602   return 0; // rank did not increase
603 } // end of function mw::process(Point)
604 
saturate(long & index,vector<long> & unsat,long sat_bd,long sat_low_bd)605 int mw::saturate(long& index, vector<long>& unsat, long sat_bd, long sat_low_bd)
606 {
607   if (verbose) cout<<"saturating basis..."<<flush;
608 
609   // This code does a dummy call to index_bound() in order to get
610   // points from the search done there into the mwbasis.  But it was
611   // decided to let the user do some searching if relevant instead
612 #if(0)
613   vector<Point> pts;
614   bigint ib = index_bound(E,basis,pts,0,(verbose>1));
615   // Must make sure that the new points have the correct Curvedata pointer!
616   for(unsigned int i=0; i<pts.size(); i++)
617     pts[i].init(E,getX(pts[i]),getY(pts[i]),getZ(pts[i]));
618   bigfloat oldreg = reg;
619   int oldrank=rank;
620   process(pts,0); //no saturation here!  This may update basis
621   bigint ind = Iround(sqrt(oldreg/reg));
622   if(verbose&&(ind>1))
623     {
624       cout<<"after search, gained index "<<ind
625 	  <<", regulator = "<<reg<<endl;
626     }
627   if((rank>oldrank))
628     {
629       cout<<"after search, rank increases to "<<rank
630 	  <<", regulator = "<<reg<<endl;
631     }
632 #endif
633   satsieve.set_points(basis);
634   int ok = 1;
635   if(rank>0) ok=satsieve.saturate(unsat,index,sat_bd,1,10, sat_low_bd);
636   if(verbose) cout<<"done"<<endl;
637   if(!ok)
638     cout<<"Failed to saturate MW basis at primes "<<unsat<<endl;
639   if(index>1)
640     {
641       basis = satsieve.getgens();
642   // completely recompute the height pairing matrix
643       for (int i=0; i < rank; i++)
644 	{
645 	  mat_entry(i,i) = height(basis[i]);
646 	  for (int j=0; j < i; j++)
647 	    {
648 	      mat_entry(i,j)
649 		= mat_entry(j,i)
650 		= height_pairing(basis[i], basis[j]);
651 	    }
652 	}
653       reg /= (index*index);
654       if(verbose)
655 	{
656 	  cout<<"Gained index "<<index<<endl;
657 	  cout<<"New regulator =  "<<reg<<endl;
658 	}
659     }
660   return ok;
661 }
662 
search(bigfloat h_lim,int moduli_option,int verb)663 void mw::search(bigfloat h_lim, int moduli_option, int verb)
664 {
665 #ifdef DEBUG
666   cout<<"In mw::search;  maxrank = "<<maxrank<<endl;
667 #endif
668   if(moduli_option)
669     {
670       sieve s(E, this, moduli_option, verb);
671       s.search(h_lim);
672     }
673   else // use Stoll's sieve, Sophie Labour's conversion:
674     {
675       vector<bigint> c(4);
676       E -> getai(a1,a2,a3,a4,a6);
677       iso = !((a1==0)&&(a3==0));
678       if(iso)
679 	{
680 	  c[0]=16*getb6(*E);
681 	  c[1]= 8*getb4(*E);
682 	  c[2]=   getb2(*E);
683 	  c[3]=1;
684 	}
685       else
686 	{
687 	  c[0]=a6;
688 	  c[1]=a4;
689 	  c[2]=a2;
690 	  c[3]=1;
691 	}
692       if(iso) h_lim+=2.08;
693 //    if(iso) cout<<"Adding log(8) to h_lim, increasing it to "<<h_lim<<endl;
694       qsieve s(this, 3, c, h_lim, verb);
695       bigcomplex c1(I2bigfloat(c[2])),
696                  c2(I2bigfloat(c[1])),
697                  c3(I2bigfloat(c[0]));
698       vector<bigcomplex> roots=solvecubic(c1,c2,c3);
699       vector<double> bnd(3);
700       int nrr=order_real_roots(bnd,roots);
701 #ifdef DEBUG_QSIEVE
702       cout<<endl;
703       cout<<"cubic "<<c[0]<<" "<<c[1]<<" "<<c[2]<<" "<<c[3]<<endl;
704       cout<<"coeff "<<c1<<" "<<c2<<" "<<c3<<endl;
705       cout<<"roots "<<roots<<endl;
706       cout<<"bnd "<<bnd<<endl;
707       cout<<"smallest "<<bnd[0]<<endl;
708 #endif
709       s.set_intervals(bnd,nrr,1);
710       s.search(); //searches and processes
711     }
712 }
713 
search_range(bigfloat xmin,bigfloat xmax,bigfloat h_lim,int moduli_option,int verb)714 void mw::search_range(bigfloat xmin, bigfloat xmax, bigfloat h_lim,
715 		    int moduli_option, int verb)
716 {
717   sieve s(E, this, moduli_option, verb);
718   s.search_range(xmin,xmax,h_lim);
719 }
720 
721 //#define DEBUG_SIEVE
722 
sieve(Curvedata * EE,mw * mwb,int moduli_option,int verb)723 sieve::sieve(Curvedata * EE, mw* mwb, int moduli_option, int verb)
724 : E(EE), mwbasis(mwb), verbose(verb)
725 {
726   E->getai(a1,a2,a3,a4,a6);
727   int ncomp = getconncomp(*E);
728   posdisc = ncomp==2;
729   long i, j;
730 
731 // find pt of order two in E(R) with minimal x-coord
732 
733   vector<bigcomplex> roots = roots_of_cubic(*E);
734   if(posdisc)
735     {
736       x1=real(roots[0]);
737       x2=real(roots[1]);
738       x3=real(roots[2]);
739       orderreal(x3,x2,x1);  // so x1<x2<x3
740       xmin=x1;
741     }
742   else
743     x3=xmin = min_real(roots);
744 
745   if (verbose)
746     {
747       cout << "sieve: real points have ";
748       if(posdisc) cout<<x1<<" <= x <= " << x2 << " or ";
749       cout << x3 << " <= x; xmin =  " << xmin << endl;
750     }
751 // set up list of auxiliary moduli
752 // and a list of which residues modulo each of these are squares
753 
754   switch(moduli_option) {
755   case 1:
756     num_aux = 10;
757     auxs = new long[num_aux];
758     auxs[0]=3;
759     auxs[1]=5;
760     auxs[2]=7;
761     auxs[3]=11;
762     auxs[4]=13;
763     auxs[5]=17;
764     auxs[6]=19;
765     auxs[7]=23;
766     auxs[8]=29;
767     auxs[9]=31;
768     break;
769 
770   case 2:// the following taken from Gebel's scheme
771     num_aux = 3;
772     auxs = new long[num_aux];
773     auxs[0]=5184;  // = (2^6)*(3^4)   // old: 6624; //  = (2^5)*(3^2)*23
774     auxs[1]=5929;  // = (7^2)*(11^2)  // old: 8075; //  = (5^2)*17*19
775     auxs[2]=4225;  // = (5^2)*(13^2)  // old: 7007; //  = (7^2)*11*13
776     break;
777 
778   case 3:
779   default:
780     num_aux = 9;
781     auxs = new long[num_aux];
782     auxs[0]=32;
783     auxs[1]= 9;
784     auxs[2]=25;
785     auxs[3]=49;
786     auxs[4]=11;
787     auxs[5]=13;
788     auxs[6]=17;
789     auxs[7]=19;
790     auxs[8]=23;
791     break;
792   }
793 
794 #ifdef DEBUG_SIEVE
795   if(verbose)
796     {
797       cout<<"Using "<<num_aux<<" sieving moduli:\n";
798       for(i=0; i<num_aux; i++) cout << auxs[i]<<"\t";
799       cout<<endl;
800     }
801 #endif
802 
803   xgood_mod_aux = new int*[num_aux];
804 //  x1good_mod_aux = new int*[num_aux];
805   squares = new int*[num_aux];
806   amod = new long[num_aux];
807 
808   for (i = 0; i < num_aux; i++)
809     {
810       long aux = auxs[i];
811       long half_aux = ((aux + 1) / 2);
812       squares[i] = new int[aux];
813       for (j = 0; j < aux; j++)      squares[i][j]=0;
814       for (j = 0; j < half_aux; j++) squares[i][(j*j)%aux]=1;
815       xgood_mod_aux[i] = new int[aux];
816 
817 //       x1good_mod_aux[i] = new int[aux];
818 //
819 //     // set the flag matrix for c=1:
820 //
821 //       long pd1 = posmod(a1, aux);
822 //       long pd2 = posmod(a2, aux);
823 //       long pd3 = posmod(a3, aux);
824 //       long pd4 = posmod(a4, aux);
825 //       long pd6 = posmod(a6, aux);
826 //
827 //       long disc, temp, temp2, x=0;
828 //
829 //       long dddf= posmod(24,aux);
830 //       long ddf = posmod(2*(pd1*pd1)%aux + 8*pd2+24 , aux);
831 //       long df  = posmod(pd1*(pd1+2*pd3)%aux + 4*(pd4+pd2+1) , aux);
832 //       long f   = posmod(((pd3*pd3)%aux+4*pd6) , aux);
833 //
834 //       while(x<aux)
835 // 	{
836 // 	  x1good_mod_aux[i][x] = squares[i][f];
837 // 	  x++;
838 // 	  f   +=  df; if(f  >=aux) f  -=aux;
839 // 	  df  += ddf; if(df >=aux) df -=aux;
840 // 	  ddf +=dddf; if(ddf>=aux) ddf-=aux;
841 // 	}
842     }  // end of aux loop
843 #ifdef DEBUG_SIEVE
844   if(verbose)
845     {
846       cout<<"squares lists:\n";
847       for(i=0; i<num_aux; i++)
848 	{
849 	  cout << auxs[i]<<":\t";
850 	  for(j=0; j<auxs[i]; j++) if(squares[i][j]) cout<<j<<"\t";
851 	  cout<<endl;
852 	}
853     }
854 #endif
855 
856 // variables for collecting efficiency data:
857 
858   modhits = new long[num_aux];
859   ascore=0; npoints=0;
860   for(i=0; i<num_aux; i++) modhits[i]=0;
861 
862 //   if(verbose)
863 //     {
864 //       cout << "Finished constructing sieve, using ";
865 //       switch(moduli_option)
866 // 	{
867 // 	case 1: cout << "ten primes 3..31"; break;
868 // 	      case 2: cout << "Gebel's three moduli"; break;
869 // 	      case 3: cout << "prime powers"; break;
870 // 	      }
871 //       cout << endl;
872 //     }
873 }
874 
~sieve()875 sieve::~sieve()
876 {
877   delete [] auxs;
878   for(long i=0; i<num_aux; i++)
879     {
880       delete [] xgood_mod_aux[i];
881 //      delete [] x1good_mod_aux[i];
882       delete [] squares[i];
883     }
884   delete [] xgood_mod_aux;
885 //  delete [] x1good_mod_aux;
886   delete [] squares;
887   delete [] amod;
888   delete [] modhits;
889 }
890 
search(bigfloat h_lim)891 void sieve::search(bigfloat h_lim)
892 {
893 // N.B. On 32-bit machines, h_lim MUST be < 21.48 else exp(h_lim)>2^31
894 //      and overflows
895 //      On 64-bit machines, h_lim must be < 43.668.
896 
897   long i,j;
898 
899   // set initial bounds for point coefficients
900   alim = I2long(Ifloor(exp(h_lim)));
901   clim = clim1 = clim2 = clim0 = I2long(Ifloor(exp(h_lim / 2)));
902   long temp;
903 
904   if(posdisc)
905     {
906       if(x2<-1)
907 	{
908 	  temp = I2long(Ifloor(sqrt(alim/(-x2))));
909 	  if(clim1>temp) clim1=temp;
910 	}
911       if(x1>1)
912 	{
913 	  temp = I2long(Ifloor(sqrt(alim/x1)));
914 	  if(clim1>temp) clim1=temp;
915 	}
916     }
917   if (x3>1)
918     {
919       temp = I2long(Ifloor(sqrt(alim/x3)));
920       if(clim2>temp) clim2=temp;
921     }
922   clim=clim2;
923   if(posdisc) if(clim1>clim2) clim=clim1;
924 
925   if (verbose)
926     cout<< "sieve::search: trying a up to "<<alim<<" and c up to "<<clim<<endl;
927 
928 // declare and initialize other loop variables
929   long pd1,pd2,pd3,pd4,pd6, csq, aux;
930   cflag = new int[10000];  // max needed; only used up to c each time,
931                            // and only when c<=10000 (use_cflag==1)
932 
933 //
934 // MAIN LOOP
935 //
936 
937 #define FIRSTC 1   // for debugging etc
938 
939   for (c = FIRSTC; c <= clim; c++)
940     {
941       // some preliminary calculations of multiples of c etc.
942       csq = c*c /* long */;
943       c2 = csq  /* bigint */;
944       c3 = c*c2; c4 = c2*c2; c6 = c2*c4;
945       d1 = a1*c; d2 = a2*c2; d3 = a3*c3; d4 = a4*c4; d6 = a6*c6;
946 
947 #ifdef DEBUG_SIEVE
948   if(verbose)
949     {
950       cout<<"c = "<<c<<"\n";
951       cout<<"d1,...,d6 = "<<d1<<", "<<d2<<", "<<d3<<", "<<d4<<", "<<d6<<"\n";
952     }
953 #endif
954       use_cflag = (c<=10000);
955       if(use_cflag)
956 	{
957 // set up flag array of residues coprime to c
958 	  cflag[0]=(c==1);
959 	  for(i=1; i<c; i++) cflag[i] = cflag[c-i] = (::gcd(i,c)==1);
960 	}
961 
962       // set the main flag matrix
963       for (long index = 0; index < num_aux; index++)
964 	{
965 	  aux = auxs[index];
966 
967 // 	  if(gcd(c,aux)==1)  // the easy case
968 // 	    {
969 // 	      long xcc=0, csqm=csq%aux;;
970 // 	      int* flag = xgood_mod_aux[index];
971 // 	      int* flag1 = x1good_mod_aux[index];
972 // 	      x=aux;
973 // 	      while(x--)
974 // 		{
975 // 		  *flag = *flag1++;
976 // 		  xcc+=csqm; flag+=csqm;
977 // 		  if(xcc>=aux) {xcc-=aux; flag-=aux;}
978 // 		}
979 // 	    }
980 // 	  else  // c, aux have common factor
981 // 	    {
982 // 	      if(odd(aux)&&((csq%aux)==0))
983 // 		{
984 // 		  int* flag = xgood_mod_aux[index];
985 // 		  int* sqs = squares[index];
986 // 		  x=aux;
987 // 		  while(x--) *flag++ = *sqs++;
988 // 		}  // end of if(odd(aux))
989 // 		else  //default: full recomputation
990 		  {
991 		    pd1 = posmod(d1 , aux);
992 		    pd2 = posmod(d2 , aux);
993 		    pd3 = posmod(d3 , aux);
994 		    pd4 = posmod(d4 , aux);
995 		    pd6 = posmod(d6 , aux);
996 
997 		    long dddf= 24%aux;
998 		    long ddf = posmod(2*(pd1*pd1)%aux + 8*pd2+24 , aux);
999 		    long df  = posmod(pd1*(pd1+2*pd3)%aux + 4*(pd4+pd2+1) , aux);
1000 		    long f   = posmod(((pd3*pd3)%aux+4*pd6) , aux);
1001 
1002 		    int* flag = xgood_mod_aux[index];
1003 		    int* sqs = squares[index];
1004 		    long x=aux;
1005 #ifdef DEBUG_SIEVE
1006   if(verbose)
1007     {
1008       cout<<"aux = "<< aux <<"\n ";
1009       cout<<"pd1,...,pd6 = "<<pd1<<", "<<pd2<<", "<<pd3<<", "<<pd4<<", "<<pd6<<"\n";
1010     }
1011 #endif
1012 		    while(x--)
1013 		      {
1014 			*flag++ = sqs[f];
1015 #ifdef DEBUG_SIEVE
1016   if(verbose)
1017     {
1018       cout<<"x = "<< aux-x-1 <<", f(x) = "<<f<<": flag = "<<sqs[f]<<"\n";
1019     }
1020 #endif
1021 			f   +=  df; if(f  >=aux) f  -=aux;
1022 			df  += ddf; if(df >=aux) df -=aux;
1023 			ddf +=dddf; if(ddf>=aux) ddf-=aux;
1024 		      }
1025 
1026 		  }  // end of default case
1027 
1028 // 	    }  // end of non-coprime case
1029  	}  // end of aux loop
1030 #ifdef DEBUG_SIEVE
1031   if(verbose)
1032     {
1033       for(i=0; i<num_aux; i++)
1034 	{
1035 	  cout<<"possible x mod "<<auxs[i]<<": ";
1036 	  for(j=0; j<auxs[i]; j++) if(xgood_mod_aux[i][j]) cout<<j<<"\t";
1037 	  cout<<endl;
1038 	}
1039     }
1040 #endif
1041   if(verbose>1)
1042     {
1043       for(i=0; i<num_aux; i++)
1044 	{
1045 	  int n=0;
1046 	  cout<<"Number of possible x mod "<<auxs[i]<<": ";
1047 	  for(j=0; j<auxs[i]; j++) if(xgood_mod_aux[i][j]) n++;
1048 	  cout<<n<<" ("<<100.0*n/auxs[i]<<" percent)";
1049 	  cout<<endl;
1050 	}
1051     }
1052 
1053       // set up for a-loop(s)
1054 
1055       if(posdisc&&(c<=clim1))
1056 	{
1057 	  long amin = -alim, amax = alim;
1058 	  long temp = I2long(Ifloor(csq*x1));
1059 	  if(temp>amin) amin=temp;
1060 	  temp = I2long(Ifloor(csq*x2));
1061 	  if(temp<amax) amax=temp;
1062 	  a_search(amin,amax);
1063 	}
1064 
1065       if(c<=clim2)
1066 	{
1067 	  long temp = I2long(Ifloor(csq*x3));
1068 	  long amin = -alim, amax = alim;
1069 	  if(temp>amin) amin=temp;
1070 	  a_search(amin,amax);
1071 	}
1072     } // ends c- loop
1073   delete []cflag;
1074 } // end of sieve::search()
1075 
search_range(bigfloat xmin,bigfloat xmax,bigfloat h_lim)1076 void sieve::search_range(bigfloat xmin, bigfloat xmax, bigfloat h_lim)
1077 {
1078 // N.B. h_lim MUST be < 21.48 else exp(h_lim)>2^31 and overflows
1079   long i;
1080 
1081   // set initial bounds for point coefficients
1082   alim = I2long(Ifloor(exp(h_lim)));
1083   clim = clim1 = clim2 = clim0 = I2long(Ifloor(exp(h_lim / 2)));
1084   long temp;
1085 
1086   if(xmax<-1)
1087     {
1088       temp = I2long(Ifloor(sqrt(alim/(-xmax))));
1089       if(clim1>temp) clim1=temp;
1090     }
1091   if(xmin>1)
1092     {
1093       temp = I2long(Ifloor(sqrt(alim/xmin)));
1094       if(clim1>temp) clim1=temp;
1095     }
1096   clim=clim2;
1097   if(clim1>clim2) clim=clim1;
1098 
1099   if (verbose)
1100     cout<< "sieve::search: trying a up to "<<alim<<" and c up to "<<clim<<endl;
1101 
1102 // declare and initialize other loop variables
1103   long pd1,pd2,pd3,pd4,pd6, csq, aux;
1104   cflag = new int[10000];  // max needed; only used up to c each time,
1105                            // and only when c<=10000 (use_cflag==1)
1106 
1107 //
1108 // MAIN LOOP
1109 //
1110 
1111   for (c = 1; c <= clim; c++)
1112     {
1113       if(c>clim1) continue;
1114 
1115       // some preliminary calculations of multiples of c etc.
1116       csq = c*c /* long */;
1117       c2 = csq  /* bigint */;
1118       c3 = c*c2; c4 = c2*c2; c6 = c2*c4;
1119       d1 = a1*c; d2 = a2*c2; d3 = a3*c3; d4 = a4*c4; d6 = a6*c6;
1120 
1121       long amin = -alim, amax = alim;
1122       long temp = I2long(Iceil(csq*xmin));
1123       if(temp>amin) amin=temp;
1124       temp = I2long(Ifloor(csq*xmax));
1125       if(temp<amax) amax=temp;
1126 cout<<"amin = " << amin << ", amax = " << amax <<  endl;
1127 
1128       if(amin>amax) continue;   // skip this c
1129 
1130       if((amax-amin)<10)        // don't both sieving for a
1131 	{
1132 	  a_simple_search(amin,amax);
1133 	}
1134       else
1135 	{
1136 // set up flag array of residues coprime to c
1137 	  use_cflag = (c<=10000);
1138 	  if(use_cflag)
1139 	    {
1140 	      cflag[0]=(c==1);
1141 	      for(i=1; i<c; i++) cflag[i] = cflag[c-i] = (::gcd(i,c)==1);
1142 	    }
1143 
1144 // set the main flag matrix
1145 	  for (long index = 0; index < num_aux; index++)
1146 	    {
1147 	      aux = auxs[index];
1148 	      pd1 = posmod(d1 , aux);
1149 	      pd2 = posmod(d2 , aux);
1150 	      pd3 = posmod(d3 , aux);
1151 	      pd4 = posmod(d4 , aux);
1152 	      pd6 = posmod(d6 , aux);
1153 
1154 	      long dddf= 24%aux;
1155 	      long ddf = posmod(2*(pd1*pd1)%aux + 8*pd2+24 , aux);
1156 	      long df  = posmod(pd1*(pd1+2*pd3)%aux + 4*(pd4+pd2+1) , aux);
1157 	      long f   = posmod(((pd3*pd3)%aux+4*pd6) , aux);
1158 
1159 	      int* flag = xgood_mod_aux[index];
1160 	      int* sqs = squares[index];
1161 	      long x=aux;
1162 	      while(x--)
1163 		{
1164 		  *flag++ = sqs[f];
1165 		  f   +=  df; if(f  >=aux) f  -=aux;
1166 		  df  += ddf; if(df >=aux) df -=aux;
1167 		  ddf +=dddf; if(ddf>=aux) ddf-=aux;
1168 		}
1169 	    }  // end of aux loop
1170 	  a_search(amin,amax);
1171 	}
1172     } // ends c- loop
1173   delete []cflag;
1174 } // end of sieve::search() version 2 (explicit xmin, xmax)
1175 
a_search(const long & amin,const long & amax)1176 void sieve::a_search(const long& amin, const long& amax)
1177 {
1178   bigint pb,qb,db,rdb,rdb2,b,ac;
1179   long i, a=amin;
1180   a--;
1181   if (verbose) cout<<"sieve::search: trying c = "<<c<<"\t"
1182                    <<"("<<amin<<" <= a <= "<<amax<<")"<<endl;
1183 
1184   for (i=0; i < num_aux; i++)  amod[i] = posmod(a, auxs[i]);
1185   amodc = posmod(a,c);
1186 #ifdef DEBUG_SIEVE
1187   if(verbose)
1188     {
1189       cout<<"Initial a =  "<<a<<" modulo moduli = \t";
1190       for(i=0; i<num_aux; i++) cout << amod[i]<<"\t";
1191       cout<<endl;
1192     }
1193 #endif
1194 
1195   while (a < amax)
1196     {
1197       a++;
1198       // check that a is good for all the auxiliaries
1199       amodc++; if(amodc==c) amodc=0;
1200       int try_x;
1201       if(use_cflag) try_x = cflag[amodc];
1202       else          try_x = (::gcd(a,c)==1);
1203 
1204       if(try_x)
1205 	{
1206 	  ascore++;
1207 	}
1208       // DON'T add "else continue; (with next a)
1209       // as the amod[i] are not yet updated!
1210 //    for ( i=0; (i<num_aux); i++)
1211       for ( i=num_aux-1; (i>=0); i--)
1212 	{ long& amodi = amod[i];
1213 	  amodi++;
1214 	  if (amodi == auxs[i]) amodi = 0;
1215 	  if(try_x)
1216 	    {
1217 	      try_x = xgood_mod_aux[i][amodi];
1218 	      if(!try_x) modhits[i]++;
1219 	    }
1220 	}
1221       if (!try_x) continue;
1222 
1223       pb=a; pb*=d1; pb+=d3;              //    pb = a*d1 + d3;
1224                                          //    qb = d6 + a*(d4 + a*(d2 + a));
1225       qb=a; qb+=d2; qb*=a; qb+=d4; qb*=a; qb+=d6;
1226       db = sqr(pb); db += (4*qb);
1227       if(isqrt(db,rdb))
1228 	{
1229 	  b = rdb-pb; b/=2; ac = a*c;
1230 	  Point P(*E, ac, b, c3);
1231 	  mwbasis->process(P);
1232 	  npoints++;
1233 	}
1234     } // ends a-loop
1235 }
1236 
a_simple_search(const long & amin,const long & amax)1237 void sieve::a_simple_search(const long& amin, const long& amax)
1238 {
1239   bigint pb,qb,db,rdb,rdb2,b,ac;
1240   long a;
1241   if (verbose) cout<<"sieve::search: trying c = "<<c<<"\t"
1242                    <<"("<<amin<<" <= a <= "<<amax<<")\n";
1243 
1244   for (a=amin; a<amax; a++)
1245     {
1246 //    pb = a*d1 + d3;
1247       pb=a; pb*=d1; pb+=d3;
1248 //    qb = d6 + a*(d4 + a*(d2 + a));
1249       qb=a; qb+=d2; qb*=a; qb+=d4; qb*=a; qb+=d6;
1250       db = sqr(pb); db += (4*qb);
1251       if(isqrt(db,rdb))
1252 	{
1253 	  b = rdb-pb; b/=2; ac = a*c;
1254 	  Point P(*E, ac, b, c3);
1255 	  mwbasis->process(P);
1256 	  npoints++;
1257 	}
1258     } // ends a-loop
1259 }
1260 
1261 
stats(void)1262 void sieve::stats(void)
1263 {
1264   cout << "\nNumber of points found: "<<npoints<<"\n";
1265   cout << "\nNumber of a tested: "<<ascore<<"\n";
1266   cout<<"Numbers eliminated by each modulus:\n";
1267   long nmodhits=0;
1268   for(long i=0; i<num_aux; i++)
1269     {
1270       cout<<auxs[i]<<": "<<modhits[i]<<"\n";
1271       nmodhits+=modhits[i];
1272     }
1273   cout<<"Number eliminated by all moduli: "<<nmodhits<<"\n";
1274   bigfloat eff = to_bigfloat(nmodhits*100.0)/(ascore-npoints);
1275   cout<<"Sieve efficiency: "<<eff<<"\n";
1276 }
1277 
order_real_roots(vector<double> & bnd,vector<bigcomplex> roots)1278 int order_real_roots(vector<double>& bnd, vector<bigcomplex> roots)
1279 {//checks (and returns) how many roots are actually real, and puts those in
1280  //bnd, in increasing order, by calling set_the_bound
1281   long i,nrr=0;
1282   vector<bigfloat> real_roots;
1283 
1284   for (i=0;i<3;i++)
1285     {
1286       if (is_approx_zero(roots[i].imag()))
1287 	{
1288 	  real_roots.push_back(roots[i].real());
1289 	  if (is_approx_zero(real_roots[nrr]))  real_roots[nrr]=0;
1290 	  nrr++;
1291 	}
1292     }
1293   //  cout<<"nrr = "<<nrr<<endl;
1294   //  cout<<"real_roots = "<<real_roots<<endl;
1295   //  cout<<"Now ordering them..."<<endl;
1296   switch (nrr)
1297     {
1298     case 1: // possible overflow in assignment from bigfloat to double
1299 	return !doublify(real_roots[0],bnd[0]);
1300 	break;
1301     case 3:
1302       orderreal(real_roots[2],real_roots[1],real_roots[0]);
1303       return set_the_bounds(bnd,real_roots[0],real_roots[1],real_roots[2]);
1304     default:
1305       cout<<"mw_info::set_the_bounds: two real roots for the elliptic curve...\n";
1306     }
1307   return 0; //we should not get here...
1308 }
1309 
1310 //This transforms (if possible) x0, x1 and x2 into double; the search
1311 //should be made on [x0,x1]U[x2,infty] so if x1 or x2 overflows, the
1312 //search is made on [x0,infty].  The function returns 3 in the first
1313 //case, 1 in the second.  If x0 overflows, it returns 0.  A warning is
1314 //printed out.
set_the_bounds(vector<double> & bnd,bigfloat x0,bigfloat x1,bigfloat x2)1315 int set_the_bounds(vector<double>& bnd, bigfloat x0, bigfloat x1, bigfloat x2)
1316 {
1317   if (doublify(x0,bnd[0]))
1318     {
1319       cout<<"##WARNING##: lowest bound "<<x0<<" is not a double.\n";
1320       cout<<"Search will be made over [-height,height]."<<endl;
1321       return 0;
1322     }
1323   else
1324     {
1325       if (doublify(x1,bnd[1]) || doublify(x2,bnd[2]))
1326 	{
1327 	  cout<<"##WARNING##: second or third root is not a double.\n";
1328 	  cout<<"]x2,x3[ not excluded in search."<<endl;
1329 	  return 1;
1330 	}
1331       else
1332 	{
1333 	  return 3;
1334 	}
1335     }
1336 }
1337 
1338 
1339 //end of file mwprocs.cc
1340 
1341 
1342 
1343 
1344 
1345