1 #include "cado.h" // IWYU pragma: keep
2 #include <cerrno> // for errno
3 #include <cstdlib> // for exit, free, strtoul, EXIT_FAILURE
4 #include <cstring> // for strdup
5 #include <cctype> // for isspace
6 #include <cstdint> // for uint64_t
7 #include <cstdio> // for fprintf, NULL, stderr, fclose, fgets, fopen, FILE
8 #include "las-dlog-base.hpp"
9 #include "las-multiobj-globals.hpp"
10 #include "macros.h" // for ASSERT_ALWAYS
11 #include "typedefs.h" // for index_t
12 #include "params.h" // param_list_parse_*
13 #include "portability.h" // strdup // IWYU pragma: keep
14 #include "verbose.h" // verbose_output_print
15
declare_usage(cxx_param_list & pl)16 void las_dlog_base::declare_usage(cxx_param_list & pl)
17 {
18 if (!dlp_descent) return;
19 param_list_decl_usage(pl, "renumber", "renumber table (for the descent)");
20 param_list_decl_usage(pl, "log", "log table, as built by reconstructlog");
21 /* These belong to las-siever-config of course. But we do a lookup
22 * from here as well.
23 */
24 param_list_decl_usage(pl, "lpb0", "set large prime bound on side 0 to 2^lpb0");
25 param_list_decl_usage(pl, "lpb1", "set large prime bound on side 1 to 2^lpb1");
26 }
27
las_dlog_base(cxx_cado_poly const & cpoly,cxx_param_list & pl)28 las_dlog_base::las_dlog_base(cxx_cado_poly const & cpoly, cxx_param_list & pl)
29 : cpoly(cpoly)
30 , renumber_table(cpoly)
31 {
32 if (!dlp_descent) return;
33 renumberfilename = NULL;
34 logfilename = NULL;
35 const char * tmp;
36 if ((tmp = param_list_lookup_string(pl, "renumber")) != NULL) {
37 renumberfilename = strdup(tmp);
38 }
39 if ((tmp = param_list_lookup_string(pl, "log")) != NULL) {
40 logfilename = strdup(tmp);
41 }
42 if (!logfilename != !renumberfilename) {
43 fprintf(stderr, "In descent mode, want either renumber+log, or none\n");
44 exit(EXIT_FAILURE);
45 }
46 if (!param_list_parse_ulong(pl, "lpb0", &(lpb[0]))) {
47 fprintf(stderr, "In descent mode, want lpb0 for the final descent\n");
48 exit(EXIT_FAILURE);
49 }
50 if (!param_list_parse_ulong(pl, "lpb1", &(lpb[1]))) {
51 fprintf(stderr, "In descent mode, want lpb1 for the final descent\n");
52 exit(EXIT_FAILURE);
53 }
54 read();
55 }
56
~las_dlog_base()57 las_dlog_base::~las_dlog_base()
58 {
59 if (!dlp_descent) return;
60 free(renumberfilename);
61 free(logfilename);
62 }
63
is_known(int side,p_r_values_t p,p_r_values_t r) const64 bool las_dlog_base::is_known(int side, p_r_values_t p, p_r_values_t r) const
65 {
66 ASSERT_ALWAYS(dlp_descent);
67 // if p is above large prime bound, its log is not known.
68 if (lpb[side] >= 64)
69 return false;
70 if (p >> lpb[side]) {
71 return false;
72 }
73 if (renumberfilename) {
74 /* For now we assume that we know the log of all bad ideals */
75 /* If we want to be able to do a complete lookup for bad ideals,
76 * then we need to use
77 * renumber_table.indices_from_p_a_b
78 * which needs a,b as well.
79 */
80 if (renumber_table.is_bad ({ p, r, side }))
81 return true;
82 index_t h = renumber_table.index_from_p_r({ p, r, side });
83 return known_logs[h];
84 }
85 return true;
86 }
87
88
read()89 void las_dlog_base::read()
90 {
91 ASSERT_ALWAYS(dlp_descent);
92 if (!renumberfilename) {
93 verbose_output_print(0, 1, "# Descent: no access to renumber table given, using lpb(%lu/%lu) to decide what are the supposedly known logs\n",
94 lpb[0], lpb[1]);
95 return;
96 }
97
98 verbose_output_print(0, 1, "# Descent: will get list of known logs from %s, using also %s for mapping\n", logfilename, renumberfilename);
99
100 renumber_table.read_from_file(renumberfilename);
101
102 for(int side = 0 ; side < 2 ; side++) {
103 if (lpb[side] != renumber_table.get_lpb(side)) {
104 fprintf(stderr, "lpb%d=%lu different from lpb%d=%u stored in renumber table, probably a bug\n", side, lpb[side], side, renumber_table.get_lpb(side));
105 exit(EXIT_FAILURE);
106 }
107 }
108
109 uint64_t nprimes = renumber_table.get_size();
110 known_logs.assign(nprimes + 32, false);
111 /* 32 is because the SM columns are here, too ! We would like to
112 * avoid reallocation, so let's be generous (anyway we'll
113 * reallocate if needed)
114 */
115
116 /* format of the log table: there are FIVE different line types.
117 *
118 * [index] added column [log]
119 * [index] bad ideals [log]
120 * [index] [p] [side] rat [log]
121 * [index] [p] [side] [r] [log]
122 * [index] SM col [i] [log]
123 * where by default side=0 means the rational side, side=1 the algebraic one
124 * r is the root of f(x) mod p, where f is the algebraic polynomial
125 * log is the virtual logarithm
126 * (see https://lists.gforge.inria.fr/pipermail/cado-nfs-discuss/2019-February/000998.html)
127 *
128 * Here we care only about the index anyway. By the way, this index
129 * is written in hex.
130 */
131 FILE * f = fopen(logfilename, "r");
132 ASSERT_ALWAYS(f != NULL);
133 size_t nlogs=0;
134 for(int lnum = 0 ; ; lnum++) {
135 char line[1024];
136 char * x = fgets(line, sizeof(line), f);
137 if (x == NULL) break;
138 for( ; *x && isspace(*x) ; x++) ;
139 if (*x == '#') continue;
140 if (!*x) continue;
141 errno=0;
142 unsigned long z = strtoul(x, &x, 16);
143 if (errno) {
144 fprintf(stderr, "Parse error at line %d in %s: %s\n", lnum, logfilename, line);
145 break;
146 }
147 if (z >= known_logs.size()) {
148 /* happens for SM columns: we have more than the size of the
149 * renumber table ! */
150 known_logs.resize(z + 1);
151 }
152 nlogs+=!known_logs[z];
153 known_logs[z] = true;
154 }
155 fclose(f);
156 verbose_output_print(0, 1, "# Got %zu known logs from %s\n", nlogs, logfilename);
157 }
158
159
160