Revision 0493cb82f256ff6d122b63d0b5226908965ec87f authored by Paul Zimmermann on 17 February 2014, 16:32:26 UTC, committed by Paul Zimmermann on 17 February 2014, 16:32:26 UTC
1 parent 9caacb8
Raw File
reconstructlog.c
#include "cado.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>   /* for _O_BINARY */

#include "filter_common.h"

#ifdef FOR_FFS
#include "utils-ffs.h"
#endif
#define DEBUG 0

/* 2 functions to compute a <- (a + l*e) mod q (e is either int32_t or mpz_t) */
static inline void
mpz_add_log_mod_si (mpz_t a, mpz_t l, int32_t e, mpz_t q)
{
  if (e > 0)
    mpz_addmul_ui (a, l, e);
  else
    mpz_submul_ui (a, l, -e);
  mpz_mod (a, a, q);
}

static inline void
mpz_add_log_mod_mpz (mpz_ptr a, mpz_t l, mpz_t e, mpz_t q)
{
  mpz_t t;
  mpz_init(t);
  mpz_mul(t, l, e);  // t <- l*e
  mpz_mod(t, t, q);  // t <- l*e mod q
  mpz_add(t, a, t);  // t <- l*e mod q + a
  mpz_mod (a, t, q); // a <- (a+l*e) mod q
  mpz_clear(t);
}

/* Structure for a relation */
typedef struct
{
  weight_t nb_unknown;
  ideal_merge_t *unknown;
  mpz_t log_known_part;
  int64_t a;
  uint64_t b;
} 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);
}

/* Structure containing the data for the reading of a relation file */
typedef struct
{
  log_rel_t *rels;
  int32_t *w;
  mpz_t *log;
  mpz_ptr q;
  uint64_t nideals;

} read_data_t;

/* Init a read_data_t structure for nrels rels and nprimes primes. Assume the
 * table of log is already allocated, but not the table of log_rel_t     */
static void
read_data_init (read_data_t *data, mpz_t *log, mpz_t q, uint64_t nprimes,
                uint64_t nrels)
{
  data->w = (int32_t *) malloc (nprimes * sizeof(int32_t));
  FATAL_ERROR_CHECK (data->w == NULL, "Cannot allocate memory");
  memset(data->w, 0, nprimes * sizeof(int32_t));
  data->rels = log_rel_init(nrels);
  data->log = log;
  data->q = q;
  data->nideals = 0;
}

static void
read_data_free (read_data_t *data, uint64_t nrels)
{
  free(data->w);
  log_rel_free (data->rels, nrels);
}

#ifndef FOR_FFS /* Not needed for FFS */
/* Structure with all the constant needed for the computation of SM. Results is
 * written in poly_t SM. */
typedef struct
{
  unsigned int nbsm;
  mpz_poly_ptr F;
  mpz_t *smlog;
  mpz_ptr smexp; /* exponent for SM */
  mpz_ptr q;
  mpz_t q2;    /* q^2 */
  mpz_t invq2;
} sm_data_t;

/* Init the sm_data_t structure, given the polynomial, the group order and the
 * exponent */
static void
sm_data_init (sm_data_t *d, unsigned int nbsm, mpz_poly_t F, mpz_t q, mpz_t smexp,
              mpz_t *log, uint64_t nprimes)
{
  d->nbsm = nbsm;
  d->F = F;
  d->q = q;
  d->smexp = smexp;

  mpz_init(d->q2);
  mpz_mul(d->q2, q, q);

  mpz_init(d->invq2);
  barrett_init(d->invq2, d->q2);

  d->smlog = &(log[nprimes]);
}

static void
sm_data_free (sm_data_t *d)
{
  mpz_clear(d->q2);
  mpz_clear(d->invq2);
}

/* Given a and b, compute the SM and add the contribution to l */
static inline void
add_sm_contribution (mpz_ptr l, sm_data_t *sm, int64_t a, uint64_t b)
{
  mpz_poly_t SMres;
  mpz_poly_init(SMres, sm->F->deg);
  SMres->deg = 0;
  mpz_poly_setcoeff_si(SMres, 0, 1);
  sm_single_rel(SMres, a, b, sm->F, sm->smexp, sm->q, sm->q2, sm->invq2);
  unsigned int i;
  for (i = 0; i < sm->nbsm && i <= (unsigned int) SMres->deg; i++)
    mpz_add_log_mod_mpz (l, sm->smlog[i], SMres->coeff[i], sm->q);
  mpz_poly_clear(SMres);
}
#endif /* ifndef FOR_FFS */

