1 #include "cado.h" // IWYU pragma: keep
2 // IWYU pragma: no_include <ext/alloc_traits.h>
3 #include <algorithm>
4 #include <fstream>      // std::ifstream // IWYU pragma: keep
5 #include <iomanip>      // std::hex // IWYU pragma: keep
6 #include <iostream>     // std::cout
7 #include <limits>
8 #include <list>
9 #include <memory>              // for allocator_traits<>::value_type, unique...
10 #include <sstream>      // std::ostringstream // IWYU pragma: keep
11 #include <stdexcept>
12 #include <string>
13 #include <vector>
14 #include <cstring>             // for strcmp
15 #include <cstdio> // stdout // IWYU pragma: keep
16 #include <climits> // UINT_MAX // IWYU pragma: keep
17 #include <gmp.h>               // for mpz_get_ui, mpz_divisible_ui_p, mpz_t
18 #include "badideals.hpp"
19 #include "cxx_mpz.hpp"         // for cxx_mpz
20 #include "getprime.h"          // for getprime_mt, prime_info_clear, prime_i...
21 #include "gmp_aux.h"           // for ulong_isprime, nbits, mpz_get_uint64
22 #include "gzip.h"       // ifstream_maybe_compressed
23 #include "mod_ul.h"     // modulusul_t
24 #include "mpz_poly.h"   // mpz_poly
25 #include "omp_proxy.h" // IWYU pragma: keep
26 #include "params.h"            // for cxx_param_list, param_list_lookup_string
27 #include "renumber.hpp"
28 #include "rootfinder.h" // mpz_poly_roots
29 #include "stats.h"      // for the builder process
30 #include "macros.h"
31 
32 /* Some documentation on the internal encoding of the renumber table...
33  *
34  * XXX This format has changed incompatibly in 2020 XXX
35  *
36  * The goal is to have a table that converts to/from two formats:
37  *
38  *  - an integer index
39  *
40  *  - a triple (side, prime number p, root in [0..p]) that represents a
41  *    prime ideal.
42  *    (yes, p included -- that means a projective root, i.e. an ideal
43  *    above p that divides J=<1,alpha>^-1).
44  *
45  * We want to minimize the storage, and guarantee cheap lookups in both
46  * cases.
47  */
48 
49 /* {{{ As of 20200515, the known uses of this table in cado-nfs, taking out
50  * the uses that pertain only to the building and handling of the
51  * database itself, are the following.
52  *
53  * index_from_p_r :
54  *      filter/dup2.cpp
55  *      sieve/las-dlog-base.cpp
56  *      sieve/fake_rels.cpp
57  *
58  * indices_from_p_a_b :
59  *      filter/dup2.cpp
60  *      sieve/las-dlog-base.cpp  -- not yet, but maybe at some point.
61  *
62  * p_r_from_index but as a forward iterator only
63  *      filter/filter_galois.cpp
64  *      filter/reconstructlog.cpp
65  *      sieve/fake_rels.cpp
66  *      filter/reconstructlog.cpp
67  *
68  * p_r_from_index, random access:
69  *      misc/convert_rels.cpp
70  *
71  * is_bad :
72  *      filter/dup2.cpp
73  *      sieve/las-dlog-base.cpp
74  *      sieve/fake_rels.cpp
75  *      (there, we do something very simple, and only pick a random index for a bad ideal, in [index, index+nb) )
76  *
77  * is_additional_column :
78  *      filter/reconstructlog.cpp
79  *      sieve/fake_rels.cpp
80  *
81  * }}} */
82 
83 /* In the above uses, the lookup (side,p,r) -> index is critical in the
84  * dup2 and descent steps, while the lookup index -> (side,p,r) is most
85  * often used only for forward iterators, where the context can be used
86  * to carry some extra information.
87  */
88 
89 /* There are various strategies that can be used to have an in-memory
90  * structure that makes these lookups possible.
91  */
92 
93 constexpr const int renumber_t::format_traditional; /*{{{*/
94 /* The traditional way that cado-nfs has been using for quite a while now
95  * (2013-2020) uses the following memory layout.
96  * In memory, the table is stored as a sequence of integers.  The info
97  * for each prime is stored as a sequence (vp,vr0,vr1,...,vrk) with
98  * vp>=vr0>...>vrk. vp is a representative for p.
99  * Whenever two adjacent integers in the in-memory table are in strictly
100  * increasing order, the latter is a marker that indicates a new p.
101  *
102  * In the traditional scheme, vr for an ideal (side,p,r) is
103  * side'*(p+1)+r, where side' is the side index counted among the
104  * non-rational sides. vp is (N-c)*(p+1)-1+c, with N the number of sides
105  * and c is 1 if there is a rational side. (In fact, the last "+c" is
106  * useless.)
107  *
108  * The goal of this traditional scheme is that exactly one integer
109  * appears in the database for each ideal -- namely, p is always
110  * implicit. This means, in particular, that when we have no rational
111  * side, there is no room to store _all_ roots: one of them must be
112  * sacrificed. The big advantage of this layout is that the
113  * index_from_p_r lookup, after the initial dichotomy, is
114  * straightforward. The big disadvantage is that p_r_from_index has to
115  * recompute the roots mod p in order to return the root mod p that was
116  * overwritten in order to store p. (This overhead occurs even in the
117  * case of a forward iterator.)
118  */
119 /*}}}*/
120 
121 constexpr const int renumber_t::format_variant; /*{{{*/
122 /* Variations around the previous scheme may be tried: we may try to
123  * store _all_ roots on non-rational sides.
124  * (The rational root is still implicit, if there is a rational side).
125  * Basically, we define vp and vr as above, but we include all vr's. This
126  * avoids the overhead of recomputing the roots when doing the
127  * p_r_from_index lookup.
128  * There are two disadvantages.
129  *  - First, storage is slightly larger. Instead of one integer per
130  *  ideal, we store approximately 1.4 integers. The density of ideals
131  *  in either side is given by D, and the number of integers that we
132  *  store is given by F, with the following magma code -- assuming
133  *  generic Galois groups on both sides:
134       D:=func<d1,d2|&+[m+n eq 0 select 0 else m+n where m is #Fix(s) where n is #Fix(t): s in S, t in T] * 1.0/#S/#T where S is SymmetricGroup(d1) where T is SymmetricGroup(d2)>;
135       F:=func<d1,d2|&+[m+n eq 0 select 0 else 1+m+n where m is #Fix(s) where n is #Fix(t): s in S, t in T] * 1.0/#S/#T where S is SymmetricGroup(d1) where T is SymmetricGroup(d2)>;
136       F(3,4)/D(3,4) is 1.4375 (on the first thought)
137  *  - But the real problem is not storage. The index_from_p_r lookup is
138  *  destroyed by this layout, since by making p explicit, we have data in
139  *  the table that does not correspond to an ideal. This means that we
140  *  need to store _more_ stuff to find the consecutive index, once we've
141  *  found the position of vr in the table. We may, right after vp, store
142  *  vp+I, with I the consecutive index of the first ideal above p. This
143  *  means that we have in the table increasing sequences of length 2 at
144  *  each p. This keeps the synchronization property. Note that the
145  *  p_r_from_index lookup is now _also_ impacted, since we moved from
146  *  O(1) to a mildly logarithmic cost (amortized O(1) for forward
147  *  iterators). This extra info costs somewhat more. By modifying F
148  *  above, we reach:
149       F(3,4)/D(3,4) is 1.875
150  */
151 /*}}}*/
152 
153 constexpr const int renumber_t::format_flat; /*{{{*/
154 /* My personal preference would be to bite the bullet and allow for two
155  * integers per ideal, always storing both p and r explicitly:
156  *  - The _from_index lookups would be trivial (we could keep the encoding
157  *    of r as vr = side'*(p+1)+r).
158  *  - The _from_p_r lookups would also be doable with very simple-minded
159  *    dichotomy (even the standard library can be put to some use here)
160  *  - The database in itself would be human readable.
161  */
162 /*}}}*/
163 
164 /* {{{ exceptions */
corrupted_table(std::string const & x)165 renumber_t::corrupted_table::corrupted_table(std::string const & x)
166     : std::runtime_error(std::string("Renumber table is corrupt: ") + x)
167 {}
168 
169 #if 0
170 static renumber_t::corrupted_table cannot_find_p(p_r_values_t p) {/*{{{*/
171     std::ostringstream os;
172     os << std::hex;
173     os << "cannot find data for prime 0x" << p;
174     os << " ; note: isprime(p)==" << ulong_isprime(p);
175 #if SIZEOF_INDEX != 8
176     os << "\n"
177         << "Note: above 2^32 ideals or relations,"
178         << " add FLAGS_SIZE=\"-DSIZEOF_P_R_VALUES=8 -DSIZEOF_INDEX=8\""
179         << " to local.sh\n";
180 #endif
181     return renumber_t::corrupted_table(os.str());
182 }/*}}}*/
183 #endif
184 
cannot_find_i(index_t i)185 static renumber_t::corrupted_table cannot_find_i(index_t i) {/*{{{*/
186     std::ostringstream os;
187     os << std::hex;
188     os << "cannot find data with index 0x" << i;
189     return renumber_t::corrupted_table(os.str());
190 }/*}}}*/
wrong_entry(p_r_values_t p,p_r_values_t vr)191 static renumber_t::corrupted_table wrong_entry(p_r_values_t p, p_r_values_t vr) {/*{{{*/
192     std::ostringstream os;
193     os << std::hex;
194     os << "above prime 0x" << p
195         << ", the index 0x" << vr << " makes no sense";
196     return renumber_t::corrupted_table(os.str());
197 }/*}}}*/
prime_is_too_large(p_r_values_t p)198 static renumber_t::corrupted_table prime_is_too_large(p_r_values_t p) {/*{{{*/
199     std::ostringstream os;
200     os << std::hex;
201     os << "prime 0x" << p << " is too large!";
202 #if SIZEOF_INDEX != 8
203     os << "\n"
204         << "Note: above 2^32 ideals or relations,"
205         << " add FLAGS_SIZE=\"-DSIZEOF_P_R_VALUES=8 -DSIZEOF_INDEX=8\""
206         << " to local.sh\n";
207 #endif
208     return renumber_t::corrupted_table(os.str());
209 }/*}}}*/
prime_maps_to_garbage(int format,p_r_values_t p,index_t i,p_r_values_t q)210 static renumber_t::corrupted_table prime_maps_to_garbage(int format, p_r_values_t p, index_t i, p_r_values_t q)/*{{{*/
211 {
212     std::ostringstream os;
213     os << std::hex;
214     os << "cached index for prime p=0x" << p;
215     os << " is 0x" << i << ", which points to q=0x" << q;
216     if (format == renumber_t::format_flat)
217         os << " (should be p)";
218     else
219         os << " (should be vp)";
220     os << " ; note: isprime(p)==" << ulong_isprime(p);
221     return renumber_t::corrupted_table(os.str());
222 }/*}}}*/
prime_maps_to_garbage(int format,p_r_values_t p,index_t i)223 static renumber_t::corrupted_table prime_maps_to_garbage(int format, p_r_values_t p, index_t i)/*{{{*/
224 {
225     std::ostringstream os;
226     os << std::hex;
227     os << "cached index for prime p=0x" << p;
228     os << " is 0x" << i << ", which points nowhere";
229     if (format == renumber_t::format_flat)
230         os << " (should be p)";
231     else
232         os << " (should be vp)";
233     os << " ; note: isprime(p)==" << ulong_isprime(p);
234     return renumber_t::corrupted_table(os.str());
235 }/*}}}*/
cannot_find_pr(renumber_t::p_r_side x,p_r_values_t vp,p_r_values_t vr)236 static renumber_t::corrupted_table cannot_find_pr(renumber_t::p_r_side x, p_r_values_t vp, p_r_values_t vr)/*{{{*/
237 {
238     std::ostringstream os;
239     os << std::hex;
240     os << "cannot find p=0x" << x.p << ", r=0x" << x.r << " on side " << x.side;
241     os << "; note: vp=0x" << vp << ", vr=0x" << vr;
242     return renumber_t::corrupted_table(os.str());
243 }/*}}}*/
cannot_find_pr(renumber_t::p_r_side x)244 static renumber_t::corrupted_table cannot_find_pr(renumber_t::p_r_side x)/*{{{*/
245 {
246     std::ostringstream os;
247     os << std::hex;
248     os << "cannot find p=0x" << x.p << ", r=0x" << x.r << " on side " << x.side;
249     return renumber_t::corrupted_table(os.str());
250 }/*}}}*/
cannot_lookup_p_a_b_in_bad_ideals(renumber_t::p_r_side x,int64_t a,uint64_t b)251 static renumber_t::corrupted_table cannot_lookup_p_a_b_in_bad_ideals(renumber_t::p_r_side x, int64_t a, uint64_t b)/*{{{*/
252 {
253     std::ostringstream os;
254     os << "failed bad ideal lookup for"
255         << " (a,b)=(" << a << "," << b << ")"
256         << " at p=0x" << std::hex << x.p
257         << " on side " << x.side;
258     return renumber_t::corrupted_table(os.str());
259 }/*}}}*/
parse_error(std::string const & what,std::istream & is)260 static renumber_t::corrupted_table parse_error(std::string const & what, std::istream& is)/*{{{*/
261 {
262     std::ostringstream os;
263     std::string s;
264     getline(is, s);
265     os << "parse error (" << what << "), next to read is: " << s;
266     return renumber_t::corrupted_table(os.str());
267 }/*}}}*/
parse_error(std::string const & what)268 static renumber_t::corrupted_table parse_error(std::string const & what)/*{{{*/
269 {
270     std::ostringstream os;
271     os << "parse error (" << what << ")";
272     return renumber_t::corrupted_table(os.str());
273 }/*}}}*/
274 /* }}} */
275 
276 /* {{{ helper functions relative to the "traditional" and "variant"
277  * formats
278  */
279 
280 /* This one is a helper only, because we use it for both T ==
281  * p_r_values_t and T == uint64_t */
vp_from_p(T p,int n,int c,int format)282 template<typename T> inline T vp_from_p(T p, int n, int c, int format)
283 {
284     /* The final "+c" is not necessary, but we keep it for compatibility */
285     int d = (format == renumber_t::format_traditional) ? (c - 1) : 0;
286     return (n - c) * (p + 1) + d;
287 }
288 
289 /* only used for format == format_{traditional,variant} */
compute_vp_from_p(p_r_values_t p) const290 p_r_values_t renumber_t::compute_vp_from_p (p_r_values_t p) const/*{{{*/
291 {
292     int n = get_nb_polys();
293     int c = (get_rational_side() >= 0);
294     return vp_from_p(p, n, c, format);
295 }/*}}}*/
296 
297 /* Inverse function of compute_vp_from_p */
298 /* only used for format == format_{traditional,variant} */
compute_p_from_vp(p_r_values_t vp) const299 p_r_values_t renumber_t::compute_p_from_vp (p_r_values_t vp) const/*{{{*/
300 {
301     int n = get_nb_polys();
302     int c = (get_rational_side() >= 0);
303     int d = (format == format_traditional) ? (c - 1) : 0;
304     return (vp - d) / (n - c) - 1;
305 }/*}}}*/
306 
307 /* only used for format == format_{traditional,variant} */
compute_vr_from_p_r_side(renumber_t::p_r_side x) const308 p_r_values_t renumber_t::compute_vr_from_p_r_side (renumber_t::p_r_side x) const/*{{{*/
309 {
310     if (x.side == get_rational_side()) {
311         /* the rational root _always_ has r encoded implicitly. In truth,
312          * we rarely need to look it up, except that we have to decide on
313          * something to store in the table...
314          */
315         return compute_vp_from_p(x.p);
316     }
317     p_r_values_t vr = x.side * (x.p + 1) + x.r;
318     if (get_rational_side() >= 0 && x.side > get_rational_side())
319         vr -= x.p + 1;
320     return vr;
321 }/*}}}*/
322 
323 /* only used for format == format_{traditional,variant} */
compute_p_r_side_from_p_vr(p_r_values_t p,p_r_values_t vr) const324 renumber_t::p_r_side renumber_t::compute_p_r_side_from_p_vr (p_r_values_t p, p_r_values_t vr) const/*{{{*/
325 {
326     /* Note that vr is only used for the encoding of non-rational ideals.
327      */
328     p_r_side res { p, 0, 0 };
329 
330     res.r = vr;
331     if (format == format_traditional && get_rational_side() < 0 && vr == compute_vp_from_p(p)) {
332         if (traditional_get_largest_nonbad_root_mod_p(res))
333             return res;
334         throw wrong_entry(p, vr);
335     }
336     for(res.side = 0 ; res.side < (int) get_nb_polys() ; res.side++) {
337         if (res.side == get_rational_side())
338             continue;
339         if (res.r <= p)
340             return res;
341         res.r -= p + 1;
342     }
343     if (res.r == 0) {
344         if (get_rational_side() >= 0) {
345             res.side = get_rational_side();
346             return res;
347         } else if (format == format_traditional && traditional_get_largest_nonbad_root_mod_p(res)) {
348             /* that is the _really, really_ annoying thing with the
349              * traditional format */
350             return res;
351         }
352     }
353     throw wrong_entry(p, vr);
354 }/*}}}*/
355 /* }}} */
356 
357 /* sort in decreasing order. Faster than qsort for ~ < 15 values in r[] */
358 /* only used for format == format_{traditional,variant} */
359 /* XXX This is total legacy, and should go away soon (we only temporarily
360  * keep it for measurement). See test-sort in
361  * tests/utils. This code is actually slow in most cases, and clearly
362  * outperformed by the code in iqsort.h
363  */
renumber_sort_ul(std::vector<unsigned long>::iterator r,size_t n)364 inline void renumber_sort_ul (std::vector<unsigned long>::iterator r, size_t n)
365 {
366     unsigned long rmin;
367 
368     if (UNLIKELY (n < 2))
369         return;
370 
371     if (UNLIKELY (n == 2)) {
372         if (r[0] < r[1]) {
373             rmin = r[0];
374             r[0] = r[1];
375             r[1] = rmin;
376         }
377         return;
378     }
379 
380     for (size_t i = n; --i;) {
381         size_t min = i;
382         rmin = r[min];
383         for (size_t j = i; j--;) {
384             unsigned long rj = r[j];
385             if (UNLIKELY (rj < rmin)) {
386                 min = j;
387                 rmin = rj;
388             }
389         }
390         if (LIKELY (min != i)) {
391             r[min] = r[i];
392             r[i] = rmin;
393         }
394     }
395 }
396 
cook(unsigned long p,std::vector<std::vector<unsigned long>> & roots) const397 renumber_t::cooked renumber_t::cook(unsigned long p, std::vector<std::vector<unsigned long>> & roots) const
398 {
399     cooked C;
400 
401     size_t total_nroots = 0;
402 
403     /* Note that all_roots always a root on the rational side, even
404      * though it's only a zero -- the root itself isn't computed.
405      */
406     for (unsigned int i = 0; i < get_nb_polys() ; i++) {
407         C.nroots.push_back(roots[i].size());
408         total_nroots += roots[i].size();
409     }
410 
411     if (total_nroots == 0) return C;
412 
413     if (format != format_flat) {
414         for (unsigned int i = 0; i < get_nb_polys() ; i++)
415             renumber_sort_ul (roots[i].begin(), roots[i].size());
416 
417         /* With the traditional format, the root on ratside side becomes vp.
418          * If there is no ratside side or not root on ratside side for this
419          * prime (i.e., lpb < p), then the largest root becomes vp.
420          */
421         p_r_values_t vp = compute_vp_from_p (p);
422 
423         if (format == format_variant) {
424             /* The "variant" has the advantage of being fairly simple */
425             C.traditional.push_back(vp);
426             /* except that we'll need to tweak this field */
427             C.traditional.push_back(vp);
428             for (int side = get_nb_polys(); side--; ) {
429                 if (side == get_rational_side())
430                     continue;
431                 for (auto r : roots[side]) {
432                     p_r_side x { (p_r_values_t) p, (p_r_values_t) r, side };
433                     C.traditional.push_back(compute_vr_from_p_r_side (x));
434                 }
435             }
436         } else {
437             C.traditional.push_back(vp);
438             /* if there _is_ a rational side, then it's an obvious
439              * candidate for which root is going to be explicit. This
440              * does not work if the lpb on the rational side is too
441              * small, however.
442              */
443             int print_it = get_rational_side() >= 0 && !(p >> get_lpb(get_rational_side()));
444             for (int side = get_nb_polys(); side--; ) {
445                 if (side == get_rational_side())
446                     continue;
447 
448                 for (auto r : roots[side]) {
449                     if (print_it++) {
450                         p_r_side x { (p_r_values_t) p, (p_r_values_t) r, side };
451                         C.traditional.push_back(compute_vr_from_p_r_side (x));
452                     }
453                 }
454             }
455         }
456         std::ostringstream os;
457         os << std::hex;
458         if (format == format_variant) {
459             ASSERT_ALWAYS(C.traditional.size() >= 2);
460             for(auto it = C.traditional.begin() + 2 ; it != C.traditional.end() ; ++it)
461                 os << *it << "\n";
462         } else {
463             for(auto x : C.traditional)
464                 os << x << "\n";
465         }
466         C.text = os.str();
467     } else {
468         /* reverse the ordering, because our goal is to remain compatible
469          * with the old-format indexing
470          */
471         for (int side = get_nb_polys(); side--; ) {
472             for (auto it = roots[side].rbegin() ; it != roots[side].rend() ; ++it) {
473                 p_r_side x { (p_r_values_t) p, (p_r_values_t) *it, side };
474                 C.flat.emplace_back(
475                         std::array<p_r_values_t, 2> {{
476                             (p_r_values_t) p,
477                             compute_vr_from_p_r_side (x)
478                         }});
479             }
480         }
481         std::ostringstream os;
482         for(auto x : C.flat)
483             os << x[0] << " " << x[1] << "\n";
484         C.text = os.str();
485     }
486     return C;
487 }
488 
489 /* Only for the traditional format, when there is no rational side.
490  *
491  * Set x.r to the largest root of f modulo x.p such that (x.p,x.r) corresponds to an
492  * ideal on side x.side which is not a bad ideal.
493  * Note: If there is a projective root, it is the largest (r = p by convention)
494  * Return true if such root mod p exists, else non-zero
495  */
496 bool
traditional_get_largest_nonbad_root_mod_p(p_r_side & x) const497 renumber_t::traditional_get_largest_nonbad_root_mod_p (p_r_side & x) const
498 {
499     for(x.side = get_nb_polys(); x.side--; ) {
500         mpz_poly_srcptr f = cpoly->pols[x.side];
501         mpz_srcptr lc = f->coeff[f->deg];
502         p_r_values_t p = x.p;
503         int side = x.side;
504         if (x.p >> lpb[x.side]) continue;
505 
506         if (mpz_divisible_ui_p (lc, p) && !is_bad ({p, p, side})) {
507             x.r = p;
508             return true;
509         }
510 
511         auto roots = mpz_poly_roots(cpoly->pols[side], (unsigned long) p, rstate);
512         renumber_sort_ul (roots.begin(), roots.size()); /* sort in decreasing order */
513         for (auto r : roots) {
514             if (!is_bad ({ (p_r_values_t) p, (p_r_values_t) r, side})) {
515                 x.r = r;
516                 return true;
517             }
518         }
519     }
520     return false;
521 }
522 
523 /* return j such that min <= j <= i, and j maximal, with
524  * traditional_data[j] pointing to a vp value (i.e. one of the rare
525  * values j such that traditional_data[j-1] <= traditional_data[j]
526  * (in the traditional_variant mode, such increases always come in pairs.
527  */
traditional_backtrack_until_vp(index_t i,index_t min,index_t max) const528 index_t renumber_t::traditional_backtrack_until_vp(index_t i, index_t min, index_t max) const
529 {
530     if (format == format_variant) {
531         if (max == std::numeric_limits<index_t>::max())
532             max = traditional_data.size();
533         /* we have conspicuous vp markers are at the positions before all
534          * local maxima of the traditional_data array. But in presence of
535          * large prime gaps, there might be _more_ vp markers.
536          *
537          * If we write - or + depending on whether traditional_data[]
538          * increases (>=) or decreases (<), we have
539          *
540          *  - + + -      Typical case ; previous prime has a non-implicit
541          *     ^         root, and gap with next prime is small.
542          *    - + -      Degenerate case ; previous prime has a no root, and
543          *     ^         gap with previous and next primes are small.
544          *  - + + + + -  These two cases happen when we have one or
545          *     ^   ^     several consecutive large prime gaps.
546          *    - + + + -
547          *     ^   ^
548          */
549         // index_t i0 = i;
550         /* move i to somewhere within an increasing sequence */
551         for( ; i > min && (i + 1 >= max || traditional_data[i+1] < traditional_data[i]) ; --i);
552         /* find the end of the increasing sequence where i was found. */
553         index_t rise_end = i + 1;
554         for( ; rise_end < max ; rise_end++) {
555             if (traditional_data[rise_end] < traditional_data[rise_end - 1])
556                 break;
557         }
558         /* Now find the beginning of the increasing sequence where i was
559          * found.
560          */
561         index_t rise_begin = i;
562         for( ; rise_begin > min ; --rise_begin) {
563             if (traditional_data[rise_begin] < traditional_data[rise_begin-1])
564                 break;
565         }
566         if (((rise_end - rise_begin) & 1) && i == rise_begin) {
567             /* Can occur at most once. */
568             return traditional_backtrack_until_vp(i-1, min, max);
569         }
570         index_t j = rise_end - 2;
571         for( ; j > i ; j -= 2);
572         return j;
573     } else {
574         for( ; i > min && traditional_data[i] < traditional_data[i-1] ; --i);
575     }
576     return i;
577 }
578 
579 /* return the number of bad ideals above x (and therefore zero if
580  * x is not bad). If the ideal is bad, put in the reference [first] the
581  * first index that corresponds to the bad ideals.
582  */
is_bad(index_t & first,p_r_side x) const583 int renumber_t::is_bad (index_t & first, p_r_side x) const
584 {
585     if (x.p > bad_ideals_max_p) return 0;
586 
587     /* bad ideals start after the additional columns in the table. */
588     first = above_add;
589 
590     for (auto const & I : bad_ideals) {
591         if (x == I.first)
592             return I.second.nbad;
593         first += I.second.nbad;
594     }
595     return 0;
596 }
597 
is_bad(p_r_side x) const598 int renumber_t::is_bad (p_r_side x) const
599 {
600     index_t first;
601     return is_bad(first, x);
602 }
603 
is_bad(index_t & first,index_t i) const604 int renumber_t::is_bad (index_t & first, index_t i) const
605 {
606     if (i >= above_bad)
607         return 0;
608     i -= above_add;
609     first = above_add;
610     for (auto const & I : bad_ideals) {
611         index_t n = I.second.nbad;
612         if (i < n) return n;
613         i -= n;
614         first += n;
615     }
616     throw corrupted_table("bad bad ideals");
617 }
618 
619 /* i is in [0..traditional_data.size()) */
traditional_is_vp_marker(index_t i) const620 bool renumber_t::traditional_is_vp_marker(index_t i) const
621 {
622     if (i == traditional_data.size()) return true;
623     if (i == 0) return true;
624     if (format == format_traditional)
625         return traditional_data[i] > traditional_data[i-1];
626     /* regarding the variant case, see the long comment in
627      * traditional_backtrack_until_vp()
628      */
629     return traditional_backtrack_until_vp(i) == i;
630 }
631 
632 
633 /* XXX This is an important part of the index_from lookup. This one needs
634  * to do a dichotomy, one way or another.
635  *
636  * Note that we return the index relative to the internal table, which is
637  * shifted by [[above_bad]] compared to the indices that we return in the
638  * public interface.
639  *
640  * if p is a non-prime, we return a lower bound for the first entry that
641  * is >= p.
642  */
get_first_index_from_p(p_r_values_t p) const643 index_t renumber_t::get_first_index_from_p(p_r_values_t p) const
644 {
645     // p_r_values_t side = x.side;
646     if (p < index_from_p_cache.size()) {
647         index_t i;
648         /* Do this loop so that we can safely return something that is
649          * valid even if p is not a prime.
650          */
651         for( ; ; p++) {
652             if (p >= index_from_p_cache.size())
653                 return get_first_index_from_p(p);
654             i = index_from_p_cache[p];
655             if (i != std::numeric_limits<index_t>::max())
656                 break;
657         }
658         if (format == format_flat) {
659             if (UNLIKELY(i >= flat_data.size()))
660                 throw prime_maps_to_garbage(format, p, i);
661             if (UNLIKELY(flat_data[i][0] != p))
662                 throw prime_maps_to_garbage(format, p, i, flat_data[i][0]);
663         } else {
664             p_r_values_t vp = compute_vp_from_p (p);
665             if (UNLIKELY(i >= traditional_data.size()))
666                 throw prime_maps_to_garbage(format, p, i);
667             if (UNLIKELY(traditional_data[i] != vp))
668                 throw prime_maps_to_garbage(format, p, i, traditional_data[i]);
669         }
670         return i;
671     }
672 
673     /* Note that if lpbmax is > the width of the type, then
674      * check_needed_bits() should have complained already.
675      *
676      * If lpbmax is == the width of the type, then the table fits (if
677      * there's only one non-rational side). But we can't simply check p
678      * >> lpbmax, since the check overflows...
679      *
680      */
681     unsigned int lpbmax = *std::max_element(lpb.begin(), lpb.end());
682     if (lpbmax < (8 * sizeof(p_r_values_t)) && UNLIKELY(p >> lpbmax))
683         throw prime_is_too_large(p);
684 
685     if (format == format_flat) {
686         std::array<p_r_values_t, 2> p0 {{ p, 0 }};
687         auto it = std::lower_bound(flat_data.begin(), flat_data.end(), p0);
688         if (it == flat_data.end())
689             throw prime_is_too_large(p);
690         if ((*it)[0] != p) {
691             /* we can reach here if p is not prime and we simply want a
692              * good lower bound on the entries that are >= p. For this,
693              * std::lower_bound really is the thing that we want.
694              *
695              * Here, (*it)[0] is a prime larger than p. But by the
696              * definition of lower_bound, (*--it)[0] is a prime that
697              * is less than p, and we definitely don't want to return
698              * that. So the good answer is really the thing that is
699              * pointed to by the iterator it.
700              */
701             //throw prime_maps_to_garbage(format, p, i, (*it)[0]);
702         }
703         index_t i = it - flat_data.begin();
704         return i;
705     } else {
706         /* A priori, traditional_data has exactly above_all-above_bad
707          * entries. Except that it holds _only_ in the
708          * format_traditional case, since we insert extra data
709          * in the format_variant case
710          */
711         if (format == format_traditional)
712             ASSERT_ALWAYS(above_all == above_bad + traditional_data.size());
713         index_t max = traditional_data.size();
714         index_t min = above_cache - above_bad;
715         p_r_values_t vp = compute_vp_from_p (p);
716         /* We have to look for i such that tab[i] == vp between min and max. */
717         for( ; max > min ; ) {
718             index_t i = min + (max - min) / 2; /* avoids overflow when
719                                                   min + max >= UMAX(index_t) */
720             i = traditional_backtrack_until_vp(i, min, max);
721             if (traditional_data[i] == vp)
722                 return i;
723             if (traditional_data[i] < vp) {
724                 if (UNLIKELY(i == min)) {
725                     /* This is a corner case. We're below what we're
726                      * looking for, sure, but we're actually looping.
727                      * Need to break the corner case. We'll finish soon
728                      * anyway, because our middle index landed inside the
729                      * range for the smallest p, which is obviously truly
730                      * exceptional.
731                      */
732                     i++;
733                     for( ; i < max && !traditional_is_vp_marker(i) ; i++)
734                         ;
735                     if (traditional_data[i] == vp) return i;
736                 }
737                 min = i;
738             } else {
739                 max = i;
740             }
741         }
742         // see remark above for the flat case.
743         return traditional_backtrack_until_vp(min, 0, max);
744         // throw cannot_find_p(p);
745     }
746 }
747 
index_from_p_r(p_r_side x) const748 index_t renumber_t::index_from_p_r (p_r_side x) const
749 {
750     index_t i;
751     if (is_bad(i, x))
752         return i;
753     if (x.p == 0) {
754         // additional columns. By convention they're attached to p==0.
755         // Note that also by convention/tradition we use only a single
756         // additional column where we have two non-monic sides, in which
757         // case it's only counted on side 0.
758         if (get_nb_polys() == 2 && get_sides_of_additional_columns().size() == 2) {
759             if (x.side == 0)
760                 return 0;
761             throw cannot_find_pr(x);
762         }
763         i = 0;
764         for(auto side : get_sides_of_additional_columns()) {
765             if (side == x.side)
766                 return i;
767             i++;
768         }
769         throw cannot_find_pr(x);
770     }
771     i = get_first_index_from_p(x.p);
772     p_r_values_t vr = compute_vr_from_p_r_side(x);
773 
774     if (format == format_flat) {
775         /* The "flat" format has really simple lookups */
776         for( ; flat_data[i][0] == x.p ; i++) {
777             if (flat_data[i][1] == vr)
778                 return above_bad + i;
779         }
780         throw cannot_find_pr(x);
781     }
782 
783     p_r_values_t vp = traditional_data[i];
784     /* Now i points to the beginning of data for p.
785      *  tab[i] is vp.
786      *  in variant format: then comes j such that the first ideal above p
787      *  actually has index j
788      *  then come the descriptors for all roots mod p
789      */
790 
791     index_t outer_idx;
792     if (format == format_variant) {
793         /* This is the special thing about the "variant" format */
794         outer_idx = above_bad + traditional_data[++i] - vp;
795     } else {
796         outer_idx = above_bad + i;
797     }
798 
799     /* get first vr in the sequence, once we've skipped vp. Note that
800      * if there's no vr at all, i might actually be the next vp already.
801      */
802     i++;
803 
804     /* In the "traditional" format, among all roots, the one with the
805      * largest vr (which is the rational one if there is a rational side)
806      * is actually missing in the table, and replaced by vp. Which makes
807      * for several cases in which we want to return outer_idx
808      * immediately:
809      *  - an ideal on rational side always corresponds to the first
810      *    element of a sequence
811      *  - if i is the last index of the table
812      *  - if the sequence contains only one value
813      *  - if the first sequence element is less than vr
814      */
815     // this first case probably makes no sense in the variant format, as
816     // we'll never use it when there is a rational side.
817     if (x.side == get_rational_side())
818         return outer_idx;
819     if (i == traditional_data.size())
820         return outer_idx;
821     // likewise, in the variant format, vp is not used to store something
822     // implicit, so there's no reason for the sequence that begins with
823     // vp to be empty.
824     if (vp < traditional_data[i])
825         return outer_idx;
826     if (vr > traditional_data[i])
827         return outer_idx;
828     /* otherwise we'll find it eventually. */
829     if (format == format_traditional)
830         outer_idx++;
831     for(unsigned int j = 0 ; traditional_data[i + j] < vp ; j++) {
832         if (vr == traditional_data[i + j])
833             return outer_idx + j;
834     }
835     throw cannot_find_pr(x, vp, vr);
836 }
837 
838 /* This returns the smallest outer index i0 that stores a prime ideal above a
839  * prime >=p0 ; note that p0 does not have to be prime.
840  * This function may return get_max_index() if no prime >= p0 is in the
841  * table.
842  */
index_from_p(p_r_values_t p0) const843 index_t renumber_t::index_from_p(p_r_values_t p0) const
844 {
845     if (p0 >> get_max_lpb())
846         return get_max_index();
847     index_t i;
848     if (p0 < bad_ideals_max_p)
849         i = 0;
850     else
851         i = above_bad + get_first_index_from_p(p0);
852     for(const_iterator it(*this, i) ; it != end() && (*it).p < p0 ; ++it, ++i);
853     return i;
854 }
index_from_p(p_r_values_t p0,int side) const855 index_t renumber_t::index_from_p(p_r_values_t p0, int side) const
856 {
857     index_t i = index_from_p(p0);
858     for(const_iterator it(*this, i) ; it != end() && (*it).side != side ; ++it, ++i);
859     return i;
860 }
861 
iterator_from_p(p_r_values_t p0) const862 renumber_t::const_iterator renumber_t::iterator_from_p(p_r_values_t p0) const
863 {
864     if (p0 >> get_max_lpb())
865         return end();
866     const_iterator it = begin();
867     if (p0 >= bad_ideals_max_p)
868         it.reseat(above_bad + get_first_index_from_p(p0));
869     for( ; it != end() && (*it).p < p0 ; ++it);
870     return it;
871 }
872 
iterator_from_p(p_r_values_t p0,int side) const873 renumber_t::const_iterator renumber_t::iterator_from_p(p_r_values_t p0, int side) const
874 {
875     const_iterator it = iterator_from_p(p0);
876     for( ; it != end() && (*it).side != side ; ++it);
877     return it;
878 }
879 
880 /* This used to be handle_bad_ideals in filter/filter_badideals.cpp ; in
881  * fact, this really belongs here.
882  */
indices_from_p_a_b(p_r_side x,int e,int64_t a,uint64_t b) const883 std::pair<index_t, std::vector<int>> renumber_t::indices_from_p_a_b(p_r_side x, int e, int64_t a, uint64_t b) const
884 {
885     /* We want this interface to be called for bad ideals only.
886      *
887      * A priori we don't need x.r since it can be reocmputed. However,
888      * since in all cases the caller just computed this r a moment ago,
889      * and it's used as a lookup key in the badideals data, let's use it.
890      * x.p and x.side are of course necessary.
891      *
892      */
893 
894     /* bad ideals start after the additional columns in the table. */
895     index_t first = above_add;
896     std::vector<int> exps;
897     for (auto const & I : bad_ideals) {
898         if (x == I.first) {
899             std::vector<int> exps;
900 
901             /* work here, and return */
902             for(auto J : I.second.branches) {
903                 int k = J.k;
904                 p_r_values_t pk = x.p;
905                 for( ; --k ; ) {
906                     p_r_values_t pk1 = pk * x.p;
907                     /* we want to be sure that we don't wrap around ! */
908                     ASSERT_ALWAYS(pk1 > pk);
909                     pk = pk1;
910                 }
911                 p_r_values_t rk = mpz_get_uint64(J.r);
912                 /* rk represents an element in P^1(Z/p^k). Ir rk < pk, it's
913                  * (rk:1), otherwise it's (1:p*(rk-pk)) (I think)
914                  */
915                 p_r_values_t uk = rk;
916                 p_r_values_t vk = 1;
917                 if (rk >= pk) {
918                     uk = 1;
919                     vk = rk - pk;
920                 }
921                 modulusul_t m;
922                 residueul_t ma, mb, muk, mvk;
923                 modul_initmod_ul (m, pk);
924                 modul_init (ma, m);
925                 modul_init (mb, m);
926                 modul_init (muk, m);
927                 modul_init (mvk, m);
928                 modul_set_int64 (ma, a, m);
929                 modul_set_uint64 (mb, b, m);
930                 modul_set_int64  (muk, uk, m);
931                 modul_set_uint64 (mvk, vk, m);
932                 modul_mul(ma, ma, mvk, m);
933                 modul_mul(mb, mb, muk, m);
934                 modul_sub(ma, ma, mb, m);
935                 if (modul_intcmp_ul(ma, 0) == 0) {
936                     /* we found the right ideal ! */
937                     for(int v : J.v) {
938                         if (v >= 0) {
939                             exps.push_back(v);
940                         } else {
941                             ASSERT_ALWAYS(e >= -v);
942                             exps.push_back(e + v);
943                         }
944                     }
945                     return { first, exps };
946                 }
947             }
948             /* then it's a fatal error ! */
949             break;
950         }
951         first += I.second.nbad;
952     }
953     throw cannot_lookup_p_a_b_in_bad_ideals(x, a, b);
954 }
955 
956 /* Scan data[i0..i0+run-1] for a location which encodes precisely index
957  * target_i. the boolean c indicates whether we have a rational side.
958  * i0 is modified by this call, to point to the beginning of the range
959  * where the location was found.
960  */
variant_scan_small_range_forward(std::vector<p_r_values_t> const & data,index_t & i0,index_t target_i,index_t run,bool c)961 static bool variant_scan_small_range_forward(std::vector<p_r_values_t> const & data, index_t & i0, index_t target_i, index_t run, bool c)
962 {
963     for( ; run ; ) {
964         index_t delta = data[i0 + 1] - data[i0];
965         if (delta == target_i) {
966             /* whether or not we have a rational side, we're
967              * definitely spot on.
968              * (if the sequence is a short one, then it makes no sense if
969              * we happen to have a rational side)
970              */
971             ASSERT_ALWAYS(c || run >= 3);
972             return true;
973         }
974         if (run < 2) return false;
975         run -= 2;
976         for(index_t j = i0 + 2 ; run ; j++, run--) {
977             if (data[j] > data[i0]) {
978                 /* Then we have a new vp marker. */
979                 i0 = j;
980                 delta = data[i0 + 1] - data[i0];
981                 break;
982             }
983             /* The delta that is attached to this i depends on
984              * the presence of a rational side.
985              */
986             if (delta + (j-(i0 + 2)) + c == target_i)
987                 return true;
988         }
989     }
990     return false;
991 }
992 
993 /* This takes an index i in the range [0, above_all-above_bad[, and returns
994  * in ii the actual position of the i-th interesting data element in the
995  * traditional_data[] array. i0 is the index of the corresponding vp
996  * marker.
997  */
variant_translate_index(index_t & i0,index_t & ii,index_t i) const998 void renumber_t::variant_translate_index(index_t & i0, index_t & ii, index_t i) const
999 {
1000     index_t max = traditional_data.size();
1001     index_t min = 0;
1002     index_t maxroots = 0;
1003     for(int side = 0 ; side < (int) get_nb_polys() ; side++) {
1004         maxroots += get_poly(side)->deg;
1005     }
1006     /* We have to look for i0 and i1 two consecutive vp markers
1007      * (possibly with i1==max) such that
1008      * traditional_data[i0 + 1] <= i < traditional_data[i1 + 1]
1009      */
1010     for( ; max > min ; ) {
1011         index_t middle = min + (max - min) / 2; /* avoids overflow */
1012         middle = traditional_backtrack_until_vp(middle, min, max);
1013         index_t delta = traditional_data[middle + 1] - traditional_data[middle];
1014         if (middle == min || (delta <= i && delta + maxroots > i)) {
1015             /* got it, probably. need to adjust a little, but that
1016              * will be quick */
1017             i0 = middle;
1018             index_t run = std::min(3 * maxroots, max - i0);
1019             if (variant_scan_small_range_forward(traditional_data,
1020                         i0, i, run, get_rational_side() >= 0))
1021                 break;
1022             throw cannot_find_i(above_bad + i);
1023         } else if (delta < i) {
1024             min = middle;
1025         } else {
1026             max = middle;
1027         }
1028     }
1029     if (min >= max)
1030         throw cannot_find_i(above_bad + i);
1031     index_t vp = traditional_data[i0];
1032     unsigned int di = i - (traditional_data[i0 + 1] - vp);
1033     /* Note that there is no point in using the "variant" format when we
1034      * have a rational side.
1035      */
1036     if (get_rational_side() >= 0) {
1037         ii = di ? i0 + 1 + di : i0;
1038     } else {
1039         ii = i0 + 2 + di;
1040     }
1041 }
1042 
1043 
1044 /* additional columns _must_ be handled differently at this point */
p_r_from_index(index_t i) const1045 renumber_t::p_r_side renumber_t::p_r_from_index (index_t i) const
1046 {
1047     if (i < above_add) {
1048         /* In the special case where we have two non-monic polynomials,
1049          * we have a single additional column, hence above_add=1 and i=0.
1050          * We return {0,0,0} in that case.
1051          */
1052         for(auto side : get_sides_of_additional_columns()) {
1053             if (i-- == 0)
1054                 return { 0, 0, side };
1055         }
1056         throw corrupted_table("bad additional columns");
1057     }
1058     if (i < above_bad) {
1059         i -= above_add;
1060         for (auto const & I : bad_ideals) {
1061             if (i < (index_t) I.second.nbad)
1062                 return I.first;
1063             i -= I.second.nbad;
1064         }
1065         throw corrupted_table("bad bad ideals");
1066     }
1067     i -= above_bad;
1068     if (format == format_flat) {
1069         p_r_values_t p = flat_data[i][0];
1070         p_r_values_t vr = flat_data[i][1];
1071         return compute_p_r_side_from_p_vr(p, vr);
1072     }
1073     if (format == format_traditional) {
1074         index_t i0 = traditional_backtrack_until_vp(i);
1075         index_t vr = traditional_data[i];
1076         index_t vp = traditional_data[i0];
1077         index_t p  = compute_p_from_vp(vp);
1078         if (i == i0) {
1079             /* then we're victims of the "optimization" that uses the same
1080              * value to represent both the implicit root and a projective
1081              * root on the last side. Note that this is not the case when
1082              * we have a rational side.
1083              */
1084             int c = get_rational_side() == -1;
1085             return compute_p_r_side_from_p_vr(p, vr + c);
1086         }
1087         return compute_p_r_side_from_p_vr(p, vr);
1088     }
1089     if (format == format_variant) {
1090         /* That is the annoying part. lookup at i is probably not right. */
1091         index_t i0, ii;
1092         variant_translate_index(i0, ii, i);
1093         p_r_values_t vp = traditional_data[i0];
1094         p_r_values_t vr = traditional_data[ii];
1095         index_t p  = compute_p_from_vp(vp);
1096         return compute_p_r_side_from_p_vr(p, vr);
1097     }
1098     ASSERT_ALWAYS(0);   // cannot reach here.
1099 }
1100 
1101 static uint64_t previous_prime_of_powers_of_2[65] = { 0x0, 0x0, 0x3, 0x7, 0xd,
1102         0x1f, 0x3d, 0x7f, 0xfb, 0x1fd, 0x3fd, 0x7f7, 0xffd, 0x1fff, 0x3ffd,
1103         0x7fed, 0xfff1, 0x1ffff, 0x3fffb, 0x7ffff, 0xffffd, 0x1ffff7, 0x3ffffd,
1104         0x7ffff1, 0xfffffd, 0x1ffffd9, 0x3fffffb, 0x7ffffd9, 0xfffffc7,
1105         0x1ffffffd, 0x3fffffdd, 0x7fffffff, 0xfffffffb, 0x1fffffff7,
1106         0x3ffffffd7, 0x7ffffffe1, 0xffffffffb, 0x1fffffffe7, 0x3fffffffd3,
1107         0x7ffffffff9, 0xffffffffa9, 0x1ffffffffeb, 0x3fffffffff5, 0x7ffffffffc7,
1108         0xfffffffffef, 0x1fffffffffc9, 0x3fffffffffeb, 0x7fffffffff8d,
1109         0xffffffffffc5, 0x1ffffffffffaf, 0x3ffffffffffe5, 0x7ffffffffff7f,
1110         0xfffffffffffd1, 0x1fffffffffff91, 0x3fffffffffffdf, 0x7fffffffffffc9,
1111         0xfffffffffffffb, 0x1fffffffffffff3, 0x3ffffffffffffe5, 0x7ffffffffffffc9,
1112         0xfffffffffffffa3, 0x1fffffffffffffff, 0x3fffffffffffffc7,
1113         0x7fffffffffffffe7, 0xffffffffffffffc5 };
1114 
1115 
check_needed_bits(unsigned int nbits)1116 void check_needed_bits(unsigned int nbits)
1117 {
1118     if (nbits > 8 * sizeof(p_r_values_t))
1119         throw std::overflow_error("p_r_values_t is too small to store ideals, "
1120                 "recompile with FLAGS_SIZE=\"-DSIZEOF_P_R_VALUES=8\"\n");
1121 }
1122 
needed_bits() const1123 unsigned int renumber_t::needed_bits() const
1124 {
1125     /* based on the lpbs and the number of sides, return 32 or 64 */
1126     uint64_t p = previous_prime_of_powers_of_2[get_max_lpb()];
1127     uint64_t vp = vp_from_p(p, get_nb_polys(), get_rational_side() >= 0, format);
1128     if (nbits (vp) <= 32)
1129         return 32;
1130     else
1131         return 64;
1132 }
1133 
set_format(int f)1134 void renumber_t::set_format(int f)
1135 {
1136     ASSERT_ALWAYS (above_all == above_bad);
1137     ASSERT_ALWAYS (above_cache == above_bad);
1138     ASSERT_ALWAYS(f == format_flat || f == format_traditional || f == format_variant);
1139     format = f;
1140 }
1141 
compute_bad_ideals_from_dot_badideals_hint(std::istream & is,unsigned int n)1142 void renumber_t::compute_bad_ideals_from_dot_badideals_hint(std::istream & is, unsigned int n)
1143 {
1144     ASSERT_ALWAYS (format == format_traditional);
1145     ASSERT_ALWAYS (above_all == above_bad);
1146     ASSERT_ALWAYS (above_cache == above_bad);
1147     above_bad = above_add;
1148     bad_ideals_max_p = 0;
1149 
1150     /* the bad ideal computation is per p, so any hints that we'll see
1151      * triggers the insertion of all bad ideals above p. Of course when
1152      * there are multiple bad ideals above the same p, we must do this
1153      * only once.
1154      */
1155     p_r_side latest_x { 0,0,0 };
1156 
1157     for( ; is && n-- ; ) {
1158         p_r_side x;
1159         for(std::string s; std::ws(is).peek() == '#' ; getline(is, s) ) ;
1160         std::string s;
1161         getline(is, s);
1162         if (is.eof() && s.empty()) break;
1163         int rc = sscanf(s.c_str(), "%" SCNpr ",%" SCNpr ":%d:", &x.p, &x.r, &x.side);
1164         if (rc != 3)
1165             throw parse_error("bad ideals", is);
1166 
1167         if (x.same_p(latest_x)) continue;
1168 
1169         mpz_poly_srcptr f = cpoly->pols[x.side];
1170         for(badideal & b : badideals_above_p(f, x.side, x.p)) {
1171             above_bad += b.nbad;
1172             p_r_side xx { (p_r_values_t) mpz_get_ui(b.p), (p_r_values_t) mpz_get_ui(b.r), x.side };
1173             bad_ideals.emplace_back(xx, std::move(b));
1174         }
1175         if (x.p >= bad_ideals_max_p)
1176             bad_ideals_max_p = x.p;
1177         latest_x = x;
1178     }
1179     above_all = above_cache = above_bad;
1180 }
1181 
read_header(std::istream & is)1182 void renumber_t::read_header(std::istream& is)
1183 {
1184     std::ios_base::fmtflags ff = is.flags();
1185     is >> std::dec;
1186 
1187     for(std::string s; std::ws(is).peek() == '#' ; getline(is, s) ) ;
1188 
1189     std::string s;
1190     getline(is, s);
1191     std::istringstream iss(s);
1192     int f;
1193     if (iss >> f && (f == format_flat || f == format_variant)) {
1194         format = f;
1195     } else {
1196         format = format_traditional;
1197         /* We'll re-parse this line according to the rules of the
1198          * traditional format */
1199         iss.str(s);
1200     }
1201 
1202     ASSERT_ALWAYS(above_all == above_add);
1203     if (format == format_traditional) {
1204         unsigned int nbits, nbad, nadd, nonmonic_bitmap, nbpol;
1205         int ratside;
1206         iss >> nbits >> ratside >> nbad >> nadd
1207             >> std::hex >> nonmonic_bitmap
1208             >> std::dec >> nbpol;
1209         for(auto & x : lpb) iss >> x;
1210         if (!iss) throw parse_error("header");
1211         if (::nbits(nonmonic_bitmap) > (int) nbpol)
1212             throw parse_error("header, bad bitmap");
1213         if (above_add == 0 && nadd)
1214             above_add = above_bad = above_cache = above_all = nadd;
1215         if (nbpol != get_nb_polys())
1216             throw std::runtime_error("incompatible renumber table -- mismatch in number of polynomials");
1217         if (nbits != needed_bits())
1218             throw std::runtime_error("incompatible renumber table -- wrong needed_bits");
1219         if (ratside != get_rational_side())
1220             throw std::runtime_error("incompatible renumber table -- different rational_side");
1221         if (nadd != above_add)
1222             throw std::runtime_error("incompatible renumber table -- mismatch in number of additional columns");
1223         compute_bad_ideals_from_dot_badideals_hint(is, nbad);
1224     } else {
1225         // we only have to parse the large prime bounds
1226         for(std::string s; std::ws(is).peek() == '#' ; getline(is, s) ) ;
1227         for(auto & x : lpb) is >> x;
1228         if (!is) throw parse_error("header");
1229         read_bad_ideals(is);
1230     }
1231     is.flags(ff);
1232 
1233     check_needed_bits(needed_bits());
1234 }
1235 
1236 /* This reads the bad ideals section of the new-format renumber file
1237  */
read_bad_ideals(std::istream & is)1238 void renumber_t::read_bad_ideals(std::istream& is)
1239 {
1240     std::ios_base::fmtflags ff = is.flags();
1241 
1242     ASSERT_ALWAYS (format != format_traditional);
1243     ASSERT_ALWAYS (above_all == above_bad);
1244     ASSERT_ALWAYS (above_cache == above_bad);
1245     above_bad = above_add;
1246     bad_ideals_max_p = 0;
1247     for(int side = 0; is && side < (int) get_nb_polys(); side++) {
1248         for(std::string s; std::ws(is).peek() == '#' ; getline(is, s) ) ;
1249         int x, n;
1250         /* The "side, number of bad ideals" is in decimal */
1251         is >> std::dec;
1252         is >> x >> n;
1253         ASSERT_ALWAYS(x == side);
1254         for( ; n-- ; ) {
1255             /* The "p, r", for consistency with the rest of the renumber
1256              * file, are in hex, while the rest of the bad ideal
1257              * description is parsed in decimal. This is enforced by the
1258              * badideal(std::istream &) ctor.
1259              */
1260             is >> std::hex;
1261             badideal b(is);
1262             p_r_side x { (p_r_values_t) mpz_get_ui(b.p), (p_r_values_t) mpz_get_ui(b.r), side };
1263             bad_ideals.emplace_back(x, b);
1264             above_bad += b.nbad;
1265             if (x.p >= bad_ideals_max_p)
1266                 bad_ideals_max_p = x.p;
1267         }
1268     }
1269     above_all = above_cache = above_bad;
1270     if (!is.good())
1271         throw parse_error("header, stream failed after reading bad ideals");
1272     is.flags(ff);
1273 }
1274 
write_header(std::ostream & os) const1275 void renumber_t::write_header(std::ostream& os) const
1276 {
1277     std::ios_base::fmtflags ff = os.flags();
1278     os << std::dec;
1279     /* The traditional format doesn't even accept comments in the very
1280      * first line !
1281      */
1282     if (format == format_traditional) {
1283         // the first line
1284         unsigned long nonmonic_bitmap = 0;
1285         for (unsigned int i = get_nb_polys(); i-- ; ) {
1286             nonmonic_bitmap <<= 1;
1287             nonmonic_bitmap += !mpz_poly_is_monic(cpoly->pols[i]);
1288         }
1289         os << needed_bits()
1290             << " " << get_rational_side()
1291             << " " << bad_ideals.size() // above_bad - above_add
1292             << " " << above_add
1293             << " " << std::hex << nonmonic_bitmap << std::dec
1294             << " " << get_nb_polys();
1295         for(auto x : lpb)
1296             os << " " << x;
1297         os << "\n";
1298     }
1299 
1300     // the comment is never significant. However only the newer formats
1301     // give us the opportunity to stick in a marker for the file format.
1302     // So if we want (for the moment) to provide old-format renumber
1303     // files that can be parsed by old code, we can only convey the
1304     // format information as an (unparsed) side note.
1305     os << "# Renumber file using format " << format << std::endl;
1306 
1307     /* Write the polynomials as comments */
1308     for (unsigned int i = 0; i < get_nb_polys() ; i++) {
1309         os << "# pol" << i << ": "
1310             << cxx_mpz_poly(cpoly->pols[i]).print_poly("x")
1311             << "\n";
1312     }
1313 
1314     if (format != format_traditional) {
1315         os << format << "\n";
1316         // number of additional columns is implicit anyway.
1317         os << "# large prime bounds:\n";
1318         for (unsigned int i = 0; i < get_nb_polys() ; i++) {
1319             if (i) os << " ";
1320             os << lpb[i];
1321         }
1322         os << "\n";
1323     }
1324 
1325     os << "# " << above_add << " additional columns";
1326     if (get_nb_polys() == 2 && get_sides_of_additional_columns().size() == 2)
1327         os << " (combined for both sides)";
1328     os << "\n";
1329     os.flags(ff);
1330 }
1331 
write_bad_ideals(std::ostream & os) const1332 void renumber_t::write_bad_ideals(std::ostream& os) const
1333 {
1334     std::ios_base::fmtflags ff = os.flags();
1335     /* Write first the bad ideal information at the beginning of file */
1336     for(int side = 0; os && side < (int) get_nb_polys(); side++) {
1337         os << "# bad ideals on side " << side << ": ";
1338         {
1339             unsigned int n = 0;
1340             for(auto const & b : bad_ideals) {
1341                 if (b.first.side == side) {
1342                     if (n++) os << "+";
1343                     n++;
1344                     os << b.second.nbad;
1345                 }
1346             }
1347             if (n == 0) os << "not used";
1348         }
1349         os << std::endl;
1350         if (format == format_traditional) {
1351             for(auto const & b : bad_ideals) {
1352                 if (b.first.side == side)
1353                     os << std::hex
1354                         << b.first.p << "," << b.first.r << ":"
1355                         << std::dec
1356                         << b.first.side
1357                         << ": " << b.second.nbad << "\n";
1358             }
1359         } else if (format != format_traditional) {
1360             unsigned int n = 0;
1361             for(auto const & b : bad_ideals)
1362                 if (b.first.side == side) n++;
1363             os << side << " " << n << std::endl;
1364             for(auto const & b : bad_ideals) {
1365                 if (b.first.side == side) {
1366                     // we print p,r in hexa at the beginning of the line,
1367                     // but the rest of the bad ideal information is in
1368                     // decimal.
1369                     os << std::hex << b.second;
1370                 }
1371             }
1372         }
1373     }
1374     os.flags(ff);
1375     os << "# renumber table for all indices above " << above_bad << ":\n";
1376 }
1377 
get_sides_of_additional_columns() const1378 std::vector<int> renumber_t::get_sides_of_additional_columns() const
1379 {
1380     std::vector<int> res;
1381     for(unsigned int side = 0 ; side < get_nb_polys() ; side++) {
1382         mpz_poly_srcptr f = cpoly->pols[side];
1383         if (f->deg > 1 && !mpz_poly_is_monic(f))
1384             res.push_back(side);
1385     }
1386     return res;
1387 }
1388 
use_additional_columns_for_dl()1389 void renumber_t::use_additional_columns_for_dl()
1390 {
1391     ASSERT_ALWAYS(above_all == 0);
1392     above_add = get_sides_of_additional_columns().size();
1393     if (get_nb_polys() == 2 && get_sides_of_additional_columns().size() == 2) {
1394         /* This is a minor optimization. When we have two non-monic
1395          * sides, a single additional column is sufficient.
1396          */
1397         above_add = 1;
1398     }
1399     above_bad = above_add;
1400     above_cache = above_add;
1401     above_all = above_add;
1402 }
1403 
compute_bad_ideals()1404 void renumber_t::compute_bad_ideals()
1405 {
1406     ASSERT_ALWAYS (above_all == above_bad);
1407     ASSERT_ALWAYS (above_cache == above_bad);
1408     /* most useful for traditional format, where we need to do this on
1409      * every open. Well, it's super cheap anyway
1410      *
1411      * Note that in all cases, we also use this function to compute bad
1412      * ideals when we create the table in the first place, from
1413      * freerel.cpp
1414      */
1415     above_bad = above_add;
1416     bad_ideals_max_p = 0;
1417     for(int side = 0 ; side < (int) get_nb_polys() ; side++) {
1418         cxx_mpz_poly f(cpoly->pols[side]);
1419         if (f->deg == 1) continue;
1420         for(auto const & b : badideals_for_polynomial(f, side)) {
1421             p_r_values_t p = mpz_get_ui(b.p);
1422             p_r_values_t r = mpz_get_ui(b.r);
1423             p_r_side x { p, r, side };
1424             bad_ideals.emplace_back(x, b);
1425             above_bad += b.nbad;
1426             if (p >= bad_ideals_max_p)
1427                 bad_ideals_max_p = p;
1428         }
1429     }
1430     above_all = above_cache = above_bad;
1431 }
1432 
use_cooked(p_r_values_t p,cooked & C)1433 void renumber_t::use_cooked(p_r_values_t p, cooked & C)
1434 {
1435     if (C.empty()) return;
1436     /* We must really use above_all - above_bad, and not
1437      * traditional_data.size() + flat_data.size() -- in the
1438      * format_variant case, they're different !
1439      */
1440     index_t pos_hard = traditional_data.size() + flat_data.size();
1441     above_all = use_cooked_nostore(above_all, p, C);
1442     traditional_data.insert(traditional_data.end(), C.traditional.begin(), C.traditional.end());
1443     flat_data.insert(flat_data.end(), C.flat.begin(), C.flat.end());
1444     if (!(p >> RENUMBER_MAX_LOG_CACHED) && p >= index_from_p_cache.size()) {
1445         index_from_p_cache.insert(index_from_p_cache.end(),
1446                 p - index_from_p_cache.size(),
1447                 std::numeric_limits<index_t>::max());
1448         ASSERT_ALWAYS(index_from_p_cache.size() == p);
1449         index_from_p_cache.push_back(pos_hard);
1450         above_cache = above_all;
1451     }
1452 }
use_cooked_nostore(index_t n0,p_r_values_t p MAYBE_UNUSED,cooked & C)1453 index_t renumber_t::use_cooked_nostore(index_t n0, p_r_values_t p MAYBE_UNUSED, cooked & C)
1454 {
1455     if (C.empty()) return n0;
1456     index_t pos_logical = n0 - above_bad;
1457     if (format == format_variant) {
1458         /* This fixup is required by the "variant" format. Well, it's
1459          * actually the whole point... */
1460         ASSERT_ALWAYS(C.traditional.size() >= 2);
1461         C.traditional[1] += pos_logical;
1462         std::ostringstream os;
1463         os << std::hex
1464             << C.traditional[0] << "\n"
1465             << C.traditional[1] << "\n"
1466             << C.text;
1467         C.text = os.str();
1468     }
1469     for(auto n : C.nroots) n0 += n;
1470     return n0;
1471 }
1472 
1473 
read_table(std::istream & is)1474 void renumber_t::read_table(std::istream& is)
1475 {
1476     stats_data_t stats;
1477     uint64_t nprimes = 0; // sigh... *must* be ulong for stats().
1478     stats_init(stats, stdout, &nprimes, 23, "Read", "primes", "", "p");
1479     for(std::string s; std::ws(is).peek() == '#' ; getline(is, s) ) ;
1480     if (format == format_flat) {
1481         for(p_r_values_t p, r ; is >> p >> r ; ) {
1482             flat_data.emplace_back(std::array<p_r_values_t, 2> {{ p, r }});
1483             above_all++;
1484         }
1485     } else {
1486         std::ios_base::fmtflags ff = is.flags();
1487         is >> std::hex;
1488         if (format == format_traditional) {
1489             for(p_r_values_t v ; is >> v ; ) {
1490                 traditional_data.push_back(v);
1491                 above_all++;
1492                 nprimes = above_all;
1493                 if (stats_test_progress(stats))
1494                     stats_print_progress(stats, nprimes, 0, 0, 0);
1495             }
1496         } else if (format == format_variant) {
1497             for(p_r_values_t v, vp = 0 ; is >> v ; ) {
1498                 if (v > vp) {
1499                     above_all -= 2;
1500                     vp = v;
1501                 }
1502                 traditional_data.push_back(v);
1503                 above_all++;
1504                 nprimes = above_all;
1505                 if (stats_test_progress(stats))
1506                     stats_print_progress(stats, nprimes, 0, 0, 0);
1507             }
1508         }
1509         is.flags(ff);
1510     }
1511     stats_print_progress(stats, nprimes, 0, 0, 1);
1512 
1513     if (format == format_traditional || format == format_variant) {
1514         p_r_values_t vp = 0;
1515         index_t i = 0;
1516         index_t logical_adjust = 0;
1517         for( ; i < traditional_data.size() ; i++)  {
1518             p_r_values_t v = traditional_data[i];
1519             if (v <= vp) continue;
1520             vp = v;
1521             p_r_values_t p = compute_p_from_vp(vp);
1522             if (p >> RENUMBER_MAX_LOG_CACHED)
1523                 break;
1524             index_from_p_cache.insert(index_from_p_cache.end(),
1525                     p - index_from_p_cache.size(),
1526                     std::numeric_limits<index_t>::max());
1527             ASSERT_ALWAYS(index_from_p_cache.size() == p);
1528             index_from_p_cache.push_back(i);
1529             if (format == format_variant) {
1530                 i++;
1531                 logical_adjust += 2;
1532             }
1533         }
1534         above_cache = above_bad + i - logical_adjust;
1535     } else {
1536         index_t i = 0;
1537         for( ; i < flat_data.size() ; i++)  {
1538             auto pvr = flat_data[i];
1539             p_r_values_t p = pvr[0];
1540             if (p >> RENUMBER_MAX_LOG_CACHED)
1541                 break;
1542             if (p < index_from_p_cache.size())
1543                 continue;
1544             index_from_p_cache.insert(index_from_p_cache.end(),
1545                     p - index_from_p_cache.size(),
1546                     std::numeric_limits<index_t>::max());
1547             ASSERT_ALWAYS(index_from_p_cache.size() == p);
1548             index_from_p_cache.push_back(i);
1549         }
1550         above_cache = above_bad + i;
1551     }
1552 }
1553 
read_from_file(const char * filename)1554 void renumber_t::read_from_file(const char * filename)
1555 {
1556     ifstream_maybe_compressed is(filename);
1557     read_header(is);
1558     info(std::cout);
1559     read_table(is);
1560     more_info(std::cout);
1561 }
1562 
1563 #if 0
1564 void renumber_t::read_bad_ideals_info(std::istream & is)
1565 {
1566     std::ios_base::fmtflags ff = is.flags();
1567     is >> std::dec;
1568     /* the badidealinfo file of old is slightly annoying to deal with.
1569      */
1570     ASSERT_ALWAYS (above_all == above_bad);
1571     ASSERT_ALWAYS (above_cache == above_bad);
1572     above_bad = above_add;
1573     bad_ideals_max_p = 0;
1574     bad_ideals.clear();
1575     std::map<p_r_side, badideal> met;
1576     for( ; is ; ) {
1577         for(std::string s; std::ws(is).peek() == '#' ; getline(is, s) ) ;
1578         if (is.eof()) break;
1579         p_r_values_t p, rk;
1580         int k, side;
1581         is >> p >> k >> rk >> side;
1582         if (!is) throw corrupted_table("bad bad ideals");
1583         p_r_values_t r = mpz_get_ui(badideal::r_from_rk(p, k, rk));
1584         p_r_side x { p, r, side };
1585         badideal b(p, r);
1586         badideal::branch br;
1587         br.k = k;
1588         br.r = rk;
1589         for(int e ; is >> e ; br.v.push_back(e));
1590         b.nbad = br.v.size();
1591         auto it = met.find(x);
1592         if (it != met.end() && it->second.nbad != b.nbad) {
1593             std::ostringstream os;
1594             os << "badidealinfo file is bad ;"
1595                 << " valuation vector found in branch description"
1596                 << " is not consistent above"
1597                 << "(" << p << ", " << r << ", side " << side << ")";
1598             throw std::runtime_error(os.str());
1599         } else if (it == met.end()) {
1600             met[x] = b;
1601         }
1602         met[x].branches.emplace_back(std::move(br));
1603     }
1604     for(auto const & prb : met) {
1605         p_r_values_t p = prb.first.p;
1606         bad_ideals.emplace_back(prb);
1607         above_bad += prb.second.nbad;
1608         if (p >= bad_ideals_max_p)
1609             bad_ideals_max_p = p;
1610     }
1611     above_all = above_cache = above_bad;
1612     is.flags(ff);
1613 }
1614 #endif
1615 
debug_data(index_t i) const1616 std::string renumber_t::debug_data(index_t i) const
1617 {
1618     p_r_side x = p_r_from_index (i);
1619     std::ostringstream os;
1620 
1621     os << "i=0x" << std::hex << i;
1622 
1623     if (is_additional_column (i)) {
1624         if (get_nb_polys() == 2 && get_sides_of_additional_columns().size() == 2) {
1625             os << " tab[i]=#"
1626                 << " added column for both sides combined";
1627         } else {
1628             os << " tab[i]=#"
1629                 << " added column for side " << std::dec << x.side;
1630         }
1631     } else if (is_bad(i)) {
1632         os << " tab[i]=#"
1633             << " bad ideal";
1634         index_t j = i - above_add;
1635         for(auto const & b : bad_ideals) {
1636             if (j < (index_t) b.second.nbad) {
1637                 os << std::dec
1638                     << " (number " << (1+j) << "/" << b.second.nbad << ")";
1639                 break;
1640             }
1641             j -= b.second.nbad;
1642         }
1643         os  << " above"
1644             << " (" << x.p << "," << x.r << ")"
1645             << " on side " << x.side;
1646     } else {
1647         i -= above_bad;
1648         os << std::hex;
1649         if (format == format_flat) {
1650             os << " tab[i]=";
1651             os << " (0x" << flat_data[i][0] << ",0x" << flat_data[i][1] << ")";
1652         } else if (format == format_variant) {
1653             index_t i0, ii;
1654             variant_translate_index(i0, ii, i);
1655             if (i0 == ii) {
1656                 os << " tab[0x" << i0 << "]=";
1657             } else {
1658                 os << " tab[0x" << i0 << "+1+"
1659                     << std::dec << (ii-(i0+1)) << "]="
1660                     << std::hex;
1661             }
1662             os << "0x" << traditional_data[ii];
1663         } else {
1664             os << " tab[i]=";
1665             os << "0x" << traditional_data[i];
1666         }
1667         os << " p=0x" << x.p;
1668         if (x.side == get_rational_side()) {
1669             os << " rat";
1670             os << " side " << std::dec << x.side;
1671         } else {
1672             os << " r=0x" << x.r;
1673             os << " side " << std::dec << x.side;
1674             if (x.r == x.p)
1675                 os << " proj";
1676         }
1677     }
1678 
1679     return os.str();
1680 }
1681 
1682 /* can be called rather early, in fact (after the bad ideals computation) */
info(std::ostream & os) const1683 void renumber_t::info(std::ostream & os) const
1684 {
1685     const char * P = "# INFO: ";
1686     os << "# Information on renumber table:\n";
1687 
1688     std::string format_string;
1689 
1690     if (format == format_traditional)
1691         format_string = "traditional";
1692     else if (format == format_variant)
1693         format_string = "variant";
1694     else if (format == format_flat)
1695         format_string = "flat";
1696 
1697     os << P << "format = " << format_string << " (" << format << ")\n";
1698     os << P << "sizeof(p_r_values_t) = " << sizeof(p_r_values_t) << "\n";
1699     os << P << "nb_bits = " << needed_bits() << "\n";
1700     os << P << "number of polynomials = " << get_nb_polys() << "\n";
1701     if (get_rational_side() < 0)
1702         os << P << "There is no rational side\n";
1703     else
1704         os << P << "Polynomial on side " << get_rational_side() << " is rational\n";
1705     os << P << "#additional columns = " << above_add;
1706     if (above_add) {
1707         os << ", on sides";
1708         for(auto s : get_sides_of_additional_columns())
1709             os << " " << s;
1710         if (get_nb_polys() == 2 && get_sides_of_additional_columns().size() == 2) {
1711             os << " (one column for both sides combined)";
1712         }
1713     }
1714     os << "\n";
1715     os << P << "#badideals = " << above_bad - above_add
1716         << ", above " << bad_ideals.size() << " (p,r) pairs"
1717         << " [max_p = " << bad_ideals_max_p << "]\n";
1718     for(int side = 0 ; side < (int) get_nb_polys() ; side++) {
1719         os << P << "pol" << side << ": ";
1720         if (mpz_poly_is_monic(get_poly(side)))
1721             os << "monic\n";
1722         else
1723             os << "not monic\n";
1724     }
1725     for(int side = 0 ; side < (int) get_nb_polys() ; side++) {
1726         os << P << "lpb" << side << " = " << lpb[side] << "\n";
1727     }
1728 }
more_info(std::ostream & os) const1729 void renumber_t::more_info(std::ostream & os) const
1730 {
1731     const char * P = "# INFO: ";
1732     os << "# Extra information on renumber table:\n";
1733     os << P << "size = " << get_size() << "\n";
1734 }
1735 
1736 static int builder_switch_lcideals = 0;
builder_configure_switches(cxx_param_list & pl)1737 void renumber_t::builder_configure_switches(cxx_param_list & pl)
1738 {
1739     param_list_configure_switch(pl, "-lcideals", &builder_switch_lcideals);
1740 }
1741 
builder_declare_usage(cxx_param_list & pl)1742 void renumber_t::builder_declare_usage(cxx_param_list & pl)
1743 {
1744     param_list_decl_usage(pl, "renumber", "output file for renumbering table");
1745     param_list_decl_usage(pl, "renumber_format", "format of the renumbering table (\"traditional\", \"variant\", \"flat\")");
1746     param_list_decl_usage(pl, "badideals", "file describing bad ideals (for DL). Only the primes are used, most of the data is recomputed anyway.");
1747     param_list_decl_usage(pl,
1748                           "lcideals",
1749                           "Add ideals for the leading "
1750                           "coeffs of the polynomials (for DL)");
1751 }
1752 
builder_lookup_parameters(cxx_param_list & pl)1753 void renumber_t::builder_lookup_parameters(cxx_param_list & pl)
1754 {
1755     param_list_lookup_string(pl, "renumber");
1756     param_list_lookup_string(pl, "renumber_format");
1757     param_list_lookup_string(pl, "badideals");
1758     param_list_lookup_string(pl, "lcideals");
1759 }
1760 
1761 /* This is the core of the renumber table building routine. Part of this
1762  * code used to exist in freerel.cpp file.
1763  */
1764 struct renumber_t::builder{/*{{{*/
1765     struct prime_chunk {/*{{{*/
1766         bool preprocess_done = false;
1767         std::vector<unsigned long> primes;
1768         std::vector<renumber_t::cooked> C;
prime_chunkrenumber_t::builder::prime_chunk1769         prime_chunk(std::vector<unsigned long> && primes) : primes(primes) {}
1770         private:
1771         prime_chunk() = default;
1772     };/*}}}*/
1773 
1774     renumber_t & R;
1775     std::ostream * os_p;
1776     renumber_t::hook * hook;
1777     stats_data_t stats;
1778     uint64_t nprimes = 0; // sigh... *must* be ulong for stats().
1779     index_t R_max_index; // we *MUST* follow it externally, since we're not storing the table in memory.
builderrenumber_t::builder1780     builder(renumber_t & R, std::ostream * os_p, renumber_t::hook * hook)
1781         : R(R)
1782         , os_p(os_p)
1783         , hook(hook)
1784         , R_max_index(R.get_max_index())
1785     {
1786         /* will print report at 2^10, 2^11, ... 2^23 computed primes
1787          * and every 2^23 primes after that */
1788         stats_init(stats, stdout, &nprimes, 23, "Processed", "primes", "", "p");
1789     }
progressrenumber_t::builder1790     void progress() {
1791         if (stats_test_progress(stats))
1792             stats_print_progress(stats, nprimes, 0, 0, 0);
1793     }
~builderrenumber_t::builder1794     ~builder() {
1795         stats_print_progress(stats, nprimes, 0, 0, 1);
1796     }
1797     index_t operator()();
1798     void preprocess(prime_chunk & P, gmp_randstate_ptr rstate);
1799     void postprocess(prime_chunk & P);
1800 };/*}}}*/
1801 
preprocess(prime_chunk & P,gmp_randstate_ptr rstate)1802 void renumber_t::builder::preprocess(prime_chunk & P, gmp_randstate_ptr rstate)/*{{{*/
1803 {
1804     ASSERT_ALWAYS(!P.preprocess_done);
1805     /* change x (list of input primes) into the list of integers that go
1806      * to the renumber table, and then set "done" to true.
1807      * This is done asynchronously.
1808      */
1809     for(auto p : P.primes) {
1810         std::vector<std::vector<unsigned long>> all_roots;
1811         for (unsigned int side = 0; side < R.get_nb_polys(); side++) {
1812             std::vector<unsigned long> roots;
1813             mpz_poly_srcptr f = R.get_poly(side);
1814 
1815             if (UNLIKELY(p >> R.get_lpb(side))) {
1816                 all_roots.emplace_back(roots);
1817                 continue;
1818             } else if (f->deg == 1) {
1819                 roots.assign(1, 0);
1820             } else {
1821                 /* Note that roots are sorted */
1822                 roots = mpz_poly_roots(f, p, rstate);
1823             }
1824 
1825             /* Check for a projective root ; append it (so that the list of roots
1826              * is still sorted)
1827              */
1828 
1829             if ((int) roots.size() != R.get_poly_deg(side)
1830                     && mpz_divisible_ui_p(f->coeff[f->deg], p))
1831                 roots.push_back(p);
1832 
1833             /* take off bad ideals from the list, if any. */
1834             if (p <= R.bad_ideals_max_p) { /* can it be a bad ideal ? */
1835                 for (size_t i = 0; i < roots.size() ; i++) {
1836                     unsigned long r = roots[i];
1837                     if (!R.is_bad(p, r, side))
1838                         continue;
1839                     /* bad ideal -> remove this root from the list */
1840                     roots.erase(roots.begin() + i);
1841                     i--;
1842                 }
1843             }
1844             all_roots.emplace_back(roots);
1845         }
1846 
1847         /* Data is written in the temp buffer in a way that is not quite
1848          * similar to the renumber table, but still close enough.
1849          */
1850         P.C.emplace_back(R.cook(p, all_roots));
1851     }
1852 #pragma omp atomic write
1853     P.preprocess_done = true;
1854 }/*}}}*/
1855 
postprocess(prime_chunk & P)1856 void renumber_t::builder::postprocess(prime_chunk & P)/*{{{*/
1857 {
1858     ASSERT_ALWAYS(P.preprocess_done);
1859     /* put all entries from x into the renumber table, and also print
1860      * to freerel_file any free relation encountered. This is done
1861      * synchronously.
1862      *
1863      * (if freerel_file is NULL, store only into the renumber table)
1864      */
1865     for(size_t i = 0; i < P.primes.size() ; i++) {
1866         p_r_values_t p = P.primes[i];
1867         renumber_t::cooked & C = P.C[i];
1868 
1869         if (hook) (*hook)(R, p, R_max_index, C);
1870 
1871         if (os_p) {
1872             R_max_index = R.use_cooked_nostore(R_max_index, p, C);
1873             (*os_p) << C.text;
1874         } else {
1875             ASSERT_ALWAYS(R_max_index == R.get_max_index());
1876             R.use_cooked(p, C);
1877             R_max_index = R.get_max_index();
1878         }
1879 
1880         nprimes++;
1881     }
1882     /* free memory ! */
1883     P.primes.clear();
1884     P.C.clear();
1885     progress();
1886 }/*}}}*/
1887 
operator ()()1888 index_t renumber_t::builder::operator()()/*{{{*/
1889 {
1890     /* Generate the renumbering table. */
1891 
1892     constexpr const unsigned int granularity = 1024;
1893 
1894     std::vector<cxx_gmp_randstate> rstate_per_thread(omp_get_max_threads());
1895 #pragma omp parallel default(none) shared(rstate_per_thread)
1896     {
1897 #pragma omp single
1898         {
1899             prime_info pi;
1900             prime_info_init(pi);
1901             std::list<prime_chunk> inflight;
1902             unsigned long lpbmax = 1UL << R.get_max_lpb();
1903             unsigned long p = 2;
1904             for (; p <= lpbmax || !inflight.empty() ;) {
1905                 if (p <= lpbmax) {
1906                     std::vector<unsigned long> pp;
1907                     pp.reserve(granularity);
1908                     for (; p <= lpbmax && pp.size() < granularity;) {
1909                         pp.push_back(p);
1910                         p = getprime_mt(pi); /* get next prime */
1911                     }
1912                     inflight.emplace_back(std::move(pp));
1913                     /* do not use a c++ reference for the omp
1914                      * firstprivate construct. It does not do what we
1915                      * want. (I saw a _copy_ !)
1916                      */
1917                     prime_chunk * latest(&inflight.back());
1918 #pragma omp task firstprivate(latest) default(none) shared(rstate_per_thread)
1919                     {
1920                         preprocess(*latest, rstate_per_thread[omp_get_thread_num()]);
1921                     }
1922                 } else {
1923 #pragma omp taskwait
1924                 }
1925 
1926                 for ( ; !inflight.empty() ; ) {
1927                     bool ready;
1928                     prime_chunk & next(inflight.front());
1929 #pragma omp atomic read
1930                     ready = next.preprocess_done;
1931                     if (!ready)
1932                         break;
1933                     postprocess(next);
1934                     inflight.pop_front();
1935                 }
1936             }
1937             prime_info_clear(pi);
1938         }
1939     }
1940 
1941     return R_max_index;
1942 }/*}}}*/
1943 
build(hook * f)1944 index_t renumber_t::build(hook * f)
1945 {
1946     cxx_param_list pl;
1947     return build(pl, f);
1948 }
1949 
build(cxx_param_list & pl,hook * f)1950 index_t renumber_t::build(cxx_param_list & pl, hook * f)
1951 {
1952     const char * badidealsfilename = param_list_lookup_string(pl, "badideals");
1953     const char * renumberfilename = param_list_lookup_string(pl, "renumber");
1954     const char * format_string = param_list_lookup_string(pl, "renumber_format");
1955 
1956     if (format_string == NULL) {
1957         set_format(format_traditional);
1958     } else if (strcmp(format_string, "traditional") == 0) {
1959         format = format_traditional;
1960     } else if (strcmp(format_string, "variant") == 0) {
1961         format = format_variant;
1962     } else if (strcmp(format_string, "flat") == 0) {
1963         format = format_flat;
1964     } else {
1965         throw std::runtime_error("cannot use this renumber format");
1966     }
1967 
1968     if (builder_switch_lcideals)
1969         use_additional_columns_for_dl();
1970     if (badidealsfilename) {
1971         /* we don't really care about the .badideals file. Except that if
1972          * we have it at hand, we might as well use it as a set of hints
1973          * to avoid the trial division when rediscovering bad ideals.
1974          *
1975          * Note that it's undoubtedly more expensive than the old version
1976          * which was just simply reusing the .badideals file. But we do
1977          * more, here. And anyway we're talking a ridiculous overhead
1978          * compared to the rest of the computation.
1979          */
1980         std::ifstream is(badidealsfilename);
1981         compute_bad_ideals_from_dot_badideals_hint(is);
1982     } else {
1983         /* We can pass some hint primes as well, in a vector */
1984         compute_bad_ideals();
1985     }
1986 
1987     info(std::cout);
1988 
1989     check_needed_bits(needed_bits());
1990 
1991     std::unique_ptr<std::ostream> out;
1992 
1993     if (renumberfilename) {
1994         out.reset(new ofstream_maybe_compressed(renumberfilename));
1995 
1996         write_header(*out);
1997         write_bad_ideals(*out);
1998     }
1999 
2000     index_t ret = builder(*this, out.get(), f)();
2001 
2002     more_info(std::cout);
2003 
2004     return ret;
2005 }
2006 
begin() const2007 renumber_t::const_iterator renumber_t::begin() const
2008 {
2009     return const_iterator(*this, 0);
2010 }
end() const2011 renumber_t::const_iterator renumber_t::end() const
2012 {
2013     return const_iterator(*this, above_bad + traditional_data.size() + flat_data.size());
2014 }
2015 
const_iterator(renumber_t const & table,index_t i)2016 renumber_t::const_iterator::const_iterator(renumber_t const & table, index_t i)
2017     : table(table)
2018       , i(i)
2019 {
2020     reseat(i);
2021 }
2022 
2023 /*
2024 void renumber_t::const_iterator::reseat(index_t new_i0, index_t new_i)
2025 {
2026     i0 = new_i0;
2027     i = new_i;
2028 }
2029 */
2030 
reseat(index_t new_i)2031 void renumber_t::const_iterator::reseat(index_t new_i)
2032 {
2033     i = new_i;
2034     if (i < table.above_bad) {
2035         if (table.is_additional_column(i)) {
2036             i0 = UINT_MAX;
2037             return;
2038         } else if (table.is_bad(i0, i)) {
2039             // ok, fine. i0 is set to exactly what we want.
2040         } else {
2041             throw std::runtime_error("Cannot create iterator");
2042         }
2043     }
2044     if (table.format != format_flat) {
2045         if (i == table.above_bad + table.traditional_data.size()) {
2046             i0 = i;
2047         } else if (i < table.above_bad) {
2048             i0 = i;
2049         } else {
2050             i0 = table.above_bad + table.traditional_backtrack_until_vp(i - table.above_bad);
2051             if (table.format == format_variant && table.get_rational_side() < 0 && i == i0)
2052                 i += 2;
2053         }
2054     } else {
2055         /* flat format doesn't give shit about keeping track of the
2056          * full p range -- so that we _don't_ use i0. */
2057         i0 = UINT_MAX;
2058     }
2059 }
2060 
operator *() const2061 renumber_t::p_r_side renumber_t::const_iterator::operator*() const {
2062     if (i < table.above_add) {
2063         /* See comment in p_r from index about the special case with 2
2064          * non-monic sides */
2065         index_t j = 0;
2066         for(auto side : table.get_sides_of_additional_columns()) {
2067             if (j++ == i)
2068                 return { 0, 0, side };
2069         }
2070     }
2071     if (i < table.above_bad) {
2072         /* annoying. we don't exactly have the pointer to the bad
2073          * ideal, we have to recover it. */
2074         index_t ii0 = i0 - table.above_add;
2075         for(auto const & I : table.bad_ideals) {
2076             if (ii0 == 0)
2077                 return I.first;
2078             ii0 -= I.second.nbad;
2079         }
2080     }
2081     if (i == table.get_max_index()) {
2082         return p_r_side {
2083             std::numeric_limits<p_r_values_t>::max(),
2084             std::numeric_limits<p_r_values_t>::max(),
2085             0 };
2086     }
2087     if (table.format != format_flat) {
2088         p_r_values_t vp = table.traditional_data[i0-table.above_bad];
2089         p_r_values_t vr = table.traditional_data[i-table.above_bad];
2090         p_r_values_t p = table.compute_p_from_vp(vp);
2091         return table.compute_p_r_side_from_p_vr(p, vr);
2092     } else {
2093         p_r_values_t p = table.flat_data[i-table.above_bad][0];
2094         p_r_values_t vr = table.flat_data[i-table.above_bad][1];
2095         return table.compute_p_r_side_from_p_vr(p, vr);
2096     }
2097 }
operator ++(int)2098 renumber_t::const_iterator renumber_t::const_iterator::operator++(int)
2099 {
2100     const_iterator ret = *this;
2101     ++*this;
2102     return ret;
2103 }
operator ++()2104 renumber_t::const_iterator& renumber_t::const_iterator::operator++()
2105 {
2106     if (i < table.above_add) {
2107         ++i;
2108         if (i == table.above_add)
2109             i0 = i;
2110         return *this;
2111     } else if (i < table.above_bad) {
2112         ++i;
2113         if (i == table.above_bad) {
2114             i0 = i;
2115             if (table.format == format_variant && table.get_rational_side() < 0)
2116                 i += 2;
2117             return *this;
2118         } else if (table.is_bad(i0, i)) {
2119             // fine
2120             return *this;
2121         }
2122         throw std::runtime_error("Cannot increase iterator");
2123     }
2124     /* general case */
2125     i++;
2126 
2127     if (table.format == format_flat)
2128         return *this;
2129 
2130     if (i == table.above_bad + table.traditional_data.size()) {
2131         i0 = i;
2132         return *this;
2133     }
2134     p_r_values_t vp = table.traditional_data[i0-table.above_bad];
2135     if (table.format == format_variant && i == i0 + 1) {
2136         // can only happen if we've been crazy enough to test
2137         // the variant format with a rational side defined.
2138         i++;
2139     }
2140     p_r_values_t vr = table.traditional_data[i-table.above_bad];
2141     if (vr > vp) {
2142         i0 = i;
2143         if (table.format == format_variant && table.get_rational_side() < 0)
2144             i += 2;
2145     }
2146     return *this;
2147 }
2148