Raw File
filter_matrix.c
#include "cado.h"

#include <string.h>
#include <stdio.h>

#include "portability.h"
#include "filter_common.h"
#include "filter_matrix.h"
#include "sparse.h"

int
decrS (int w)
{
  return (w >= 0 ? w - 1 : w + 1);
}

/* increment the absolute value of a signed number */
int
incrS (int w)
{
  return (w >= 0 ? w + 1 : w - 1);
}

/* initialize the sparse matrix mat */
void
initMat (filter_matrix_t *mat, int maxlevel, uint32_t keep,
         uint32_t nburied)
{
  mat->keep  = keep;
  mat->mergelevelmax = maxlevel;
  mat->cwmax = 2 * maxlevel;
  ASSERT_ALWAYS (mat->cwmax < 255);
  mat->nburied = nburied;

  mat->weight = 0;
  mat->tot_weight = 0;
  mat->rem_ncols = 0;

  mat->rows = (typerow_t **) malloc (mat->nrows * sizeof (typerow_t *));
  ASSERT_ALWAYS (mat->rows != NULL);
  mat->wt = (int32_t *) malloc (mat->ncols * sizeof (int32_t));
  memset (mat->wt, 0, mat->ncols * sizeof (int32_t));
  mat->R = (index_t **) malloc (mat->ncols * sizeof(index_t *));
  ASSERT_ALWAYS(mat->R != NULL);
}

void
clearMat (filter_matrix_t *mat)
{
  uint64_t i, j;

  for (i = 0; i < mat->nrows; i++)
    free (mat->rows[i]);
  free (mat->rows);
  free (mat->wt);
  for (j = 0; j < mat->ncols; j++)
    free (mat->R[j]);
  free (mat->R);
}

/* initialize Rj[j] for light columns, i.e., for those of weight <= cwmax */
void
InitMatR (filter_matrix_t *mat)
{
  index_t h;
  int32_t w;

  for(h = 0; h < mat->ncols; h++)
  {
    w = mat->wt[h];
    if (w <= mat->cwmax)
    {
      mat->R[h] = (index_t *) malloc((w + 1) * sizeof(index_t));
      FATAL_ERROR_CHECK(mat->R[h] == NULL, "Cannot allocate memory");
      mat->R[h][0] = 0; /* last index used */
    }
    else /* weight is larger than cwmax */
    {
      mat->wt[h] = -mat->wt[h]; // trick!!!
      mat->R[h] = NULL;
    }
  }
}

/* callback function called by filter_rels */
void * insert_rel_into_table (void *context_data, earlyparsed_relation_ptr rel)
{
  filter_matrix_t *mat = (filter_matrix_t *) context_data;
  unsigned int next_id = 0;
  typerow_t buf[REL_MAX_SIZE];

  for (unsigned int i = 0; i < rel->nb; i++)
  {
    index_t h = rel->primes[i].h;
    weight_t e = rel->primes[i].e;
    mat->tot_weight++;
    /* For factorization, they should not be any multiplicity here.
       For DL we do not want to count multiplicity in mat->wt */
#ifndef FOR_DL
    ASSERT_ALWAYS (e == 1);
#endif
	  if (mat->wt[h] == 0)
    {
	    mat->wt[h] = 1;
	    mat->rem_ncols++;
	  }
    else if (mat->wt[h] != SMAX(int32_t))
	    mat->wt[h]++;

	  if (h >= mat->nburied)
    {
      mat->weight++;
      setCell(buf[next_id], h, e);
      next_id++;
	  }
  }

  //FIXME for now can't use my malloc, because rows is realloc later
  mat->rows[rel->num] = (typerow_t*) malloc ((next_id + 1) * sizeof (typerow_t));
  FATAL_ERROR_CHECK(mat->rows[rel->num] == NULL, "Cannot allocate memory");
  matLengthRow(mat, rel->num) = next_id;
  memcpy(&(mat->rows[rel->num][1]), buf, next_id * sizeof(typerow_t));
  // sort indices in val to ease row merges
  qsort(&(mat->rows[rel->num][1]), next_id, sizeof(typerow_t), cmp_typerow_t);

  return NULL;
}