/* Read the index file produced by replay (needed to read the logarithms)*/
static index_t *
read_index (const char *filename, uint64_t *ncols, uint64_t nprimes)
{
  FILE *f = NULL;
  uint64_t nbread = 0, i, j;
  index_t *tab = NULL;

  double tt = seconds();
  printf ("# Reading ideals file from %s\n", filename);
  fflush(stdout);
  f = fopen_maybe_compressed (filename, "r");
  FATAL_ERROR_CHECK(f == NULL, "Cannot open file for reading");

  if (fscanf (f, "# %" SCNu64 "\n", ncols) != 1)
  {
    fprintf(stderr, "Error while reading first line of %s\n", filename);
    exit(EXIT_FAILURE);
  }

  tab = (index_t *) malloc (*ncols * sizeof (index_t));
  FATAL_ERROR_CHECK(tab == NULL, "Cannot allocate memory");

  while (fscanf (f, "%" SCNu64 " %" SCNx64 "\n", &i, &j) == 2)
  {
    FATAL_ERROR_CHECK (i >= *ncols, "Too big value of column number");
    FATAL_ERROR_CHECK (j >= nprimes, "Too big value of index");
    tab[i] = j;
    nbread++;
  }

  FATAL_ERROR_CHECK (nbread != *ncols, "Not enough or too many index read");
  fclose_maybe_compressed (f, filename);
  printf ("# Reading %" PRIu64 " index took %.1fs\n", nbread, seconds() - tt);
  return tab;
}

/* Read the logarithms computed by the linear algebra */
static mpz_t *
read_log (index_t *mat_renum, const char *filename, mpz_t q, unsigned int nbsm,
          uint64_t ncols, uint64_t nprimes)
{
  uint64_t i;
  mpz_t tmp_log, *log = NULL;
  FILE *f = NULL;

  double tt = seconds();
  printf ("# Reading logarithms computed by LA from %s\n", filename);
  fflush(stdout);
  f = fopen_maybe_compressed (filename, "r");
  FATAL_ERROR_CHECK(f == NULL, "Cannot open file for reading");

  log = (mpz_t *) malloc ((nprimes + nbsm) * sizeof(mpz_t));
  FATAL_ERROR_CHECK(log == NULL, "Cannot allocate memory");
  size_t q_nbits = mpz_size(q) * GMP_LIMB_BITS;
  for (i = 0; i < nprimes + nbsm; i++)
  {
    mpz_init2 (log[i], q_nbits);
    mpz_set_si(log[i], -1);
  }

  mpz_init (tmp_log);
  i = 0;
  while (i < ncols + nbsm)
  {
    int ret = gmp_fscanf (f, "%Zd\n", tmp_log);
    FATAL_ERROR_CHECK (ret != 1, "Error in file containing logarithms values");

    if (mpz_cmp_ui (tmp_log, 0) < 0)
    {
      fprintf (stderr, "Warning, log is negative for cols %" PRIu64 "\n", i);
      mpz_mod (tmp_log, tmp_log, q);
    }
    else if (mpz_cmp (tmp_log, q) >= 0)
    {
      fprintf (stderr, "Warning, log >= q for cols %" PRIu64 "\n", i);
      mpz_mod (tmp_log, tmp_log, q);
    }
    if (mpz_cmp_ui (tmp_log, 0) == 0)
      fprintf (stderr, "Warning, log is zero for cols %" PRIu64 "\n", i);

    if (i < ncols)
      mpz_set (log[mat_renum[i]], tmp_log);
    else // log that corresponds to a SM columns in the matrix
      mpz_set (log[nprimes+(i-ncols)], tmp_log);
    i++;
  }

  while (gmp_fscanf (f, "%Zd\n", tmp_log) == 1)
    printf ("Warning, line %" PRIu64 " is ignored\n", i++);

  printf ("# Reading %" PRIu64 " logs took %.1fs\n", ncols, seconds() - tt);
  if (nbsm)
    printf ("# logs for %u SM columns were also read\n", nbsm);
  mpz_clear (tmp_log);
  fclose_maybe_compressed (f, filename);
  return log;
}

