https://gitlab.inria.fr/cado-nfs/cado-nfs
Tip revision: d5a5c566e3ab7037e0960b1441613062ade661c9 authored by Alexander Kruppa on 29 March 2021, 19:23:48 UTC
Merge branch 'torture_redc_timing' into 'master'
Merge branch 'torture_redc_timing' into 'master'
Tip revision: d5a5c56
reconstructlog.cpp
#include "cado.h" // IWYU pragma: keep
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cinttypes> // for PRIu64, SCNu64
#include <cstdint> // for uint64_t, int32_t, int64_t, uint8_t
#include <pthread.h> // for pthread_mutex_lock, pthread_mutex_unlock
#ifdef HAVE_MINGW
#include <fcntl.h> /* for _O_BINARY */
#endif
#include <gmp.h>
#include "bit_vector.h" // for bit_vector_set, bit_vector, bit_vector_getbit
#include "cado_poly.h" // cado_poly
#include "cxx_mpz.hpp"
#include "filter_io.h" // earlyparsed_relation_ptr
#include "gmp_aux.h" // for nbits, mpz_addmul_si
#include "gzip.h" // fopen_maybe_compressed
#include "macros.h"
#include "memalloc.h" // my_malloc_free_all
#include "mpz_poly.h" // for mpz_poly_setcoeff_int64, mpz_poly, mpz_poly_...
#include "params.h"
#include "purgedfile.h" // purgedfile_read_firstline
#include "renumber.hpp"
#include "sm_utils.h" // sm_side_info_clear
#include "stats.h" // stats_data_t
#include "timing.h" // for wct_seconds
#include "typedefs.h" // for ideal_merge_t, index_t, weight_t, PRid, prime_t
#include "verbose.h" // verbose_decl_usage
#define DEBUG 0
stats_data_t stats; /* struct for printing progress */
/*********************** mutex for multi threaded version ********************/
/* used as mutual exclusion lock for reading the status of logarithms */
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
/**** Relations structure used for computing the logarithms from the rels ****/
typedef struct
{
weight_t nb_unknown;
ideal_merge_t *unknown;
mpz_t log_known_part;
} log_rel_t;
/* Init a table of log_rel_t of size nrels (malloc + all mpz_init) */
static log_rel_t *
log_rel_init (uint64_t nrels)
{
log_rel_t *rels;
uint64_t i;
rels = (log_rel_t *) malloc (nrels * sizeof (log_rel_t));
FATAL_ERROR_CHECK(rels == NULL, "Cannot allocate memory");
memset(rels, 0, nrels * sizeof(log_rel_t));
for (i = 0; i < nrels; i++)
mpz_init(rels[i].log_known_part);
return rels;
}
/* Free what is allocated by log_rel_init */
static void
log_rel_free (log_rel_t *rels, uint64_t nrels)
{
uint64_t i;
my_malloc_free_all();
for (i = 0; i < nrels; i++)
mpz_clear (rels[i].log_known_part);
free(rels);
}
/***** Light relations structure (for constructing the dependency graph) *****/
typedef struct
{
weight_t len;
index_t *needed;
} light_rel;
typedef light_rel *light_rels_t;
/* Init a light_rels_t of size nrels */
static light_rels_t
light_rels_init (uint64_t nrels)
{
light_rels_t rels;
rels = (light_rels_t) malloc (nrels * sizeof (light_rel));
FATAL_ERROR_CHECK(rels == NULL, "Cannot allocate memory");
memset(rels, 0, nrels * sizeof(light_rel));
return rels;
}
/* Free what is allocated by light_rel_init (and during reading for the
* "unknown" array in the light_rel structure */
static void
light_rels_free (light_rels_t rels)
{
my_malloc_free_all();
free(rels);
}
/****************** Struct for the tab of log (mpz_t *) *********************/
struct logtab
{
uint64_t nprimes;
uint64_t nknown;
unsigned int nbsm;
cxx_mpz ell;
cado_poly_srcptr poly;
sm_side_info *sm_info;
private:
mp_limb_t * data;
public:
struct mpz_ro_accessor {
/* This is a ***NON-OWNING*** mpz-like accessor for an integer
* stored somewhere.
*
* A typical construct might be to use this as in:
*
* mpz_addmul(foo, log[i], bar);
*
* here log[i] would create an mpz_ro_accessor object, and then
* call its mpz_srcptr converter (member function below) to
* return an mpz_srcptr that is appropriate to pass to
* mpz_addmul.
*
* The fine point is whether the dtor for the temporary
* mpz_ro_accessor object is called before or after entering the
* mpz_addmul function.
*
* The C++ standard says: after. [C++11 ยง 12.2.3] Namely:
*
* When an implementation introduces a temporary object of a
* class that has a non-trivial constructor (12.1, 12.8), it
* shall ensure that a constructor is called for the
* temporary object. Similarly, the destructor shall be
* called for a temporary with a non-trivial destructor
* (12.4). Temporary objects are destroyed as the last step
* in evaluating the full-expression (1.9) that (lexically)
* contains the point where they were created.
*
* Bottom line: the construct mpz_addmul(foo, log[i], bar) is
* safe. (However mpz_srcptr z = log[i]; followed by
* mpz_addmul(foo, z, bar) is not !)
*/
private:
static inline int mpz_normalized_size(mp_limb_t * p, mp_size_t n) {
for( ; n && p[n-1] == 0 ; n--);
return n;
}
protected:
mpz_t ugly;
public:
/* The following construct would be valid with gmp-6+
* MPZ_ROINIT_N function, but unfortunately MPZ_ROINIT_N sets the
* _mp_alloc field to zero, which gets in the way of our usage in
* the rw_accessor below.
mpz_ro_accessor(logtab const & log, mp_limb_t * place) : ugly MPZ_ROINIT_N(place, mpz_normalized_size(place, mpz_size(log.ell))) {}
*/
mpz_ro_accessor(logtab const & log, mp_limb_t * place) {
ugly->_mp_d = place;
ugly->_mp_alloc = mpz_size(log.ell);
ugly->_mp_size = mpz_normalized_size(place, mpz_size(log.ell));
}
operator mpz_srcptr() const { return ugly; }
};
struct mpz_rw_accessor : public mpz_ro_accessor {
private:
/* This is ***NON-OWNING*** as well, but has operator= which
* carries over to the parent structure */
uint64_t h;
logtab & log;
public:
bool is_known() const { return log.is_known(h); }
mpz_rw_accessor(logtab & log, uint64_t h, mp_limb_t * place) : mpz_ro_accessor(log, place), h(h), log(log) {
}
mpz_rw_accessor& operator=(mpz_srcptr v) {
if (is_known()) {
gmp_fprintf (stderr, "ERROR, inconsistent log for h = %" PRIu64 " ; we previously had %Zd in the database, now we want to store %Zd\n", h,
(mpz_srcptr) *this, v);
ASSERT_ALWAYS (mpz_cmp ((mpz_srcptr) *this, v) == 0);
return *this;
}
if (mpz_cmp_ui (v, 0) < 0)
{
fprintf (stderr, "Warning, log is negative for h = %" PRIu64 "\n", h);
cxx_mpz vv;
mpz_mod(vv, v, log.ell);
(*this) = vv;
} else if (mpz_cmp (v, log.ell) >= 0) {
fprintf (stderr, "Warning, log >= ell for h = %" PRIu64 "\n", h);
cxx_mpz vv;
mpz_mod(vv, v, log.ell);
(*this) = vv;
} else {
ASSERT_ALWAYS(mpz_size(v) <= mpz_size(log.ell));
mpn_zero(ugly->_mp_d, mpz_size(log.ell));
if (mpz_cmp_ui (v, 0) == 0) {
fprintf (stderr, "Warning, log is zero for h = %" PRIu64 "\n", h);
} else {
mpn_copyi(ugly->_mp_d, v->_mp_d, mpz_size(v));
}
// log of SM columns are not taken into account
if (h < log.nprimes)
log.nknown++;
}
return *this;
}
};
private:
uint64_t smlog_index(int side, int idx_sm) const {
uint64_t h = nprimes;
for(int i = 0 ; i < side ; i++) {
h += sm_info[i]->nsm;
}
return h + idx_sm;
}
public:
bool is_zero(uint64_t h) const {
mpz_ro_accessor z = (*this)[h];
return mpz_cmp_ui ((mpz_srcptr) z, 0) == 0;
}
bool is_known(uint64_t h) const {
mpz_ro_accessor z = (*this)[h];
return mpz_cmp ((mpz_srcptr) z, ell) < 0;
}
mpz_ro_accessor operator[](uint64_t h) const {
return mpz_ro_accessor(*this, data + h * mpz_size(ell));
}
mpz_rw_accessor operator[](uint64_t h) {
return mpz_rw_accessor(*this, h, data + h * mpz_size(ell));
}
mpz_ro_accessor smlog(int side, int idx_sm) const {
return (*this)[smlog_index(side, idx_sm)];
}
mpz_rw_accessor smlog(int side, int idx_sm) {
return (*this)[smlog_index(side, idx_sm)];
}
void force_set(uint64_t h, mpz_srcptr v)
{
mp_limb_t * p = data + h * mpz_size(ell);
ASSERT_ALWAYS(mpz_size(v) <= mpz_size(ell));
mpn_zero(p, mpz_size(ell));
mpn_copyi(p, v->_mp_d, mpz_size(v));
}
logtab(cado_poly_srcptr poly, sm_side_info * sm_info, uint64_t nprimes, mpz_srcptr ell)
: nprimes(nprimes)
, poly(poly)
, sm_info(sm_info)
{
mpz_set(this->ell, ell);
nknown = 0;
nbsm = 0;
for(int i = 0 ; i < poly->nb_polys ; i++) {
nbsm += sm_info[i]->nsm;
}
data = (mp_limb_t *) malloc((nprimes + nbsm) * mpz_size(ell) * sizeof(mp_limb_t));
FATAL_ERROR_CHECK(data == NULL, "Cannot allocate memory");
/* set everything to the max value */
memset(data, -1, (nprimes + nbsm) * mpz_size(ell) * sizeof(mp_limb_t));
}
logtab(logtab const &) = delete;
~logtab() { free(data); }
};
/************ Struct used for reading rels files with process_rels ***********/
struct read_data
{
log_rel_t *rels;
logtab & log;
uint64_t nrels;
cado_poly_ptr poly;
sm_side_info *sm_info;
renumber_t & renum_tab;
read_data(logtab & log, uint64_t nrels,
cado_poly_ptr poly, sm_side_info *sm_info,
renumber_t & renum_tab)
: log(log)
, nrels(nrels)
, poly(poly)
, sm_info(sm_info)
, renum_tab(renum_tab)
{
rels = log_rel_init (nrels);
fflush(stdout);
}
read_data(read_data const &) = delete;
~read_data() {
log_rel_free (rels, nrels);
}
};
/************************ Handling of the SMs *******************************/
/* number of SM that must be used. */
/* Callback function called by filter_rels in compute_log_from_rels */
void *
thread_sm (void * context_data, earlyparsed_relation_ptr rel)
{
read_data & data = * (read_data *) context_data;
log_rel_t *lrel = &(data.rels[rel->num]);
mpz_ptr l = lrel->log_known_part;
int64_t a = rel->a;
uint64_t b = rel->b;
uint64_t nonvoidside = 0; /* bit vector of which sides appear in the rel */
if (data.poly->nb_polys > 2) {
for (weight_t i = 0; i < rel->nb; i++) {
index_t h = rel->primes[i].h;
int side = data.renum_tab.p_r_from_index(h).side;
nonvoidside |= ((uint64_t) 1) << side;
}
/* nonvoidside must *not* be a power of two. If it is, then we
* have a nasty problem similar to bug 21707: in a sense, we have
* true gem of a relation that yields a trivial norm on one side,
* but it's really too bad that we have no effective way to check
* for it. */
ASSERT_ALWAYS(nonvoidside & (nonvoidside - 1));
/* one thing we might do at this point is recompute the norm from
* a, b, and data.poly->pols[side], and see if we get \pm1.
*/
} else {
nonvoidside = 3;
}
if (rel->sm_size) {
/* use the SM values which are already present in the input file,
* because some goodwill computed them for us.
*/
int c = 0;
for(int side = 0 ; side < data.poly->nb_polys ; side++) {
sm_side_info_srcptr S = data.sm_info[side];
if (S->nsm > 0 && (nonvoidside & (((uint64_t) 1) << side))) {
#define xxxDOUBLECHECK_SM
#ifdef DOUBLECHECK_SM
/* I doubt that this is really compatible with our
* changes in the SM mode.
*/
mpz_poly u;
mpz_poly_init(u, MAX(1, S->f->deg-1));
mpz_poly_setcoeff_int64(u, 0, a);
mpz_poly_setcoeff_int64(u, 1, -b);
compute_sm_piecewise(u, u, S);
ASSERT_ALWAYS(u->deg < S->f->deg);
ASSERT_ALWAYS(u->deg == S->f->deg - 1);
for(int i = 0 ; i < S->nsm; i++) {
if (S->mode == SM_MODE_LEGACY_PRE2018)
ASSERT_ALWAYS(mpz_cmp(u->coeff[S->f->deg-1-i],rel->sm[c + i
]) == 0);
else
ASSERT_ALWAYS(mpz_cmp(u->coeff[i],rel->sm[c + i]) == 0);
}
#endif
ASSERT_ALWAYS(c + S->nsm <= rel->sm_size);
for(int i = 0 ; i < S->nsm ; i++, c++) {
mpz_addmul(l, data.log.smlog(side, i), rel->sm[c]);
}
mpz_mod(l, l, data.log.ell);
#ifdef DOUBLECHECK_SM
mpz_poly_clear(u);
#endif
}
}
} else {
mpz_srcptr ell = data.log.ell;
for(int side = 0 ; side < data.poly->nb_polys ; side++) {
sm_side_info_srcptr S = data.sm_info[side];
if (S->nsm > 0 && (nonvoidside & (((uint64_t) 1) << side))) {
mpz_poly u;
mpz_poly_init(u, MAX(1, S->f->deg-1));
mpz_poly_setcoeff_int64(u, 0, a);
mpz_poly_setcoeff_int64(u, 1, -b);
compute_sm_piecewise(u, u, S);
ASSERT_ALWAYS(u->deg < S->f->deg);
if (S->mode == SM_MODE_LEGACY_PRE2018) {
for(int i = S->f->deg-1-u->deg; i < S->nsm; i++) {
mpz_addmul (l, data.log.smlog(side, i), u->coeff[S->f->deg-1-i]);
}
} else {
for(int i = 0; i < S->nsm; i++) {
mpz_addmul (l, data.log.smlog(side, i), u->coeff[i]);
}
}
mpz_mod(l, l, ell);
mpz_poly_clear(u);
}
}
}
return NULL;
}
/****************** Computation of missing logarithms ************************/
/* Callback function called by filter_rels in compute_log_from_rels */
void *
thread_insert (void * context_data, earlyparsed_relation_ptr rel)
{
read_data & data = * (read_data *) context_data;
log_rel_t *lrel = &(data.rels[rel->num]);
unsigned int next = 0;
ideal_merge_t buf[REL_MAX_SIZE];
int c = 0;
for (unsigned int i = 0; i < rel->nb; i++)
{
index_t h = rel->primes[i].h;
exponent_t e = rel->primes[i].e;
if (data.log.is_known(h)) {
mpz_addmul_si (lrel->log_known_part, data.log[h], e);
c++;
} else
buf[next++] = (ideal_merge_t) {.id = h, .e = e};
}
if (c) mpz_mod(lrel->log_known_part, lrel->log_known_part, data.log.ell);
lrel->unknown = idealmerge_my_malloc (next);
lrel->nb_unknown = next;
memcpy(lrel->unknown, buf, next * sizeof(ideal_merge_t));
return NULL;
}
/* Return the number of unknown logarithms in the relation.
* rels[i].nb_unknown may not be up-to-date (can only be greater than the actual
* value) */
static inline weight_t
nb_unknown_log (read_data & data, uint64_t i)
{
log_rel_t * lrel = &(data.rels[i]);
weight_t j, k, len = lrel->nb_unknown;
ideal_merge_t *p = lrel->unknown;
int c = 0;
for (j = 0, k = 0; k < len; k++)
{
pthread_mutex_lock (&lock);
bool known = data.log.is_known(p[k].id);
pthread_mutex_unlock (&lock);
if (!known) {
if (j != k)
p[j] = p[k];
j++;
} else { // We know this log, add it to log_know_part
mpz_addmul_si(lrel->log_known_part, data.log[p[k].id], p[k].e);
c++;
}
}
if (c) mpz_mod(lrel->log_known_part, lrel->log_known_part, data.log.ell);
lrel->nb_unknown = j;
return j;
}
/* In a relation with 1 missing logarithm of exponent e, compute its values,
* i.e. compute dest <- (-vlog / e) mod ell
* Return 0 if dest was already known (i.e. computed between the call to
* nb_unknown_log and the call to this functions), return 1 otherwise.
*/
static inline unsigned int
compute_missing_log (logtab::mpz_rw_accessor dest, mpz_t vlog, int32_t e, mpz_t ell)
{
unsigned int ret;
mpz_t tmp;
mpz_init_set_si (tmp, e);
mpz_invert (tmp, tmp, ell);
mpz_neg (vlog, vlog);
mpz_mul (vlog, vlog, tmp);
mpz_mod (tmp, vlog, ell);
pthread_mutex_lock (&lock);
if (dest.is_known()) {
// log was already computed by another thread
ret = 0;
} else {
dest = tmp;
ret = 1;
}
pthread_mutex_unlock (&lock);
mpz_clear (tmp);
return ret;
}
/* Compute all missing logarithms for relations in [start,end[.
* Return the number of computed logarithms */
static uint64_t
log_do_one_part_of_iter (read_data & data, bit_vector not_used, uint64_t start,
uint64_t end)
{
uint64_t i, computed = 0;
for (i = start; i < end; i++)
{
if (bit_vector_getbit(not_used, (size_t) i))
{
weight_t nb = nb_unknown_log (data, i);
if (nb <= 1)
{
bit_vector_clearbit(not_used, (size_t) i);
mpz_ptr vlog = data.rels[i].log_known_part;
if (nb == 0 && mpz_cmp_ui (vlog, 0) != 0)
{
gmp_fprintf (stderr, "Error, no unknown log in rel %" PRIu64 " and sum"
" of log is not zero, sum is: %Zd\n", i, vlog);
exit (EXIT_FAILURE);
}
else if (nb == 1)
{
ideal_merge_t ideal = data.rels[i].unknown[0];
computed +=
compute_missing_log (data.log[ideal.id], vlog, ideal.e,
data.log.ell);
}
}
}
}
return computed;
}
#define log_do_one_iter_mono(d, bv, n) log_do_one_part_of_iter (d, bv, 0, n)
/************************** Dependency graph *********************************/
typedef struct
{
uint8_t state;
uint64_t i;
} node_dep_t;
typedef struct
{
uint64_t size;
node_dep_t *tab;
} graph_dep_t;
/* Macro for state of node_dep_t. UNKNOWN must be 0. */
#define NODE_DEP_LOG_UNKNOWN 0
#define NODE_DEP_LOG_KNOWN_FROM_LOGFILE 1
#define NODE_DEP_LOG_RECONSTRUCTED 2
#define GRAPH_DEP_IS_LOG_UNKNOWN(G, h) (G.tab[h].state == NODE_DEP_LOG_UNKNOWN)
graph_dep_t
graph_dep_init (uint64_t size)
{
node_dep_t *tab = NULL;
tab = (node_dep_t *) malloc (sizeof(node_dep_t) * size);
FATAL_ERROR_CHECK(tab == NULL, "Cannot allocate memory");
memset (tab, 0, sizeof(node_dep_t) * size);
return (graph_dep_t) {.size = size, .tab = tab};
}
void
graph_dep_clear (graph_dep_t G)
{
free(G.tab);
}
/* Set G[h].state accordingly to log[h] values */
void
graph_dep_set_log_already_known (graph_dep_t G, logtab const & log)
{
for (uint64_t h = 0; h < log.nprimes; h++)
{
if (log.is_known(h))
G.tab[h].state = NODE_DEP_LOG_KNOWN_FROM_LOGFILE;
}
}
uint64_t
graph_dep_needed_rels_from_index (graph_dep_t G, index_t h, light_rels_t rels,
bit_vector needed_rels)
{
if (G.tab[h].state == NODE_DEP_LOG_UNKNOWN)
{
fprintf (stderr, "Error: logarithms of %" PRid" cannot be reconstructed "
"from this set of relations. Abort!\n", h);
abort();
}
else if (G.tab[h].state == NODE_DEP_LOG_KNOWN_FROM_LOGFILE)
{
/* We know the wanted logarithm from linear algebra, no new relation is
* necessary */
#if DEBUG >= 1
fprintf (stderr, "DEBUG: h = %" PRid " is known from logfile\n", h);
#endif
return 0;
}
else
{
uint64_t relnum = G.tab[h].i;
bit_vector_setbit (needed_rels, relnum);
uint64_t nadded = 1;
weight_t nb_needed = rels[relnum].len;
#if DEBUG >= 1
fprintf (stderr, "DEBUG: h = %" PRid " can be reconstructed\n", h);
fprintf (stderr, "DEBUG: relation %" PRIu64 " added\n", relnum);
fprintf (stderr, "DEBUG: depends of %u others logs\n", nb_needed-1);
#endif
for (weight_t j = 0; j < nb_needed; j++)
{
index_t hh = rels[relnum].needed[j];
if (!bit_vector_getbit (needed_rels, G.tab[hh].i))
{
nadded += graph_dep_needed_rels_from_index (G, hh, rels, needed_rels);
}
}
return nadded;
}
}
/* Trivial structure containing the data necessary for reading rels for dep. graph */
struct dep_read_data
{
light_rels_t rels;
graph_dep_t G;
dep_read_data(light_rels_t rels, graph_dep_t G) : rels(rels), G(G) {}
};
/* Callback function called by filter_rels in compute_needed_rels */
void *
dep_thread_insert (void * context_data, earlyparsed_relation_ptr rel)
{
dep_read_data & data = * (dep_read_data *) context_data;
light_rels_t lrel = &(data.rels[rel->num]);
unsigned int next = 0;
index_t buf[REL_MAX_SIZE];
for (unsigned int i = 0; i < rel->nb; i++)
{
index_t h = rel->primes[i].h;
if (GRAPH_DEP_IS_LOG_UNKNOWN(data.G, h))
buf[next++] = h;
}
lrel->needed = index_my_malloc (next);
lrel->len = next;
memcpy(lrel->needed, buf, next * sizeof(ideal_merge_t));
return NULL;
}
/* Return the number of unknown logarithms in the relation and put in h the last
* unknown logarithm of the relations (useful when the number of unknown
* logarithms is 1) */
static inline weight_t
dep_nb_unknown_log (dep_read_data & data, uint64_t i, index_t *h)
{
weight_t k, nb;
index_t *p = data.rels[i].needed;
for (nb = 0, k = 0; k < data.rels[i].len; k++)
{
pthread_mutex_lock (&lock);
int unknow = GRAPH_DEP_IS_LOG_UNKNOWN (data.G, p[k]);
pthread_mutex_unlock (&lock);
if (unknow) // we do not know the log if this ideal
{
nb++;
*h = p[k];
}
}
return nb;
}
/* Compute all dependencies for relations in [start,end[.
* Return the number of dependencies found */
static uint64_t
dep_do_one_part_of_iter (dep_read_data & data, bit_vector not_used,
uint64_t start, uint64_t end)
{
uint64_t i, computed = 0;
for (i = start; i < end; i++)
{
if (bit_vector_getbit(not_used, (size_t) i))
{
index_t h = 0; // Placate gcc
weight_t nb = dep_nb_unknown_log(data, i, &h);
if (nb <= 1)
{
bit_vector_clearbit(not_used, (size_t) i);
if (nb == 1)
{
data.G.tab[h].state = NODE_DEP_LOG_RECONSTRUCTED;
data.G.tab[h].i = i;
computed++;
}
}
}
}
return computed;
}
#define dep_do_one_iter_mono(d, bv, n) dep_do_one_part_of_iter (d, bv, 0, n)
/******************** Code for multi thread version **************************/
#define SIZE_BLOCK 1024
typedef struct {
void *data;
bit_vector_ptr not_used;
uint64_t offset;
uint64_t nb;
uint64_t computed;
int version; /* 0 means call dep_* , 1 means call log_* */
} thread_info;
void * thread_start(void *arg)
{
thread_info *ti = (thread_info *) arg;
bit_vector_ptr not_used = ti->not_used;
uint64_t start = ti->offset;
uint64_t end = start + ti->nb;
if (ti->version == 0)
{
dep_read_data & data = * (dep_read_data *) ti->data;
ti->computed = dep_do_one_part_of_iter (data, not_used, start, end);
}
else
{
read_data & data = * (read_data *) ti->data;
ti->computed = log_do_one_part_of_iter (data, not_used, start, end);
}
return NULL;
}
static uint64_t
do_one_iter_mt (void *data, bit_vector not_used, int nt, uint64_t nrels,
int version)
{
// We'll use a rotating buffer of thread id.
pthread_t *threads;
threads = (pthread_t *) malloc( nt * sizeof(pthread_t));
int active_threads = 0; // number of running threads
int threads_head = 0; // next thread to wait / restart.
// Prepare the main loop
uint64_t i = 0; // counter of relation.
uint64_t computed = 0;
// Arguments for threads
thread_info *tis;
tis = (thread_info *) malloc( nt * sizeof(thread_info));
for (int i = 0; i < nt; ++i)
{
tis[i].data = data;
tis[i].not_used = not_used;
tis[i].version = version;
// offset and nb must be adjusted.
}
// Main loop
while ((i < nrels) || (active_threads > 0))
{
// Start / restart as many threads as allowed
if ((active_threads < nt) && (i < nrels))
{
tis[threads_head].offset = i;
tis[threads_head].nb = MIN(SIZE_BLOCK, nrels-i);
pthread_create(&threads[threads_head], NULL,
&thread_start, (void *)(&tis[threads_head]));
i += SIZE_BLOCK;
active_threads++;
threads_head++;
if (threads_head == nt)
threads_head = 0;
continue;
}
// Wait for the next thread to finish in order to print result.
pthread_join(threads[threads_head], NULL);
active_threads--;
computed += tis[threads_head].computed;
// If we are at the end, no job will be restarted, but head still
// must be incremented.
if (i >= nrels)
{
threads_head++;
if (threads_head == nt)
threads_head = 0;
}
}
free(tis);
free(threads);
return computed;
}
/* Compute all missing logarithms possible. Run through all the relations once.
* Multi thread version
* Return the number of computed logarithms */
static inline uint64_t
log_do_one_iter_mt (read_data & d, bit_vector bv, int nt, uint64_t nrels)
{
return do_one_iter_mt ((void *) & d, bv, nt, nrels, 1);
}
/* Compute all missing logarithms possible. Run through all the relations once.
* Multi thread version
* Return the number of computed logarithms */
static inline uint64_t
dep_do_one_iter_mt (dep_read_data & d, bit_vector bv, int nt, uint64_t nrels)
{
return do_one_iter_mt ((void *) & d, bv, nt, nrels, 0);
}
/***************** Important functions called by main ************************/
/* Read the logarithms computed by the linear algebra */
static void
read_log_format_LA (logtab & log, const char *logfile, const char *idealsfile,
sm_side_info *sm_info, int nb_polys)
{
uint64_t i, ncols, col;
index_t h;
mpz_t tmp_log;
FILE *flog = NULL, *fid = NULL;
printf ("# Reading logarithms in LA format from %s\n", logfile);
printf ("# Reading links between matrix columns and ideals from %s\n",
idealsfile);
fflush(stdout);
flog = fopen_maybe_compressed (logfile, "r");
FATAL_ERROR_CHECK(flog == NULL, "Cannot open file for reading logarithms");
fid = fopen_maybe_compressed (idealsfile, "r");
FATAL_ERROR_CHECK(fid == NULL, "Cannot open ideals file");
if (fscanf (fid, "# %" SCNu64 "\n", &ncols) != 1)
{
fprintf(stderr, "Error while reading first line of %s\n", idealsfile);
abort();
}
mpz_init (tmp_log);
i = 0;
stats_init (stats, stdout, &i, nbits(ncols)-5, "Read", "logarithms", "", "logs");
while (fscanf (fid, "%" SCNu64 " %" PRid "\n", &col, &h) == 2)
{
FATAL_ERROR_CHECK (col >= ncols, "Too big value of column number");
FATAL_ERROR_CHECK (h >= log.nprimes, "Too big value of index");
int ret = gmp_fscanf (flog, "%Zd\n", tmp_log);
FATAL_ERROR_CHECK (ret != 1, "Error in file containing logarithms values");
ASSERT_ALWAYS (col == i);
log[h] = tmp_log;
i++;
if (stats_test_progress (stats))
stats_print_progress (stats, i, 0, 0, 0);
}
stats_print_progress (stats, i, 0, 0, 1);
ASSERT_ALWAYS (feof(fid));
ASSERT_ALWAYS (i == ncols);
for(int side = 0; side < nb_polys; side++)
{
for (int ism = 0; ism < sm_info[side]->nsm; ism++)
{
int ret = gmp_fscanf (flog, "%Zd\n", tmp_log);
FATAL_ERROR_CHECK (ret != 1, "Error in file containing logarithms values");
log.smlog(side, ism) = tmp_log;
}
}
/* If we are not at the end of the file, it means that it remains some values
* and we do not know to what "ideals" they correspond. Probably an error
* somewhere, it is better to abort. */
ASSERT_ALWAYS (feof(flog));
for(int side = 0; side < nb_polys; side++)
{
if (sm_info[side]->nsm)
printf ("# Logarithms for %d SM columns on side %d were also read\n",
sm_info[side]->nsm, side);
}
mpz_clear (tmp_log);
fclose_maybe_compressed (flog, logfile);
fclose_maybe_compressed (fid, idealsfile);
}
/* Read the logarithms in output format of reconstructlog */
static void
read_log_format_reconstruct (logtab & log, MAYBE_UNUSED renumber_t const & renumb,
const char *filename)
{
uint64_t nread = 0;
index_t h;
mpz_t tmp_log;
FILE *f = NULL;
int ret;
printf ("# Reading logarithms in reconstruct format from %s\n", filename);
fflush(stdout);
f = fopen_maybe_compressed (filename, "r");
FATAL_ERROR_CHECK(f == NULL, "Cannot open file for reading");
mpz_init (tmp_log);
stats_init (stats, stdout, &nread, nbits(renumb.get_size())-5, "Read", "logarithms", "",
"logs");
for (index_t i = 0; i < renumb.number_of_additional_columns(); i++) {
ret = gmp_fscanf (f, "%" SCNid " added column %Zd\n", &h, tmp_log);
ASSERT_ALWAYS (ret == 2);
ASSERT_ALWAYS (renumb.is_additional_column(h));
nread++;
log[h] = tmp_log;
}
for (index_t i = 0; i < renumb.number_of_bad_ideals(); i++) {
ret = gmp_fscanf (f, "%" SCNid " bad ideals %Zd\n", &h, tmp_log);
ASSERT_ALWAYS (ret == 2);
ASSERT_ALWAYS (renumb.is_bad(h));
nread++;
log[h] = tmp_log;
}
while (gmp_fscanf (f, "%" SCNid " %*" SCNpr " %*d %*s %Zd\n", &h, tmp_log)
== 2)
{
nread++;
log[h] = tmp_log;
if (stats_test_progress (stats))
stats_print_progress (stats, nread, 0, 0, 0);
}
stats_print_progress (stats, nread, 0, 0, 1);
for (unsigned int nsm = 0; nsm < log.nbsm; nsm++)
{
unsigned int n, side;
if (nsm == 0) /* h was already read by previous gmp_fscanf */
{
ret = gmp_fscanf (f, "SM %u %u %Zd\n", &side, &n, tmp_log);
ASSERT_ALWAYS (ret == 3);
}
else
{
ret = gmp_fscanf (f, "%" SCNid " SM %u %u %Zd\n", &h, &side, &n, tmp_log);
ASSERT_ALWAYS (ret == 4);
}
// ASSERT_ALWAYS (n == nsm); // obsolete with new coding
ASSERT_ALWAYS (h == (index_t) nsm + log.nprimes);
log[h] = tmp_log;
}
ASSERT_ALWAYS (feof(f));
mpz_clear (tmp_log);
fclose_maybe_compressed (f, filename);
}
/* Write values of the known logarithms. */
static void
write_log (const char *filename, logtab & log, renumber_t const & tab,
sm_side_info *sm_info)
{
uint64_t i;
FILE *f = NULL;
printf ("# Opening %s for writing logarithms\n", filename);
fflush(stdout);
f = fopen_maybe_compressed (filename, "w");
FATAL_ERROR_CHECK(f == NULL, "Cannot open file for writing");
/* Divide all known logs by 'base' so that the first known non-zero logarithm
* is equal to 1.
* TODO: make a command line argument to choose this 'base'.
*/
int base_already_set = 0;
cxx_mpz base, scaled;
for (i = 0; i < log.nprimes + log.nbsm; i++)
{
if (!log.is_known(i)) continue;
if (log.is_zero(i)) continue;
if (!base_already_set)
{
base_already_set = 1;
/* base = 1/log[i] mod ell */
int ret = mpz_invert (base, log[i], log.ell);
ASSERT_ALWAYS (ret != 0);
mpz_set_ui(scaled, 1);
log.force_set(i, scaled);
}
else
{
mpz_mul (scaled, log[i], base);
mpz_mod (scaled, scaled, log.ell);
log.force_set(i, scaled);
}
}
uint64_t nknown = 0;
stats_init (stats, stdout, &nknown, nbits(tab.get_size())-5, "Wrote",
"known logarithms", "ideals", "logs");
i = 0;
for( ; tab.is_additional_column(i) ; i++) {
if (!log.is_known(i)) continue;
nknown++;
gmp_fprintf (f, "%" PRid " added column %Zd\n", i, (mpz_srcptr) log[i]);
}
for( ; tab.is_bad(i) ; i++) {
if (!log.is_known(i)) continue;
nknown++;
gmp_fprintf (f, "%" PRid " bad ideals %Zd\n", i, (mpz_srcptr) log[i]);
}
for( ; i < tab.get_size(); i++) {
if (!log.is_known(i)) continue;
nknown++;
// TODO forward iterator
renumber_t::p_r_side x = tab.p_r_from_index(i);
if (x.side != tab.get_rational_side())
gmp_fprintf (f, "%" PRid " %" PRpr " %d %" PRpr " %Zd\n",
i, x.p, x.side, x.r, (mpz_srcptr) log[i]);
else
gmp_fprintf (f, "%" PRid " %" PRpr " %d rat %Zd\n",
i, x.p, x.side, (mpz_srcptr) log[i]);
if (stats_test_progress (stats))
stats_print_progress (stats, nknown, i+1, 0, 0);
}
stats_print_progress (stats, nknown, tab.get_size(), 0, 1);
for (unsigned int nsm = 0, i = tab.get_size(); nsm < log.nbsm; nsm++)
{
// compute side
int side, nsm_tot = sm_info[0]->nsm, jnsm = nsm;
for(side = 0; ((int)nsm) >= nsm_tot; side++){
nsm_tot += sm_info[side+1]->nsm;
jnsm -= sm_info[side]->nsm;
}
ASSERT_ALWAYS ((jnsm >= 0) && (jnsm < sm_info[side]->nsm));
if (log.is_zero(i+nsm)) {
printf("# Note: on side %d, log of SM number %d is zero\n", side, jnsm);
} else {
ASSERT_ALWAYS (log.is_known(i+nsm));
}
gmp_fprintf (f, "%" PRid " SM %d %d %Zd\n", i+nsm, side, jnsm,
(mpz_srcptr) log[i+nsm]);
}
uint64_t missing = tab.get_size() - nknown;
printf ("# factor base contains %" PRIu64 " elements\n"
"# logarithms of %" PRIu64 " elements are known (%.1f%%)\n"
"# logarithms of %" PRIu64 " elements are missing (%.1f%%)\n",
tab.get_size(), nknown, 100.0 * nknown / (double) tab.get_size(),
missing, 100.0 * missing / (double) tab.get_size());
fclose_maybe_compressed (f, filename);
ASSERT_ALWAYS (log.nknown == nknown);
}
/* Given a filename, compute all the possible logarithms of ideals appearing in
* the file. Return the number of computed logarithms.
* Modify its first argument bit_vector needed_rels */
static uint64_t
compute_log_from_rels (bit_vector needed_rels,
const char *relspfilename, uint64_t nrels_purged,
const char *relsdfilename, uint64_t nrels_del,
uint64_t nrels_needed, int nt,
read_data & data)
{
double wct_tt0, wct_tt;
uint64_t total_computed = 0, iter = 0, computed;
uint64_t nrels = nrels_purged + nrels_del;
ASSERT_ALWAYS (nrels_needed > 0);
/* Reading all relations */
printf ("# Reading relations from %s and %s\n", relspfilename, relsdfilename);
if (nrels_needed != nrels)
printf ("# Parsing only %" PRIu64 " needed relations out of %" PRIu64 "\n",
nrels_needed, nrels);
#if DEBUG >= 1
printf ("# DEBUG: Using %d thread(s) for thread_sm\n", nt);
#endif
fflush(stdout);
char *fic[3] = {(char *) relspfilename, (char *) relsdfilename, NULL};
/* When purged.gz and relsdel.gz both have SM info included, we may
* have an advantage in having more threads for thread_insert. Note
* though that we'll most probably be limited by gzip throughput */
int ni = 1;
int ns = nt;
if (!filename_matches_one_compression_format(relspfilename) && !filename_matches_one_compression_format(relsdfilename)) {
printf("# Files %s and %s are uncompressed, limiting consumer threads\n",
relspfilename,
relsdfilename);
ns = 4;
}
struct filter_rels_description desc[3] = {
{ .f = thread_insert, .arg=(void*) &data, .n=ni},
{ .f = thread_sm, .arg=(void*) &data, .n=ns},
{ .f = NULL, .arg=0, .n=0}
};
filter_rels2 (fic, desc,
EARLYPARSE_NEED_AB_HEXA |
EARLYPARSE_NEED_INDEX |
EARLYPARSE_NEED_SM, /* It's fine (albeit slow) if we recompute them */
needed_rels, NULL);
/* computing missing log */
printf ("# Starting to compute missing logarithms from rels\n");
/* adjust the number of threads based on the number of needed relations */
double ntm = ceil((nrels_needed + 0.0)/SIZE_BLOCK);
if (nt > ntm)
nt = (int) ntm;
if (nt > 1)
printf("# Using multithread version with %d threads\n", nt);
else
printf("# Using monothread version\n");
wct_tt0 = wct_seconds();
do
{
printf ("# Iteration %" PRIu64 ": starting... [%" PRIu64 " known logs]\n", iter, data.log.nknown);
fflush(stdout);
wct_tt = wct_seconds();
if (nt > 1)
computed = log_do_one_iter_mt (data, needed_rels, nt, nrels);
else
computed = log_do_one_iter_mono (data, needed_rels, nrels);
total_computed += computed;
printf ("# Iteration %" PRIu64 ": %" PRIu64 " new logarithms computed\n",
iter, computed);
printf ("# Iteration %" PRIu64 " took %.1fs (wall-clock time).\n",
iter, wct_seconds() - wct_tt);
iter++;
} while (computed);
printf ("# Computing %" PRIu64 " new logarithms took %.1fs (wall-clock "
"time)\n", total_computed, wct_seconds() - wct_tt0);
size_t c = bit_vector_popcount(needed_rels);
if (c != 0)
fprintf(stderr, "### Warning, %zu relations were not used\n", c);
return total_computed;
}
/* Given a filename, compute all the relations needed to compute the logarithms
* appearing in the file.
* needed_rels should be initialized before calling this function. Its size
* must be nrels_purged + nrels_del.
* Output:
* bit_vector needed_rels, where bits of needed rels are set.
* Return the number of needed_rels.*/
static uint64_t
compute_needed_rels (bit_vector needed_rels,
const char *relspfilename, uint64_t nrels_purged,
const char *relsdfilename, uint64_t nrels_del,
logtab & log, const char *wanted_filename, int nt)
{
double wct_tt0, wct_tt;
uint64_t total_computed = 0, iter = 0, computed;
uint64_t nrels = nrels_purged + nrels_del;
graph_dep_t dep_graph = graph_dep_init (log.nprimes);
light_rels_t rels = light_rels_init (nrels);
graph_dep_set_log_already_known (dep_graph, log);
dep_read_data data(rels, dep_graph);
/* Init bit_vector to remember which relations were already used */
bit_vector_set (needed_rels, 1);
/* Reading all relations */
printf ("# Reading relations from %s and %s\n", relspfilename, relsdfilename);
fflush(stdout);
char *fic[3] = {(char *) relspfilename, (char *) relsdfilename, NULL};
filter_rels (fic, (filter_rels_callback_t) &dep_thread_insert, (void *) &data,
EARLYPARSE_NEED_INDEX, NULL, NULL);
/* computing dependencies */
printf ("# Starting to compute dependencies from rels\n");
/* adjust the number of threads based on the number of relations */
double ntm = ceil((nrels + 0.0)/SIZE_BLOCK);
if (nt > ntm)
nt = (int) ntm;
if (nt > 1)
printf("# Using multithread version with %d threads\n", nt);
else
printf("# Using monothread version\n");
wct_tt0 = wct_seconds();
do
{
printf ("# Iteration %" PRIu64 ": starting...\n", iter);
fflush(stdout);
wct_tt = wct_seconds();
if (nt > 1)
computed = dep_do_one_iter_mt (data, needed_rels, nt, nrels);
else
computed = dep_do_one_iter_mono (data, needed_rels, nrels);
total_computed += computed;
printf ("# Iteration %" PRIu64 ": %" PRIu64 " new dependencies computed\n",
iter, computed);
printf ("# Iteration %" PRIu64 " took %.1fs (wall-clock time).\n",
iter, wct_seconds() - wct_tt);
iter++;
} while (computed);
printf ("# Computing dependencies took %.1fs (wall-clock time)\n",
wct_seconds() - wct_tt0);
FILE *f = NULL;
printf ("# Reading wanted logarithms from %s\n", wanted_filename);
fflush(stdout);
f = fopen_maybe_compressed (wanted_filename, "r");
FATAL_ERROR_CHECK(f == NULL, "Cannot open file for reading");
bit_vector_set (needed_rels, 0);
index_t h;
uint64_t nadded, nrels_necessary = 0, nwanted_log = 0;
wct_tt = wct_seconds();
while (fscanf (f, "%" SCNid "\n", &h) == 1)
{
FATAL_ERROR_CHECK (h >= log.nprimes, "Too big value of index");
printf ("# Computing rels necessary for wanted log %" PRid "\n", h);
fflush(stdout);
nadded = graph_dep_needed_rels_from_index (dep_graph, h, rels, needed_rels);
nrels_necessary += nadded;
printf ("-> %" PRIu64 " needed relations were added (%" PRIu64 " so far)\n",
nadded, nrels_necessary);
nwanted_log++;
}
fclose_maybe_compressed (f, wanted_filename);
printf ("# Reading %" PRIu64 " wanted logarithms took %.1fs\n", nwanted_log,
wct_seconds() - wct_tt);
printf ("# %" PRIu64 " relations are needed to compute these logarithms\n",
nrels_necessary);
ASSERT_ALWAYS (nrels_necessary == bit_vector_popcount (needed_rels));
light_rels_free (rels);
graph_dep_clear (dep_graph);
return nrels_necessary;
}
/********************* usage functions and main ******************************/
static void declare_usage(param_list pl)
{
param_list_decl_usage(pl, "log", "input file containing known logarithms");
param_list_decl_usage(pl, "logformat", "format of input log file: 'LA' or "
"'reconstruct' (default is 'LA')");
param_list_decl_usage(pl, "ell", "group order (see sm -ell parameter)");
param_list_decl_usage(pl, "out", "output file for logarithms");
param_list_decl_usage(pl, "renumber", "input file for renumbering table");
param_list_decl_usage(pl, "poly", "input polynomial file");
param_list_decl_usage(pl, "ideals", "link between matrix cols and ideals "
"(see replay -ideals parameter)");
param_list_decl_usage(pl, "purged", "file with purged relations "
"(see purge -out parameter)");
param_list_decl_usage(pl, "relsdel", "file with relations deleted by purge "
"(see purge -outdel parameter)");
param_list_decl_usage(pl, "nrels", "number of relations (same as purge "
"-nrels parameter)");
param_list_decl_usage(pl, "partial", "do not reconstruct everything "
"that can be reconstructed");
param_list_decl_usage(pl, "sm-mode", "SM mode (see sm-portability.h)");
param_list_decl_usage(pl, "nsm", "number of SM's to add on side 0,1,...");
param_list_decl_usage(pl, "mt", "number of threads (default 1)");
param_list_decl_usage(pl, "wanted", "file containing list of wanted logs");
param_list_decl_usage(pl, "force-posix-threads", "force the use of posix threads, do not rely on platform memory semantics");
param_list_decl_usage(pl, "path_antebuffer", "path to antebuffer program");
verbose_decl_usage(pl);
}
static void
usage (param_list pl, char *argv0)
{
param_list_print_usage(pl, argv0, stderr);
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
char *argv0 = argv[0];
uint64_t nrels_tot = 0, nrels_purged, nrels_del, nrels_needed;
uint64_t nprimes;
int mt = 1;
int partial = 0;
int nsm_arg[NB_POLYS_MAX];
/* negative value means that the value that will be used is the value
* computed later by sm_side_info_init */
for (int side = 0; side < NB_POLYS_MAX; side++)
nsm_arg[side] = -1;
mpz_t ell;
cxx_cado_poly poly;
param_list pl;
param_list_init(pl);
declare_usage(pl);
argv++,argc--;
param_list_configure_switch(pl, "partial", &partial);
param_list_configure_switch(pl, "force-posix-threads", &filter_rels_force_posix_threads);
#ifdef HAVE_MINGW
_fmode = _O_BINARY; /* Binary open for all files */
#endif
if (argc == 0)
usage(pl, argv0);
for( ; argc ; ) {
if (param_list_update_cmdline(pl, &argc, &argv)) { continue; }
fprintf (stderr, "Unknown option: %s\n", argv[0]);
usage(pl, argv0);
}
/* print command-line arguments */
verbose_interpret_parameters(pl);
param_list_print_command_line (stdout, pl);
fflush(stdout);
mpz_init (ell);
const char * logfilename = param_list_lookup_string(pl, "log");
const char * logformat = param_list_lookup_string(pl, "logformat");
const char * idealsfilename = param_list_lookup_string(pl, "ideals");
const char * relsdfilename = param_list_lookup_string(pl, "relsdel");
const char * relspfilename = param_list_lookup_string(pl, "purged");
const char * outfilename = param_list_lookup_string(pl, "out");
const char * renumberfilename = param_list_lookup_string(pl, "renumber");
const char * polyfilename = param_list_lookup_string(pl, "poly");
const char * wantedfilename = param_list_lookup_string(pl, "wanted");
param_list_parse_int(pl, "mt", &mt);
const char *path_antebuffer = param_list_lookup_string(pl, "path_antebuffer");
/* Some checks on command line arguments */
if (!param_list_parse_mpz(pl, "ell", ell) || mpz_cmp_ui (ell, 0) <= 0)
{
fprintf(stderr, "Error, missing -ell command line argument "
"(or ell <= 0)\n");
usage (pl, argv0);
}
if (!param_list_parse_uint64(pl, "nrels", &nrels_tot) || nrels_tot == 0)
{
fprintf(stderr, "Error, missing -nrels command line argument "
"(or nrels = 0)\n");
usage (pl, argv0);
}
if (logfilename == NULL)
{
fprintf(stderr, "Error, missing -log command line argument\n");
usage (pl, argv0);
}
if (relspfilename == NULL)
{
fprintf(stderr, "Error, missing -purged command line argument\n");
usage (pl, argv0);
}
if (relsdfilename == NULL)
{
fprintf(stderr, "Error, missing -relsdel command line argument\n");
usage (pl, argv0);
}
if (outfilename == NULL)
{
fprintf(stderr, "Error, missing -out command line argument\n");
usage (pl, argv0);
}
if (renumberfilename == NULL)
{
fprintf(stderr, "Error, missing -renumber command line argument\n");
usage (pl, argv0);
}
if (polyfilename == NULL)
{
fprintf(stderr, "Error, missing -poly command line argument\n");
usage (pl, argv0);
}
if (mt < 1)
{
fprintf(stderr, "Error: parameter mt must be at least 1\n");
usage (pl, argv0);
}
if (logformat != NULL)
{
if (strcmp(logformat, "LA") != 0 && strcmp(logformat, "reconstruct") != 0)
{
fprintf(stderr, "Error, unknown -formatlog argument. Must be 'LA' or "
"'reconstruct'\n");
usage (pl, argv0);
}
}
if ((logformat == NULL || strcmp(logformat, "LA") == 0) &&
idealsfilename == NULL)
{
fprintf(stderr, "Error, missing -ideals command line argument\n");
usage (pl, argv0);
}
if (wantedfilename != NULL && !partial)
{
fprintf(stderr, "Warning, -wanted command line argument is ignored if "
"-partial is not set\n");
}
if (!cado_poly_read (poly, polyfilename))
{
fprintf (stderr, "Error reading polynomial file\n");
exit (EXIT_FAILURE);
}
/* Read number of sm to be printed from command line */
param_list_parse_int_list (pl, "nsm", nsm_arg, poly->nb_polys, ",");
for(int side = 0; side < poly->nb_polys; side++)
{
if (nsm_arg[side] > poly->pols[side]->deg)
{
fprintf(stderr, "Error: nsm%d=%d can not exceed the degree=%d\n",
side, nsm_arg[side], poly->pols[side]->deg);
exit (EXIT_FAILURE);
}
}
const char * sm_mode_string = param_list_lookup_string(pl, "sm-mode");
if (param_list_warn_unused(pl))
{
fprintf(stderr, "Error, unused parameters are given\n");
usage(pl, argv0);
}
set_antebuffer_path (argv0, path_antebuffer);
/* Init data for computation of the SMs. */
sm_side_info sm_info[NB_POLYS_MAX];
for (int side = 0; side < poly->nb_polys; side++)
{
sm_side_info_init(sm_info[side], poly->pols[side], ell);
sm_side_info_set_mode(sm_info[side], sm_mode_string);
fprintf(stdout, "\n# Polynomial on side %d:\n# F[%d] = ", side, side);
mpz_poly_fprintf(stdout, poly->pols[side]);
printf("# SM info on side %d:\n", side);
sm_side_info_print(stdout, sm_info[side]);
if (nsm_arg[side] >= 0)
sm_info[side]->nsm = nsm_arg[side]; /* command line wins */
printf("# Will use %d SMs on side %d\n", sm_info[side]->nsm, side);
/* do some consistency checks */
if (sm_info[side]->unit_rank != sm_info[side]->nsm)
{
fprintf(stderr, "# On side %d, unit rank is %d, computing %d SMs ; "
"weird.\n", side, sm_info[side]->unit_rank,
sm_info[side]->nsm);
/* for the 0 case, we haven't computed anything: prevent the
* user from asking SM data anyway */
ASSERT_ALWAYS(sm_info[side]->unit_rank != 0);
}
}
fflush(stdout);
/* Reading renumber file */
/* XXX legacy format insists on getting the badidealinfo file */
printf ("\n###### Reading renumber file ######\n");
renumber_t renumber_table(poly);
renumber_table.read_from_file(renumberfilename);
nprimes = renumber_table.get_size();
/* Read number of rows and cols on first line of purged file */
{
uint64_t nideals_purged;
purgedfile_read_firstline (relspfilename, &nrels_purged, &nideals_purged);
nrels_del = nrels_tot - nrels_purged;
}
/* Malloc'ing log tab and reading values of log */
printf ("\n###### Reading known logarithms ######\n");
fflush(stdout);
logtab log(poly, sm_info, nprimes, ell);
if (logformat == NULL || strcmp(logformat, "LA") == 0)
read_log_format_LA (log, logfilename, idealsfilename, sm_info,
poly->nb_polys);
else
read_log_format_reconstruct (log, renumber_table, logfilename);
/* Init bit_vector of rels that must be process by compute_log_from_rels */
bit_vector rels_to_process;
bit_vector_init (rels_to_process, nrels_tot);
if (partial)
{
if (wantedfilename == NULL)
{
bit_vector_set (rels_to_process, 0);
nrels_needed = 0;
}
else /* We compute needed rels for logarithms in wantedfilename */
{
printf ("\n###### Computing needed rels ######\n");
nrels_needed =
compute_needed_rels (rels_to_process, relspfilename, nrels_purged,
relsdfilename, nrels_del, log, wantedfilename, mt);
}
}
else
{
bit_vector_set (rels_to_process, 1);
nrels_needed = nrels_tot;
}
/* Computing logs using rels in purged file */
printf ("\n###### Computing logarithms using rels ######\n");
if (nrels_needed > 0)
{
read_data data(log, nrels_purged + nrels_del, poly, sm_info,
renumber_table);
compute_log_from_rels (rels_to_process, relspfilename,
nrels_purged, relsdfilename,
nrels_del, nrels_needed, mt,
data);
printf ("# %" PRIu64 " logarithms are known.\n", log.nknown);
extern double m_seconds;
fprintf(stderr, "# %.2f\n", m_seconds);
}
else
printf ("# All wanted logarithms are already known, skipping this step\n");
fflush(stdout);
/* Writing all the logs in outfile */
printf ("\n###### Writing logarithms in a file ######\n");
write_log (outfilename, log, renumber_table, sm_info);
/* freeing and closing */
mpz_clear(ell);
for (int side = 0 ; side < poly->nb_polys ; side++)
sm_side_info_clear (sm_info[side]);
bit_vector_clear(rels_to_process);
param_list_clear (pl);
return EXIT_SUCCESS;
}