void
filter_matrix_read (filter_matrix_t *mat, const char *purgedname)
{
  uint64_t nread, i, h;
  char *fic[2] = {(char *) purgedname, NULL};

  /* read all rels */
  nread = filter_rels(fic, (filter_rels_callback_t) &insert_rel_into_table, mat,
                      EARLYPARSE_NEED_INDEX, NULL, NULL);
  ASSERT_ALWAYS(nread == mat->nrows);
  mat->rem_nrows = nread;
  printf("# Weight of the active part of the matrix: %" PRIu64 "\n# Total "
         "weight of the matrix: %" PRIu64 "\n", mat->weight, mat->tot_weight);

  /* print weight count */
  uint64_t *nbm;
  nbm = (uint64_t *) malloc ((mat->mergelevelmax + 1) * sizeof (uint64_t));
  memset (nbm, 0, (mat->mergelevelmax + 1) * sizeof (uint64_t));
  for (h = 0; h < mat->ncols; h++)
    if (mat->wt[h] <= mat->mergelevelmax)
      nbm[mat->wt[h]]++;
  for (h = 0; h <= (uint64_t) mat->mergelevelmax; h++)
    printf ("There are %" PRIu64 " column(s) of weight %" PRIu64 "\n", nbm[h], h);
  ASSERT_ALWAYS(mat->rem_ncols == mat->ncols - nbm[0]);
  free (nbm);

  /* Print info on buried columns (columns not take into account during merge).
    The 'nburied'-first cols are buried, should be the heaviest by construction.
  */
  uint64_t weight_buried = 0;
  if (mat->nburied)
  {
    int32_t bmin = mat->nrows, bmax = 0;

    for (h = 0; h < mat->nburied; h++)
    {
      int32_t w = ABS(mat->wt[h]);
      weight_buried += w;
      if (w > bmax)
        bmax = w;
      if (w < bmin)
        bmin = w;
#if DEBUG >= 1
      fprintf(stderr, "# Burying j=%" PRIu64 " (wt=%" PRId32 ")\n", h, w);
#endif
    }
    printf("# Number of buried columns is %" PRid " (min_weight=%" PRId32 ", "
           "max_weight=%" PRId32 ")\n", mat->nburied, bmin, bmax);
  }
  else
    printf("# No columns were buried.\n");
  ASSERT_ALWAYS (mat->weight + weight_buried == mat->tot_weight);

  /* Allocate mat->R[h] if necessary */
  InitMatR (mat);

  /* Re-read all rels (in memory) to fill-in mat->R */
  printf("# Start to fill-in columns of the matrix.\n");
  fflush (stdout);
  for (i = 0; i < mat->nrows; i++)
  {
    for(unsigned int k = 1 ; k <= matLengthRow(mat, i); k++)
    {
      h = matCell(mat, i, k);
      ASSERT (mat->nburied <= h && h < mat->ncols);
      if(mat->wt[h] > 0)
      {
        mat->R[h][0]++;
        mat->R[h][mat->R[h][0]] = i;
      }
    }
  }
}

void
print_row(filter_matrix_t *mat, int i)
{
    fprintRow (stdout, mat->rows[i]);
}

void
destroyRow(filter_matrix_t *mat, int i)
{
    free(mat->rows[i]);
    mat->rows[i] = NULL;
}

void
freeRj(filter_matrix_t *mat, int j)
{
    free(mat->R[j]);
    mat->R[j] = NULL;
}

// Don't touch to R[j][0]!!!!
void
remove_i_from_Rj(filter_matrix_t *mat, int i, int j)
{
  // be dumb for a while
  unsigned int k;

  if(mat->R[j] == NULL)
  {
	  fprintf(stderr, "Row %d already empty\n", j);
	  return;
  }
  for(k = 1; k <= mat->R[j][0]; k++)
	  if((int) mat->R[j][k] == i)
    {
#if DEBUG >= 2
      fprintf(stderr, "Removing row %d from R[%d]\n", i, j);
#endif
      mat->R[j][k] = UMAX(index_t);
      break;
	  }
}

// cell M[i, j] is incorporated in the data structure. It is used
// later on in cases where i is not already present in row[j].
void
add_i_to_Rj(filter_matrix_t *mat, int i, int j)
{
  // be semi-dumb for a while
  unsigned int k;

#if DEBUG >= 2
  fprintf(stderr, "Adding row %d to R[%d]\n", i, j);
#endif
  for(k = 1; k <= mat->R[j][0]; k++)
    if(mat->R[j][k] == UMAX(index_t))
      break;
  if(k <= mat->R[j][0])
  {
  // we have found a place where it is -1
  mat->R[j][k] = i;
  }
  else
  {
#if DEBUG >= 2
    fprintf(stderr, "WARNING: reallocing things in add_i_to_Rj for R[%d]\n", j);
#endif
    int l = mat->R[j][0]+2;
    mat->R[j] = (index_t *)realloc(mat->R[j], l * sizeof(index_t));
    mat->R[j][l-1] = i;
    mat->R[j][0] = l-1;
  }
}