/* Write values of the known logarithms. Return the number of missing values */
static uint64_t
write_log (const char *filename, mpz_t *log, mpz_t q, renumber_t tab,
           cado_poly poly, uint64_t known_log)
{
  uint64_t i, missing = 0;
  double tt = seconds();
  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");

  for (i = 0; i < tab->size; i++)
  {
	  if (mpz_sgn(log[i]) < 0) // we do not know the log if this ideal
      missing++;
    else if (tab->table[i] == RENUMBER_SPECIAL_VALUE)
    {
      ASSERT_ALWAYS (mpz_cmp (log[i], q) < 0);
      if (i == 0 && tab->add_full_col)
        gmp_fprintf (f, "%" PRid " added column %Zd\n", i, log[i]);
      else
        gmp_fprintf (f, "%" PRid " bad ideals %Zd\n", i, log[i]);
    }
    else
    {
      ASSERT_ALWAYS (mpz_cmp (log[i], q) < 0);
      p_r_values_t p, r;
      int side;
      renumber_get_p_r_from_index (tab, &p, &r, &side, i, poly);
      if (side != tab->rat)
        gmp_fprintf (f, "%" PRid " %" PRpr " %d %" PRpr " %Zd\n", i, p, side,
                                                                  r, log[i]);
      else
        gmp_fprintf (f, "%" PRid " %" PRpr " %d rat %Zd\n", i, p, side, log[i]);
    }
  }

  printf ("# Writing logarithms took %.1fs\n", seconds()-tt);
  printf ("# %" PRIu64 " logarithms are known, %" PRIu64 " are missing\n",
          known_log, missing);
  fclose_maybe_compressed (f, filename);
  ASSERT_ALWAYS (known_log + missing == tab->size);
  return missing;
}

/* Callback function called by filter_rels in compute_log_from_relfile */
void *
insert_rel_into_table(void * context_data, earlyparsed_relation_ptr rel)
{
  read_data_t *data = (read_data_t *) context_data;
  log_rel_t *lrel = &(data->rels[rel->num]);
  unsigned int next = 0;
  ideal_merge_t buf[REL_MAX_SIZE];

  lrel->a = rel->a;
  lrel->b = rel->b;

  for (unsigned int i = 0; i < rel->nb; i++)
  {
    index_t h = rel->primes[i].h;
    weight_t e = rel->primes[i].e;

    if (data->w[h] == 0)
    {
      data->w[h] = 1;
      data->nideals++;
    }
    else if (data->w[h] != SMAX(int32_t))
      data->w[h]++;

	  if (mpz_sgn(data->log[h]) >= 0)
      mpz_add_log_mod_si (lrel->log_known_part, data->log[h], e, data->q);
    else
      buf[next++] = (ideal_merge_t) {.id = h, .e = e};
  }

  lrel->unknown = idealmerge_my_malloc (next);
  lrel->nb_unknown = next;
  memcpy(lrel->unknown, buf, next * sizeof(ideal_merge_t));

  return NULL;
}

/* Debug functions */
#if DEBUG == 1
/* Debug functions */ /* List all unused relations.*/
static void
check_unused_rel (bit_vector not_used, log_rel_t *rels, uint64_t nrels)
{
  for (uint64_t i = 0; i < nrels; i++)
  {
    if (bit_vector_getbit(not_used, (size_t) i))
    {
      fprintf (stderr, "DEBUG: rel i=%" PRIu64 ": %u unknown logarithms: ",
                       i, rels[i].nb_unknown);
      for (weight_t k = 0; k < rels[i].nb_unknown; k++)
        fprintf (stderr, "%" PRxid " ", rels[i].unknown[k].id);
      fprintf (stderr, "\n");
    }
  }
}

/* If an ideal had a non zero weight, it logarithm should be known at the end of
 * compute_log_from_relfile */
static void
check_unknown_log (read_data_t *data, uint64_t nprimes)
{
  uint64_t c = 0;
  int32_t *weight = data->w;
  mpz_t *log = data->log;
  for (index_t k = 0; k < nprimes; k++)
    if (weight[k])
	    if (mpz_sgn(log[k]) < 0)
      {
        c++;
        fprintf (stderr, "DEBUG: ideal %" PRxid " had weight %u but its "
                         "logarithm is unknown\n", k, weight[k]);
      }
  fprintf (stderr, "DEBUG: %" PRIu64 " more logarithms should be known\n", c);
}
#endif

