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