// Remove j from R[i] and crunch R[i].
void
remove_j_from_row(filter_matrix_t *mat, int i, int j)
{
  unsigned int k;

#if TRACE_ROW >= 0
    if(i == TRACE_ROW){
	fprintf(stderr, "TRACE_ROW: remove_j_from_row i=%d j=%d\n", i, j);
    }
#endif
#if DEBUG >= 2
    fprintf(stderr, "row[%d]_b=", i);
    print_row(mat, i);
    fprintf(stderr, "\n");
#endif
    for(k = 1; k <= matLengthRow(mat, i); k++)
	if((int) matCell(mat, i, k) == j)
	    break;
    ASSERT(k <= matLengthRow(mat, i));
    // crunch
    for(++k; k <= matLengthRow(mat, i); k++)
        matCell(mat, i, k-1) = matCell(mat, i, k);
    matLengthRow(mat, i) -= 1;
    mat->weight--;
#if DEBUG >= 2
    fprintf(stderr, "row[%d]_a=", i);
    print_row(mat, i);
    fprintf(stderr, "\n");
#endif
}

/* return the weight of the relation obtained when adding relations i2 and i2
*/
int
weightSum(filter_matrix_t *mat, int i1, int i2, MAYBE_UNUSED int32_t j)
{
  unsigned int k1, k2, w, len1, len2;

    len1 = (isRowNull(mat, i1) ? 0 : matLengthRow(mat, i1));
    len2 = (isRowNull(mat, i2) ? 0 : matLengthRow(mat, i2));
#if DEBUG >= 1
    if((len1 == 0) || (len2 == 0))
        fprintf(stderr, "i1=%d i2=%d len1=%d len2=%d\n", i1, i2, len1, len2);
#endif
#ifdef FOR_DL /* look for the exponents of j in i1 i2*/
    int e1 = 0, e2 = 0;
    int d;
    unsigned int l;
    for (l = 1 ; l <= matLengthRow(mat, i1) ; l++)
        if ((int) matCell(mat, i1, l) == j)
            e1 = mat->rows[i1][l].e;
    for (l = 1 ; l <= matLengthRow(mat, i2) ; l++)
        if ((int) matCell(mat, i2, l) == j)
            e2 = mat->rows[i2][l].e;

    ASSERT (e1 != 0 && e2 != 0);

    d  = (int) gcd_int64 ((int64_t) e1, (int64_t) e2);
    e1 /= -d;
    e2 /= d;
#endif
    k1 = k2 = 1;
    w = 0;
    while((k1 <= len1) && (k2 <= len2))
    {
        if(matCell(mat, i1, k1) < matCell(mat, i2, k2))
        {
#ifdef FOR_DL
            w += (e2 * mat->rows[i1][k1].e == 0) ? 0 : 1;
#else
            w++;
#endif
            k1++;
        }
        else if(matCell(mat, i1, k1) > matCell(mat, i2, k2))
        {
#ifdef FOR_DL
            w += (e1 * mat->rows[i2][k2].e == 0) ? 0 : 1;
#else
            w++;
#endif
            k2++;
        }
        else
        {
#ifdef FOR_DL
            w += (e2*mat->rows[i1][k1].e + e1*mat->rows[i2][k2].e == 0) ? 0 : 1;
#endif
            k1++;
            k2++;
        }
    }
    // finish with k1
    for( ; k1 <= matLengthRow(mat, i1); k1++)
#ifdef FOR_DL
            w += (e2 * mat->rows[i1][k1].e == 0) ? 0 : 1;
#else
            w++;
#endif
    // finish with k2
    for( ; k2 <= matLengthRow(mat, i2); k2++)
#ifdef FOR_DL
            w += (e1 * mat->rows[i2][k2].e == 0) ? 0 : 1;
#else
            w++;
#endif
    return w;
}

/* put in ind[0]..ind[m-1] the indices of the m (active) rows containing j,
   and return the total weight of all those rows */
int
fillTabWithRowsForGivenj(int32_t *ind, filter_matrix_t *mat, int32_t j)
{
  int ni = 0, w = 0;
  unsigned int k;
  index_t i;

  for (k = 1; k <= mat->R[j][0]; k++)
    if ((i = mat->R[j][k]) != UMAX(index_t))
      {
        ind[ni++] = i;
        w += matLengthRow(mat, i);
        if (ni == mat->wt[j])
          break;
      }
  return w;
}
back to top