/* 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_t *data, uint64_t i)
{
  weight_t j, k, len = data->rels[i].nb_unknown;
  ideal_merge_t *p = data->rels[i].unknown;

  for (j = 0, k = 0; k < len; k++)
  {
	  if (mpz_sgn(data->log[p[k].id]) < 0) // we do not know the log if this ideal
    {
      if (j != k)
        p[j] = p[k];
      j++;
    }
    else // We know this log, add it to log_know_part
      mpz_add_log_mod_si (data->rels[i].log_known_part, data->log[p[k].id],
                          p[k].e, data->q);
  }

  data->rels[i].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 q */
static inline void
compute_missing_log (mpz_t dest, mpz_t vlog, int32_t e, mpz_t q)
{
  mpz_t invert_coeff;
  mpz_init_set_si (invert_coeff, e);
  mpz_invert (invert_coeff, invert_coeff, q);
  mpz_neg (vlog, vlog);
  mpz_mul (vlog, vlog, invert_coeff);
  mpz_mod (dest, vlog, q);
}

/* Compute all missing logarithms for relations in [start,end[.
 * Return the number of computed logarithms */
static uint64_t
#ifndef FOR_FFS
do_one_part_of_iter (read_data_t *data, sm_data_t *sm, bit_vector not_used,
                     uint64_t start, uint64_t end)
#else
do_one_part_of_iter (read_data_t *data, bit_vector not_used, uint64_t start,
                     uint64_t end)
#endif
{
  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;
#ifndef FOR_FFS
        add_sm_contribution(vlog, sm, data->rels[i].a, data->rels[i].b);
#endif
        if (nb == 0 && mpz_cmp_ui (vlog, 0) != 0)
        {
          gmp_fprintf (stderr, "Error, no unknow log in rel %" PRIu64 " and sum"
                       " of log is not zero (sum is %Zd), error!\n", i, vlog);
          exit (EXIT_FAILURE);
        }
        else if (nb == 1)
        {
          ideal_merge_t ideal = data->rels[i].unknown[0];
          compute_missing_log(data->log[ideal.id], vlog, ideal.e, data->q);
          computed++;
        }
      }
    }
  }

  return computed;
}

/* Compute all missing logarithms possible. Run through all the relations once.
 * Mono thread version
 * Return the number of computed logarithms */
static uint64_t
#ifndef FOR_FFS
do_one_iter_mono (read_data_t *data, sm_data_t *sm, bit_vector not_used,
                  uint64_t nrels)
{
  return do_one_part_of_iter (data, sm, not_used, 0, nrels);
}
#else
do_one_iter_mono (read_data_t *data, bit_vector not_used, uint64_t nrels)
{
  return do_one_part_of_iter (data, not_used, 0, nrels);
}
#endif

/* Code for multi thread version */
#define SIZE_BLOCK 1024

typedef struct {
  read_data_t *data;
  bit_vector_ptr not_used;
#ifndef FOR_FFS
  sm_data_t *sm;
#endif
  uint64_t offset;
  uint64_t nb;
  uint64_t computed;
} thread_info;

void * thread_start(void *arg)
{
  thread_info *ti = (thread_info *) arg;
  read_data_t *data = ti->data;
  bit_vector_ptr not_used = ti->not_used;
  uint64_t start = ti->offset;
  uint64_t end = start + ti->nb;
  
#ifndef FOR_FFS
  sm_data_t *sm = ti->sm;
  ti->computed = do_one_part_of_iter (data, sm, not_used, start, end);
#else
  ti->computed = do_one_part_of_iter (data, not_used, start, end);
#endif

  return NULL;
}

/* Compute all missing logarithms possible. Run through all the relations once.
 * Multi thread version
 * Return the number of computed logarithms */
static uint64_t
#ifndef FOR_FFS
do_one_iter_mt (read_data_t *data, sm_data_t *sm, bit_vector not_used, int nt,
                  uint64_t nrels)
#else
do_one_iter_mt (read_data_t *data, bit_vector not_used, int nt, uint64_t nrels)
#endif
{
  // 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;
#ifndef FOR_FFS
    tis[i].sm = sm;
#endif
    // 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;
}



/* Given a filename, compute all the possible logarithms of ideals appearing in
 * the file. Return the number of computed logarithms. */
static uint64_t
#ifndef FOR_FFS
compute_log_from_relfile (const char *filename, uint64_t nrels, mpz_t q,
                          mpz_t *log, uint64_t nprimes, unsigned long nbsm,
                          mpz_t smexp, mpz_poly_t F, int nt)
#else
compute_log_from_relfile (const char *filename, uint64_t nrels, mpz_t q,
                          mpz_t *log, uint64_t nprimes, int nt)
#endif
{
  double tt0, tt;
  uint64_t total_computed = 0, iter = 0, computed;
  read_data_t data;
  read_data_init(&data, log, q, nprimes, nrels);

  /* Reading all relations */
  printf ("# Reading relations from %s\n", filename);
  fflush(stdout);
  char *fic[2] = {(char *) filename, NULL};
  filter_rels (fic, (filter_rels_callback_t) insert_rel_into_table, &data,
          EARLYPARSE_NEED_AB_HEXA | EARLYPARSE_NEED_INDEX, NULL, NULL);

  /* Init data needed to compute SM */
#ifndef FOR_FFS
  sm_data_t sm;
  sm_data_init(&sm, nbsm, F, q, smexp, log, nprimes);
#endif

  /* Init bit_vector to remember which relations were already used */
  bit_vector not_used;
  bit_vector_init(not_used, nrels);
  FATAL_ERROR_CHECK (not_used->p == NULL, "Cannot allocate memory");
  bit_vector_set(not_used, 1);
  if (nrels & (BV_BITS - 1))
    not_used->p[nrels>>LN2_BV_BITS] &= (((bv_t) 1)<<(nrels & (BV_BITS - 1))) - 1;

  /* 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;
  printf("# Using multi thread version with %d threads\n", nt);

  /* computing missing log */
  printf ("# Starting to computing missing logarithms from rels\n");
  tt0 = seconds();
  do
  {
    printf ("# Iteration %" PRIu64 ": begin\n", iter);
    fflush(stdout);
    tt = seconds();
#ifndef FOR_FFS
    if (nt > 1)
      computed = do_one_iter_mt (&data, &sm, not_used, nt, nrels);
    else
      computed = do_one_iter_mono (&data, &sm, not_used, nrels);
#else
    if (nt > 1)
      computed = do_one_iter_mt (&data, not_used, nt, nrels);
    else
      computed = do_one_iter_mono (&data, not_used, nrels);
#endif
    total_computed += computed;
    printf ("# Iteration %" PRIu64 ": end with %" PRIu64 " new "
            "logarithms computed in %.1fs.\n", iter, computed, seconds()-tt);
    iter++;
  } while (computed);
  printf ("# Computing %" PRIu64 " new logarithms took %.1fs\n", total_computed,
          seconds() - tt0);

  size_t c = bit_vector_popcount(not_used);
  if (c != 0)
    fprintf(stderr, "Warning, %zu relations were not used\n", c);
#if DEBUG == 1
  if (c != 0)
    check_unused_rel(not_used, data->rels, nrels);
  check_unknown_log (&data, nprimes);
#endif

  read_data_free(&data, nrels);
#ifndef FOR_FFS
  sm_data_free(&sm);
#endif
  bit_vector_clear(not_used);
  return total_computed;
}


static void declare_usage(param_list pl)
{
  param_list_decl_usage(pl, "log", "input file containing known logarithms");
  param_list_decl_usage(pl, "gorder", "group order (see sm -gorder 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", "(switch) do not reconstruct everything that can be reconstructed");
#ifndef FOR_FFS
  param_list_decl_usage(pl, "sm", "number of SM to add to relations");
  param_list_decl_usage(pl, "smexp", "sm exponent (see sm -smexp parameter)");
#endif
  param_list_decl_usage(pl, "mt", "number of threads (default 1)");
  param_list_decl_usage(pl, "force-posix-threads", "(switch)");
  param_list_decl_usage(pl, "path_antebuffer", "path to antebuffer program");
}

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];

  renumber_t renumber_table;
  uint64_t ncols_matrix, nrels_tot = 0, nrels_purged, nideals_purged, nrels_del;
  uint64_t nprimes, i, known_log;
  index_t *matrix_indexing = NULL;
  int mt = 1;
  int partial = 0;

  unsigned int nbsm = 0;
  mpz_t q, smexp, *log = NULL;
  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 */
  param_list_print_command_line (stdout, pl);
  fflush(stdout);

  mpz_init (q);
  mpz_init (smexp);
  const char * logfilename = param_list_lookup_string(pl, "log");
  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");
  param_list_parse_uint64(pl, "nrels", &nrels_tot);
  param_list_parse_mpz(pl, "gorder", q);
#ifndef FOR_FFS
  param_list_parse_uint(pl, "sm", &nbsm);
  param_list_parse_mpz(pl, "smexp", smexp);
#endif
  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_warn_unused(pl))
  {
    fprintf(stderr, "Error, unused parameters are given\n");
    usage(pl, argv0);
  }

  if (mpz_cmp_ui (q, 0) <= 0)
  {
    fprintf(stderr, "Error, missing -gorder command line argument "
                    "(or gorder <= 0)\n");
    usage (pl, argv0);
  }
  if (nbsm != 0 && mpz_cmp_ui (smexp, 0) <= 0)
  {
    fprintf(stderr, "Error, missing -smexp command line argument "
                    "(or smexp <= 0)\n");
    usage (pl, argv0);
  }
  if (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 (idealsfilename == NULL)
  {
    fprintf(stderr, "Error, missing -ideals 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);
  }

  cado_poly_init (poly);
#ifndef FOR_FFS
  if (!cado_poly_read (poly, polyfilename))
#else
  if (!ffs_poly_read (poly, polyfilename))
#endif
  {
    fprintf (stderr, "Error reading polynomial file\n");
    exit (EXIT_FAILURE);
  }
  /* Get mpz_poly_t F from cado_poly pol (algebraic side) */
#ifndef FOR_FFS
  mpz_poly_ptr F = poly->pols[ALGEBRAIC_SIDE];
  FATAL_ERROR_CHECK(nbsm > (unsigned int) poly->alg->deg, "Too many SM");
#endif


  set_antebuffer_path (argv0, path_antebuffer);

  /* Reading renumber file */
  renumber_init (renumber_table, poly, NULL);
  renumber_read_table (renumber_table, renumberfilename);
  nprimes = renumber_table->size;

  /* Read number of rows and cols on first line of purged file */
  purgedfile_read_firstline (relspfilename, &nrels_purged, &nideals_purged);
  nrels_del = nrels_tot - nrels_purged;

  /* Opening ideals file, malloc'ing matrix_indexing and reading ideals file */
  matrix_indexing = read_index (idealsfilename, &ncols_matrix, nprimes);

  /* Opening log file, malloc'ing log tab and reading values of log */
  log = read_log (matrix_indexing, logfilename, q, nbsm, ncols_matrix, nprimes);
  known_log = ncols_matrix;
  free (matrix_indexing);

  if (!partial) {
    /* Computing log using rels in purged file */
    known_log +=
#ifndef FOR_FFS
      compute_log_from_relfile (relspfilename, nrels_purged, q, log, nprimes,
                                nbsm, smexp, F, mt);
#else
      compute_log_from_relfile (relspfilename, nrels_purged, q, log, nprimes, mt);
#endif
    printf ("# %" PRIu64 " known logarithms so far.\n", known_log);
    fflush(stdout);

    /* Computing log using rels in del file */
    known_log +=
#ifndef FOR_FFS
      compute_log_from_relfile (relsdfilename, nrels_del, q, log, nprimes,
                                nbsm, smexp, F, mt);
#else
      compute_log_from_relfile (relsdfilename, nrels_del, q, log, nprimes, mt);
#endif
    printf ("# %" PRIu64 " known logarithms.\n", known_log);
    fflush(stdout);
  }

  /* Writing all the logs in outfile */
  write_log (outfilename, log, q, renumber_table, poly, known_log);

  /* freeing and closing */
  for (i = 0; i < nprimes + nbsm; i++)
    mpz_clear(log[i]);
  free(log);
  mpz_clear(q);
  mpz_clear(smexp);

  renumber_free (renumber_table);
  cado_poly_clear (poly);
  param_list_clear (pl);
  return EXIT_SUCCESS;
}
back to top