Пример #1
0
void mod2sparse_add
( mod2sparse *m1,	/* Left operand of add */
  mod2sparse *m2,	/* Right operand of add */
  mod2sparse *r		/* Place to store result of add */
)
{
  mod2entry *e1, *e2;
  int i;

  if (mod2sparse_rows(m1)!=mod2sparse_rows(r) 
   || mod2sparse_cols(m1)!=mod2sparse_cols(r) 
   || mod2sparse_rows(m2)!=mod2sparse_rows(r)
   || mod2sparse_cols(m2)!=mod2sparse_cols(r)) 
  { fprintf(stderr,"mod2sparse_add: Matrices have different dimensions\n");
    exit(1);
  }

  if (r==m1 || r==m2)
  { fprintf(stderr,
     "mod2sparse_add: Result matrix is the same as one of the operands\n");
    exit(1);
  }

  mod2sparse_clear(r);

  for (i = 0; i<mod2sparse_rows(r); i++)
  { 
    e1 = mod2sparse_first_in_row(m1,i);
    e2 = mod2sparse_first_in_row(m2,i);

    while (!mod2sparse_at_end(e1) && !mod2sparse_at_end(e2))
    { 
      if (mod2sparse_col(e1)==mod2sparse_col(e2))
      { e1 = mod2sparse_next_in_row(e1);
        e2 = mod2sparse_next_in_row(e2); 
      }

      else if (mod2sparse_col(e1)<mod2sparse_col(e2))
      { mod2sparse_insert(r,i,mod2sparse_col(e1));
        e1 = mod2sparse_next_in_row(e1);
      }

      else
      { mod2sparse_insert(r,i,mod2sparse_col(e2));
        e2 = mod2sparse_next_in_row(e2);       
      }
    }

    while (!mod2sparse_at_end(e1))
    { mod2sparse_insert(r,i,mod2sparse_col(e1));
      e1 = mod2sparse_next_in_row(e1);
    }

    while (!mod2sparse_at_end(e2))
    { mod2sparse_insert(r,i,mod2sparse_col(e2));
      e2 = mod2sparse_next_in_row(e2);
    }
  }
}
Пример #2
0
void mod2sparse_copyrows
( mod2sparse *m,	/* Matrix to copy */
  mod2sparse *r,	/* Place to store copy of matrix */
  int *rows		/* Indexes of rows to copy, from 0 */
)
{ 
  mod2entry *e;
  int i;

  if (mod2sparse_cols(m)>mod2sparse_cols(r))
  { fprintf(stderr,
     "mod2sparse_copyrows: Destination matrix has fewer columns than source\n");
    exit(1);
  }

  mod2sparse_clear(r);

  for (i = 0; i<mod2sparse_rows(r); i++)
  { if (rows[i]<0 || rows[i]>=mod2sparse_rows(m))
    { fprintf(stderr,"mod2sparse_copyrows: Row index out of range\n");
      exit(1);
    }
    e = mod2sparse_first_in_row(m,rows[i]);
    while (!mod2sparse_at_end(e))
    { mod2sparse_insert(r,i,e->col);
      e = mod2sparse_next_in_row(e);
    }
  }
}
Пример #3
0
double expected_parity_errors
( mod2sparse *H,	/* Parity check matrix */
  double *bpr		/* Bit probabilities */
)
{ 
  mod2entry *f;
  double ee, p;
  int M, i, j;

  M = mod2sparse_rows(H);

  ee = 0;

  for (i = 0; i<M; i++)
  { p = 0;
    for (f = mod2sparse_first_in_row(H,i);
         !mod2sparse_at_end(f);
         f = mod2sparse_next_in_row(f))
    { j = mod2sparse_col(f);
      p = p * (1-bpr[j]) + (1-p) * bpr[j];
    }
    ee += p;
  }

  return ee;
}
Пример #4
0
void mod2sparse_transpose
( mod2sparse *m,	/* Matrix to compute transpose of (left unchanged) */
  mod2sparse *r		/* Result of transpose operation */
)
{
  mod2entry *e;
  int i;

  if (mod2sparse_rows(m)!=mod2sparse_cols(r) 
   || mod2sparse_cols(m)!=mod2sparse_rows(r))
  { fprintf(stderr,
     "mod2sparse_transpose: Matrices have incompatible dimensions\n");
    exit(1);
  }

  if (r==m)
  { fprintf(stderr, 
     "mod2sparse_transpose: Result matrix is the same as the operand\n");
    exit(1);
  }

  mod2sparse_clear(r);

  for (i = 0; i<mod2sparse_rows(m); i++)
  {
    e = mod2sparse_first_in_row(m,i);

    while (!mod2sparse_at_end(e))
    { mod2sparse_insert(r,mod2sparse_col(e),i);
      e = mod2sparse_next_in_row(e);
    }
  }
}
Пример #5
0
/******************************************************************************
 * BuildParitySymbol: Builds a new parity symbol.
 * => See header file for more informations.
 */
	ldpc_error_status
BuildParitySymbol (
		LDPCFecSession *Session, 
		void* symbol_canvas[],
		int paritySymbol_index,
		void* paritySymbol)
{
	uintptr_t	*fec_buf;	// buffer for this parity symbol
	uintptr_t	*to_add_buf;	// buffer for the  source.parity symbol to add
	mod2entry	*e;
	int seqno, k=0;
	static int n=0;

	fec_buf = (uintptr_t*)GetBufferPtrOnly(paritySymbol);

	e = mod2sparse_first_in_row(Session->m_pchkMatrix, paritySymbol_index);

	while (!mod2sparse_at_end(e)) {
		// paritySymbol_index in {0.. n-k-1} range, so this test is ok
		if (e->col != paritySymbol_index) {
			// don't add paritySymbol to itself
			seqno = GetSymbolSeqno(Session, e->col);
			//fprintf(stderr, "[%s:%d] total:%d now:%d seqno:%d, paritySymbol_index:%d, col:%d\n", __FILE__, __LINE__, n++, k++, seqno, paritySymbol_index, e->col);
			to_add_buf = (uintptr_t*)
				GetBuffer(symbol_canvas[seqno]);
			if (to_add_buf == NULL) {
				return LDPC_ERROR;
			}
			AddToSymbol(fec_buf, to_add_buf);
		}
		e = mod2sparse_next_in_row(e);
	}
	return LDPC_OK;
}
Пример #6
0
void mod2sparse_copy
( mod2sparse *m,	/* Matrix to copy */
  mod2sparse *r		/* Place to store copy of matrix */
)
{
  mod2entry *e, *f;
  int i;

  if (mod2sparse_rows(m)>mod2sparse_rows(r) 
   || mod2sparse_cols(m)>mod2sparse_cols(r))
  { fprintf(stderr,"mod2sparse_copy: Destination matrix is too small\n");
    exit(1);
  }

  mod2sparse_clear(r);

  for (i = 0; i<mod2sparse_rows(m); i++)
  {
    e = mod2sparse_first_in_row(m,i); 

    while (!mod2sparse_at_end(e))
    { f = mod2sparse_insert(r,e->row,e->col);
#if 0
      f->lr = e->lr;
      f->pr = e->pr;
#endif      
      e = mod2sparse_next_in_row(e);
    }
  }
}
Пример #7
0
mod2entry *mod2sparse_find
( mod2sparse *m,
  int row,
  int col
)
{ 
  mod2entry *re, *ce;

  if (row<0 || row>=mod2sparse_rows(m) || col<0 || col>=mod2sparse_cols(m))
  { fprintf(stderr,"mod2sparse_find: row or column index out of bounds\n");
    exit(1);
  }

  /* Check last entries in row. */

  re = mod2sparse_last_in_row(m,row);
  if (mod2sparse_at_end(re) || mod2sparse_col(re)<col) 
  { return 0;
  }
  if (mod2sparse_col(re)==col) 
  { return re;
  }

#ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE
  ce = mod2sparse_last_in_col(m,col);
  if (mod2sparse_at_end(ce) || mod2sparse_row(ce)<row)
  { return 0;
  }
  if (mod2sparse_row(ce)==row)
  { return ce;
  }
#endif

  /* Search row and column in parallel, from the front. */

  re = mod2sparse_first_in_row(m,row);
  ce = mod2sparse_first_in_col(m,col);

  for (;;)
  { 
    if (mod2sparse_at_end(re) || mod2sparse_col(re)>col)
    { return 0;
    } 
    if (mod2sparse_col(re)==col) 
    { return re;
    }

    if (mod2sparse_at_end(ce) || mod2sparse_row(ce)>row)
    { return 0;
    } 
    if (mod2sparse_row(ce)==row)
    { return ce;
    }

    re = mod2sparse_next_in_row(re);
    ce = mod2sparse_next_in_col(ce);
  }
}
Пример #8
0
void mod2sparse_add_row
( mod2sparse *m1,	/* Matrix containing row to add to */
  int row1,		/* Index in this matrix of row to add to */
  mod2sparse *m2,	/* Matrix containing row to add from */
  int row2		/* Index in this matrix of row to add from */
)
{
  mod2entry *f1, *f2, *ft;

  if (mod2sparse_cols(m1)<mod2sparse_cols(m2))
  { fprintf (stderr,
     "mod2sparse_add_row: row added to is shorter than row added from\n");
    exit(1);
  }

  if (row1<0 || row1>=mod2sparse_rows(m1) 
   || row2<0 || row2>=mod2sparse_rows(m2))
  { fprintf (stderr,"mod2sparse_add_row: row index out of range\n");
    exit(1);
  }

  f1 = mod2sparse_first_in_row(m1,row1);
  f2 = mod2sparse_first_in_row(m2,row2);

  while (!mod2sparse_at_end(f1) && !mod2sparse_at_end(f2))
  { if (mod2sparse_col(f1)>mod2sparse_col(f2))
    { mod2sparse_insert(m1,row1,mod2sparse_col(f2));
      f2 = mod2sparse_next_in_row(f2);
    }
    else
    { ft = mod2sparse_next_in_row(f1);  
      if (mod2sparse_col(f1)==mod2sparse_col(f2))
      { mod2sparse_delete(m1,f1);
        f2 = mod2sparse_next_in_row(f2);
      }
      f1 = ft;
    }
  }

  while (!mod2sparse_at_end(f2))
  { mod2sparse_insert(m1,row1,mod2sparse_col(f2));
    f2 = mod2sparse_next_in_row(f2);
  }
}
Пример #9
0
int mod2sparse_equal
( mod2sparse *m1,
  mod2sparse *m2
)
{
  mod2entry *e1, *e2;
  int i;

  if (mod2sparse_rows(m1)!=mod2sparse_rows(m2) 
   || mod2sparse_cols(m1)!=mod2sparse_cols(m2))
  { fprintf(stderr,"mod2sparse_equal: Matrices have different dimensions\n");
    exit(1);
  }
  
  for (i = 0; i<mod2sparse_rows(m1); i++)
  { 
    e1 = mod2sparse_first_in_row(m1,i);
    e2 = mod2sparse_first_in_row(m2,i);

    while (!mod2sparse_at_end(e1) && !mod2sparse_at_end(e2))
    {  
      if (mod2sparse_col(e1)!=mod2sparse_col(e2))
      { return 0;
      }

      e1 = mod2sparse_next_in_row(e1);
      e2 = mod2sparse_next_in_row(e2);
    }

    if (!mod2sparse_at_end(e1) || !mod2sparse_at_end(e2)) 
    { return 0;
    }
  }

  return 1;
}
Пример #10
0
int mod2sparse_write
( FILE *f,
  mod2sparse *m
)
{
  mod2entry *e;
  int i;

  intio_write(f,m->n_rows);
  if (ferror(f)) return 0;

  intio_write(f,m->n_cols);
  if (ferror(f)) return 0;

  for (i = 0; i<mod2sparse_rows(m); i++)
  { 
    e = mod2sparse_first_in_row(m,i);

    if (!mod2sparse_at_end(e))
    {
      intio_write (f, -(i+1));
      if (ferror(f)) return 0;

      while (!mod2sparse_at_end(e))
      { 
        intio_write (f, mod2sparse_col(e)+1);
        if (ferror(f)) return 0;

        e = mod2sparse_next_in_row(e);
      }
    }
  }

  intio_write(f,0);
  if (ferror(f)) return 0;

  return 1;
}
Пример #11
0
int mod2sparse_count_row
( mod2sparse *m,
  int row
)
{
  mod2entry *e;
  int count;

  if (row<0 || row>=mod2sparse_rows(m))
  { fprintf(stderr,"mod2sparse_count_row: row index out of bounds\n");
    exit(1);
  }

  count = 0;

  for (e = mod2sparse_first_in_row(m,row);
       !mod2sparse_at_end(e);
       e = mod2sparse_next_in_row(e))
  { count += 1;
  }

  return count;
}
Пример #12
0
void mod2sparse_print
( FILE *f,
  mod2sparse *m
)
{ 
  int rdigits, cdigits;
  mod2entry *e;
  int i;

  rdigits = mod2sparse_rows(m)<=10 ? 1 
          : mod2sparse_rows(m)<=100 ? 2
          : mod2sparse_rows(m)<=1000 ? 3
          : mod2sparse_rows(m)<=10000 ? 4
          : mod2sparse_rows(m)<=100000 ? 5
          : 6;

  cdigits = mod2sparse_cols(m)<=10 ? 1 
          : mod2sparse_cols(m)<=100 ? 2
          : mod2sparse_cols(m)<=1000 ? 3
          : mod2sparse_cols(m)<=10000 ? 4
          : mod2sparse_cols(m)<=100000 ? 5
          : 6;

  for (i = 0; i<mod2sparse_rows(m); i++)
  { 
    fprintf(f,"%*d:",rdigits,i);

    e = mod2sparse_first_in_row(m,i);
    while (!mod2sparse_at_end(e))
    { fprintf(f," %*d",cdigits,mod2sparse_col(e));
      e = mod2sparse_next_in_row(e);
    }

    fprintf(f,"\n");
  }
}
Пример #13
0
/******************************************************************************
 * InitSession : Initializes the LDPC session.
 * => See header file for more informations.
 */
ldpc_error_status
InitSession (
		LDPCFecSession *Session,
		int nbSourceSymbols,
		int nbParitySymbols,
		int symbolSize,
		int flags,
		int seed,
		SessionType codecType,
		int leftDegree)
{
	int row, seq;
	mod2entry	*e;

	Session->m_initialized	= false;
	Session->m_sessionFlags	= flags;
	Session->m_sessionType	= codecType;
	Session->m_symbolSize	= symbolSize;

	if (nbSourceSymbols + nbParitySymbols > GetMaxN()) 
		return LDPC_ERROR;

	Session->m_nbSourceSymbols	= nbSourceSymbols;
	Session->m_nbParitySymbols	= nbParitySymbols;

	// sanity check: setting a left degree != 3 is only meaningfull with
	// LDGM codes, not with LDPC-Staircase/Triangle codes.
	if ((Session->m_sessionType != TypeLDGM) && (leftDegree != 3)) {
		fprintf(stderr, "LDPCFecSession::InitSession: ERROR: setting a leftDegree!=3 (here %d) is only meaningfull with LDGM codes, not with LDPC-Staircase/Triangle codes!\n", leftDegree);
		return LDPC_ERROR;
	}
	Session->m_leftDegree	= leftDegree;
	Session->m_firstNonDecoded = 0;

	Session->m_pchkMatrix = CreatePchkMatrix(Session->m_nbParitySymbols, Session->m_nbSourceSymbols + Session->m_nbParitySymbols, Evenboth, Session->m_leftDegree, seed, false, Session->m_sessionType);
	if (Session->m_pchkMatrix == NULL) 
		return LDPC_ERROR;

	if (Session->m_sessionFlags & FLAG_CODER) {
		Session->m_nb_unknown_symbols_encoder = (int*)calloc(Session->m_nbParitySymbols, sizeof(int));
		if (Session->m_nb_unknown_symbols_encoder == NULL) 
			return LDPC_ERROR;

		for (row = 0; row < Session->m_nbParitySymbols; row++) {
			mod2entry *e;
			for (e = mod2sparse_first_in_row(Session->m_pchkMatrix, row);
					!mod2sparse_at_end(e);
					e = mod2sparse_next_in_row(e)) {
				Session->m_nb_unknown_symbols_encoder[row]++;
			}
		}
	} else {
		Session->m_nb_unknown_symbols_encoder = NULL;
	}

	if (Session->m_sessionFlags & FLAG_DECODER) {
		if (((Session->m_checkValues	= (void**)calloc(Session->m_nbParitySymbols, sizeof(void*))) == NULL) ||
				((Session->m_nbSymbols_in_equ = (int*)calloc(Session->m_nbParitySymbols, sizeof(int))) == NULL) ||
				((Session->m_nb_unknown_symbols = (int*)calloc(Session->m_nbParitySymbols, sizeof(int))) == NULL) ||
				((Session->m_nbEqu_for_parity = (int*)calloc(Session->m_nbParitySymbols, sizeof(int))) == NULL) ||
				((Session->m_parity_symbol_canvas = (void**)calloc(Session->m_nbParitySymbols, sizeof(void*))) == NULL)) {
			return LDPC_ERROR;
		}
		// and update the various tables now
		for (row = 0; row < Session->m_nbParitySymbols; row++) {
			for (e = mod2sparse_first_in_row(Session->m_pchkMatrix, row);
					!mod2sparse_at_end(e);
					e = mod2sparse_next_in_row(e))
			{
				Session->m_nbSymbols_in_equ[row]++;
				Session->m_nb_unknown_symbols[row]++;
			}
		}
		for (seq = Session->m_nbSourceSymbols; seq < (Session->m_nbParitySymbols+Session->m_nbSourceSymbols); seq++) {
			for (e = mod2sparse_first_in_col(Session->m_pchkMatrix,
						GetMatrixCol(Session, seq));
					!mod2sparse_at_end(e);
					e = mod2sparse_next_in_col(e))
			{
				Session->m_nbEqu_for_parity[seq - Session->m_nbSourceSymbols]++;
			}
		}
	} else {
		// CODER session
		Session->m_checkValues = NULL;
		Session->m_nbSymbols_in_equ = NULL;
		Session->m_nb_unknown_symbols = NULL;
		Session->m_nbEqu_for_parity = NULL;
		Session->m_parity_symbol_canvas = NULL;
	}
	if ((Session->m_sessionType == TypeTRIANGLE) && (((Session->m_nbParitySymbols+Session->m_nbSourceSymbols)/Session->m_nbSourceSymbols) < 2.0)) {
		Session->m_triangleWithSmallFECRatio = true;
	} else {
		Session->m_triangleWithSmallFECRatio = false;
	}
	Session->m_initialized = true;
	return LDPC_OK;
}
Пример #14
0
void mod2sparse_multiply 
( mod2sparse *m1, 	/* Left operand of multiply */
  mod2sparse *m2,	/* Right operand of multiply */
  mod2sparse *r		/* Place to store result of multiply */
)
{
  mod2entry *e1, *e2;
  int i, j, b;

  if (mod2sparse_cols(m1)!=mod2sparse_rows(m2) 
   || mod2sparse_rows(m1)!=mod2sparse_rows(r) 
   || mod2sparse_cols(m2)!=mod2sparse_cols(r))
  { fprintf (stderr,
      "mod2sparse_multiply: Matrices have incompatible dimensions\n");
    exit(1);
  }

  if (r==m1 || r==m2)
  { fprintf(stderr,
     "mod2sparse_multiply: Result matrix is the same as one of the operands\n");
    exit(1);
  }

  mod2sparse_clear(r);

  for (i = 0; i<mod2sparse_rows(m1); i++)
  { 
    if (mod2sparse_at_end(mod2sparse_first_in_row(m1,i))) 
    { continue;
    }

    for (j = 0; j<mod2sparse_cols(m2); j++)
    { 
      b = 0;

      e1 = mod2sparse_first_in_row(m1,i);
      e2 = mod2sparse_first_in_col(m2,j);

      while (!mod2sparse_at_end(e1) && !mod2sparse_at_end(e2))
      { 
        if (mod2sparse_col(e1)==mod2sparse_row(e2))
        { b ^= 1;
          e1 = mod2sparse_next_in_row(e1);
          e2 = mod2sparse_next_in_col(e2); 
        }

        else if (mod2sparse_col(e1)<mod2sparse_row(e2))
        { e1 = mod2sparse_next_in_row(e1);
        }

        else
        { e2 = mod2sparse_next_in_col(e2);       
        }
      }

      if (b)
      { mod2sparse_insert(r,i,j);
      }
    }
  }
}
Пример #15
0
mod2sparse* CreatePchkMatrix (  int nbRows, int nbCols, make_method makeMethod, int leftDegree, int seed, bool no4cycle, SessionType type, int verbosity )
{
	mod2entry *e;
#if 0
	mod2entry *f, *g, *h;	/* using by no4cycle mode */
	int elim4;
#endif
	int added, uneven;
	int i, j, k, t;
	int *u;
	mod2sparse *pchkMatrix = NULL;
	int skipCols = 0;		// avoid warning
	int nbDataCols = 0;		// avoid warning

	if (type != TypeLDGM && type != TypeSTAIRS && type != TypeTRIANGLE) {
		fprintf(stderr, "unsupported code type (%d)\n", type);
		return NULL;
	}
	skipCols = nbRows;
	nbDataCols = nbCols-skipCols;

	// Check for some problems.
	if (leftDegree>nbRows)
	{
		fprintf(stderr, "ERROR, Number of checks per bit (%d) is greater than total checks (%d)\n", leftDegree, nbRows);
		return NULL;
	}
#if 0
	if (leftDegree==nbRows && nbCols>1 && no4cycle)
	{
		fprintf(stderr,	"ERROR, Can't eliminate cycles of length four with this many checks per bit\n");
		return NULL;
	}
#endif
	if (no4cycle) { 
		fprintf(stderr, "ERROR: no4cycle mode is no longer supported!\n");
		exit(-1);
	}

	ldpc_srand(seed);
	pchkMatrix = mod2sparse_allocate(nbRows, nbCols);

	/* Create the initial version of the parity check matrix. */
	switch (makeMethod)
	{ 
	case Evencol:
		for(j=skipCols; j<nbCols; j++)
		{
			for(k=0; k<leftDegree; k++)
			{
				do
				{
					i = ldpc_rand(nbRows);
				}
				while (mod2sparse_find(pchkMatrix,i,j));
				mod2sparse_insert(pchkMatrix,i,j);
			}
		}
		break;

	case Evenboth:
		u = (int*)chk_alloc (leftDegree*nbDataCols, sizeof *u);

		/* initialize a list of possible choices to guarantee a homogeneous "1" distribution */
		for(k = leftDegree*nbDataCols-1; k>=0; k--)
		{
			u[k] = k%nbRows;
		}
		uneven = 0;
		t = 0;	/* left limit within the list of possible choices, u[] */
		for(j = skipCols; j<nbCols; j++)	/* for each source symbol column */
		{
			for(k = 0; k<leftDegree; k++)	/* add left_degree "1s" */
			{ 
				/* check that valid available choices remain */
				for(i = t; i<leftDegree*nbDataCols && mod2sparse_find(pchkMatrix,u[i],j); i++) ;

				if(i < leftDegree*nbDataCols)
				{
					/* choose one index within the list of possible choices */
					do {
						i = t + ldpc_rand(leftDegree*nbDataCols-t);
					} while (mod2sparse_find(pchkMatrix,u[i],j));
					mod2sparse_insert(pchkMatrix,u[i],j);
					/* replace with u[t] which has never been chosen */
					u[i] = u[t];
					t++;
				}
				else
				{
					/* no choice left, choose one randomly */
					uneven += 1;
					do {
						i = ldpc_rand(nbRows);
					} while (mod2sparse_find(pchkMatrix,i,j));
					mod2sparse_insert(pchkMatrix,i,j);
				}
			}
		}

		if(uneven > 0 && verbosity >= 1)
		{
			fprintf(stderr,"Had to place %d checks in rows unevenly\n",uneven);
		}
		free(u);	/* VR: added */
		break;

	default: abort();
	}

	/* Add extra bits to avoid rows with less than two checks. */
	added = 0;
	for(i = 0; i<nbRows; i++)
	{
		e = mod2sparse_first_in_row(pchkMatrix,i);
		if(mod2sparse_at_end(e))
		{
			j = (ldpc_rand(nbDataCols))+skipCols;
			e = mod2sparse_insert(pchkMatrix,i,j);
			added ++;
		}
		e = mod2sparse_first_in_row(pchkMatrix,i);
		if(mod2sparse_at_end(mod2sparse_next_in_row(e)) && nbDataCols>1)
		{ 
			do 
			{ 
				j = (ldpc_rand(nbDataCols))+skipCols; 
			} while (j==mod2sparse_col(e));
			mod2sparse_insert(pchkMatrix,i,j);
			added ++;
		}
	}

	if(added > 0 && verbosity >= 1)
	{
		fprintf(stderr, "Added %d extra bit-checks to make row counts at least two\n", added);
	}


	/* Add extra bits to try to avoid problems with even column counts. */
	if(leftDegree%2==0 && leftDegree<nbRows && nbDataCols>1 && added<2)
	{
		int a;
		for(a = 0; added+a<2; a++)
		{
			do
			{
				i = ldpc_rand(nbRows);
				j = (ldpc_rand(nbDataCols))+skipCols;
			} while (mod2sparse_find(pchkMatrix,i,j));
			mod2sparse_insert(pchkMatrix,i,j);
		}
		if (verbosity >= 1) {
			fprintf(stderr, "Added %d extra bit-checks to try to avoid problems from even column counts\n", a);
		}
	}

#if 0
	/* Eliminate cycles of length four, if asked, and if possible. */
	if(no4cycle)
	{ 
		elim4 = 0;

		for(t = 0; t<10; t++) 
		{
			k = 0;
			for(j = 0; j<nbCols; j++)
			{
				for( e=mod2sparse_first_in_col(pchkMatrix,j); !mod2sparse_at_end(e); e=mod2sparse_next_in_col(e) )
				{
					for( f=mod2sparse_first_in_row(pchkMatrix,mod2sparse_row(e)); !mod2sparse_at_end(f); f=mod2sparse_next_in_row(f) )
					{
						if(f==e) continue;
						for(g=mod2sparse_first_in_col(pchkMatrix,mod2sparse_col(f)); !mod2sparse_at_end(g); g=mod2sparse_next_in_col(g) )
						{
							if(g==f) continue;
							for( h=mod2sparse_first_in_row(pchkMatrix,mod2sparse_row(g)); !mod2sparse_at_end(h); h = mod2sparse_next_in_row(h) )
							{
								if(mod2sparse_col(h)==j)
								{
									do
									{
										i = ldpc_rand(nbRows);
									}
									while (mod2sparse_find(pchkMatrix,i,j));
									mod2sparse_delete(pchkMatrix,e);
									mod2sparse_insert(pchkMatrix,i,j);
									elim4 += 1;
									k += 1;
									goto nextj;
								}
							}
						}
					}
				}
nextj: ;
			}
			if(k==0) break;
		}

		if(elim4>0)
		{
			fprintf(stderr, "Eliminated %d cycles of length four by moving checks within column\n", elim4);
		}

		if(t==10) 
		{
			fprintf(stderr, "Couldn't eliminate all cycles of length four in 10 passes\n");
		}
	}
#endif

	switch (type) {
	case TypeLDGM:
		for (i = 0; i < nbRows; i++) {
			/* identity */
			mod2sparse_insert(pchkMatrix, i, i);
		}
		break;

	case TypeSTAIRS:
		mod2sparse_insert(pchkMatrix, 0, 0);	/* 1st row */
		for (i = 1; i < nbRows; i++) {		/* for all other rows */
			/* identity */
			mod2sparse_insert(pchkMatrix, i, i);
			/* staircase */
			mod2sparse_insert(pchkMatrix, i, i-1);
		}
		break;

	case TypeTRIANGLE:
		mod2sparse_insert(pchkMatrix, 0, 0);	/* 1st row */
		for (i = 1; i < nbRows; i++) {		/* for all other rows */
			/* identity */
			mod2sparse_insert(pchkMatrix, i, i);
			/* staircase */
			mod2sparse_insert(pchkMatrix, i, i-1);
			/* triangle */	
			j = i-1;
			for (int l = 0; l < j; l++) { /* limit the # of "1s" added */
				j = ldpc_rand(j);
				mod2sparse_insert(pchkMatrix, i, j);
			}
		}
		break;
	}

	return pchkMatrix;
}
Пример #16
0
void make_ldpc
( int seed,		/* Random number seed */
  make_method method,	/* How to make it */
  distrib *d,		/* Distribution list specified */
  int no4cycle		/* Eliminate cycles of length four? */
)
{
  mod2entry *e, *f, *g, *h;
  int added, uneven, elim4, all_even, n_full, left;
  int i, j, k, t, z, cb_N;
  int *part, *u;

  rand_seed(10*seed+1);

  H = mod2sparse_allocate(M,N);
  part = column_partition(d,N);

  /* Create the initial version of the parity check matrix. */

  switch (method)
  { 
    case Evencol:
    { 
      z = 0;
      left = part[z];

      for (j = 0; j<N; j++)
      { while (left==0)
        { z += 1;
          if (z>distrib_size(d))
          { abort();
          }
          left = part[z];
        }
        for (k = 0; k<distrib_num(d,z); k++)
        { do
          { i = rand_int(M);
          } while (mod2sparse_find(H,i,j));
          mod2sparse_insert(H,i,j);
        }
        left -= 1;
      }

      break;
    }

    case Evenboth:
    {
      cb_N = 0;
      for (z = 0; z<distrib_size(d); z++)
      { cb_N += distrib_num(d,z) * part[z];
      }
      
      u = chk_alloc (cb_N, sizeof *u);

      for (k = cb_N-1; k>=0; k--)
      { u[k] = k%M;
      }
  
      uneven = 0;
      t = 0;
      z = 0;
      left = part[z];

      for (j = 0; j<N; j++)
      { 
        while (left==0)
        { z += 1;
          if (z>distrib_size(d))
          { abort();
          }
          left = part[z];
        }

	for (k = 0; k<distrib_num(d,z); k++)
        { 
          for (i = t; i<cb_N && mod2sparse_find(H,u[i],j); i++) ;

          if (i==cb_N)
          { uneven += 1;
            do
            { i = rand_int(M);
            } while (mod2sparse_find(H,i,j));
            mod2sparse_insert(H,i,j);
          }
          else
          { do
            { i = t + rand_int(cb_N-t);
            } while (mod2sparse_find(H,u[i],j));
            mod2sparse_insert(H,u[i],j);
            u[i] = u[t];
            t += 1;
          }
        }

        left -= 1;
      }

      if (uneven>0)
      { fprintf(stderr,"Had to place %d checks in rows unevenly\n",uneven);
      }

      break;
    }

    default: abort();
  }

  /* Add extra bits to avoid rows with less than two checks. */

  added = 0;

  for (i = 0; i<M; i++)
  { e = mod2sparse_first_in_row(H,i);
    if (mod2sparse_at_end(e))
    { j = rand_int(N);
      e = mod2sparse_insert(H,i,j);
      added += 1;
    }
    e = mod2sparse_first_in_row(H,i);
    if (mod2sparse_at_end(mod2sparse_next_in_row(e)) && N>1)
    { do 
      { j = rand_int(N); 
      } while (j==mod2sparse_col(e));
      mod2sparse_insert(H,i,j);
      added += 1;
    }
  }

  if (added>0)
  { fprintf(stderr,
           "Added %d extra bit-checks to make row counts at least two\n",
           added);
  }

  /* Add extra bits to try to avoid problems with even column counts. */

  n_full = 0;
  all_even = 1;
  for (z = 0; z<distrib_size(d); z++)
  { if (distrib_num(d,z)==M) 
    { n_full += part[z];
    }
    if (distrib_num(d,z)%2==1)
    { all_even = 0;
    }
  }

  if (all_even && N-n_full>1 && added<2)
  { int a;
    for (a = 0; added+a<2; a++)
    { do
      { i = rand_int(M);
        j = rand_int(N);
      } while (mod2sparse_find(H,i,j));
      mod2sparse_insert(H,i,j);
    }
    fprintf(stderr,
 "Added %d extra bit-checks to try to avoid problems from even column counts\n",
      a);
  }

  /* Eliminate cycles of length four, if asked, and if possible. */

  if (no4cycle)
  { 
    elim4 = 0;

    for (t = 0; t<10; t++) 
    { k = 0;
      for (j = 0; j<N; j++)
      { for (e = mod2sparse_first_in_col(H,j);
             !mod2sparse_at_end(e);
             e = mod2sparse_next_in_col(e))
        { for (f = mod2sparse_first_in_row(H,mod2sparse_row(e));
               !mod2sparse_at_end(f);
               f = mod2sparse_next_in_row(f))
          { if (f==e) continue;
            for (g = mod2sparse_first_in_col(H,mod2sparse_col(f));
                 !mod2sparse_at_end(g);
                 g = mod2sparse_next_in_col(g))
            { if (g==f) continue;
              for (h = mod2sparse_first_in_row(H,mod2sparse_row(g));
                   !mod2sparse_at_end(h);
                   h = mod2sparse_next_in_row(h))
              { if (mod2sparse_col(h)==j)
                { do
                  { i = rand_int(M);
                  } while (mod2sparse_find(H,i,j));
                  mod2sparse_delete(H,e);
                  mod2sparse_insert(H,i,j);
                  elim4 += 1;
                  k += 1;
                  goto nextj;
                }
              }
            }
          }
        }
      nextj: ;
      }
      if (k==0) break;
    }

    if (elim4>0)
    { fprintf(stderr,
        "Eliminated %d cycles of length four by moving checks within column\n",
         elim4);
    }

    if (t==10) 
    { fprintf(stderr,
        "Couldn't eliminate all cycles of length four in 10 passes\n");
    }
  }
}
Пример #17
0
mod2entry *mod2sparse_insert
( mod2sparse *m,
  int row,
  int col
)
{
#ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE
  mod2entry *re, *ce, *ne;
#else
  mod2entry *re, *ce, *ne, *ce2;
#endif

  if (row<0 || row>=mod2sparse_rows(m) || col<0 || col>=mod2sparse_cols(m))
  { fprintf(stderr,"mod2sparse_insert: row or column index out of bounds\n");
    exit(1);
  }

  /* Find old entry and return it, or allocate new entry and insert into row. */

  re = mod2sparse_last_in_row(m,row);

  if (!mod2sparse_at_end(re) && mod2sparse_col(re)==col) 
  { return re;
  }

  if (mod2sparse_at_end(re) || mod2sparse_col(re)<col) 
  { re = re->right;
  }
  else
  {
    re = mod2sparse_first_in_row(m,row);

    for (;;)
    { 
      if (!mod2sparse_at_end(re) && mod2sparse_col(re)==col) 
      { return re;
      }

      if (mod2sparse_at_end(re) || mod2sparse_col(re)>col)
      { break;
      } 

      re = mod2sparse_next_in_row(re);
    }
  }

  ne = alloc_entry(m);

  ne->row = row;
  ne->col = col;

  ne->left = re->left;
  ne->right = re;
  ne->left->right = ne;
  ne->right->left = ne;

  /* Insert new entry into column. */

#ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE
  /* If we find an existing entry here,
     the matrix must be garbled, since we didn't find it in the row. */

  ce = mod2sparse_last_in_col(m,col);

  if (!mod2sparse_at_end(ce) && mod2sparse_row(ce)==row) 
  { fprintf(stderr,"mod2sparse_insert: Garbled matrix\n");
    exit(1);
  }

  if (mod2sparse_at_end(ce) || mod2sparse_row(ce)<row) 
  { ce = ce->down;
  }
  else
  {
#else
    ce2 = &(m->cols[col]);
#endif
    ce = mod2sparse_first_in_col(m,col);

    for (;;)
    { 
      if (!mod2sparse_at_end(ce) && mod2sparse_row(ce)==row) 
      { fprintf(stderr,"mod2sparse_insert: Garbled matrix\n");
        exit(1);
      }

      if (mod2sparse_at_end(ce) || mod2sparse_row(ce)>row)
      { break;
      } 
#ifdef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE
      ce2 = ce;
#endif     
      ce = mod2sparse_next_in_col(ce);
    }    
    
#ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE
  }
  
  ne->up = ce->up;
  ne->down = ce;
  ne->up->down = ne;
  ne->down->up = ne;
#else    
  ne->down = ce;
  ce2->down = ne;
#endif

  /* Return the new entry. */

  return ne;
}
Пример #18
0
int mod2sparse_tunnel_sub
( mod2sparse *L,	/* Matrix that is lower triangular after reordering */
  int *rows,		/* Array of indexes (from 0) of rows for new order */
  char *x,		/* Vector on right of equation, also reordered */
  char *y		/* Place to store solution */
)
{
  int K, i, j, ii, b, d;
  mod2entry *e;

  K = mod2sparse_cols(L);

  /* Make sure that L is lower-triangular, after row re-ordering. */

  for (i = 0; i<K; i++)
  { ii = rows ? rows[i] : i;
    e = mod2sparse_last_in_row(L,ii);
    if (!mod2sparse_at_end(e) && mod2sparse_col(e)>i)
    { fprintf(stderr,
        "mod2sparse_tunnel_sub: Matrix is not lower-triangular\n");
      exit(1);
    }
  }

  /* Solve system by tunnel substitution. */

  for (i = 0; i<K; i++)
  { 
    ii = rows ? rows[i] : i;

    /* Look at bits in this row, forming inner product with partial 
       solution, and seeing if the diagonal is 1. */

    d = 0;
    b = 0;

    for (e = mod2sparse_first_in_row(L,ii); 
         !mod2sparse_at_end(e);
         e = mod2sparse_next_in_row(e))
    { 
      j = mod2sparse_col(e);

      if (j==i)
      { d = 1;
      }
      else
      { b ^= y[j];
      }
    }

    /* Check for no solution if the diagonal isn't 1. */

    if (!d && b!=x[ii]) 
    { return 0;
    }

    /* Set bit of solution, zero if arbitrary. */

    y[i] = b^x[ii];
  }

  return 1;
}
Пример #19
0
int mod2sparse_backward_sub
( mod2sparse *U,	/* Matrix that is upper triangular after reordering */
  int *cols,		/* Array of indexes (from 0) of columns for new order */
  char *y,		/* Vector on right of equation */
  char *z		/* Place to store solution, also reordered */
)
{
  int K, i, j, ii, b, d;
  mod2entry *e;

  K = mod2sparse_rows(U);

  /* Make sure that U is upper-triangular, after column re-ordering. */

  for (i = 0; i<K; i++)
  { ii = cols ? cols[i] : i;
    e = mod2sparse_last_in_col(U,ii);
    if (!mod2sparse_at_end(e) && mod2sparse_row(e)>i)
    { fprintf(stderr,
        "mod2sparse_backward_sub: Matrix is not upper-triangular\n");
      exit(1);
    }
  }

  /* Solve system by backward substitution. */

  for (i = K-1; i>=0; i--)
  { 
    ii = cols ? cols[i] : i;

    /* Look at bits in this row, forming inner product with partial 
       solution, and seeing if the diagonal is 1. */

    d = 0;
    b = 0;

    for (e = mod2sparse_first_in_row(U,i); 
         !mod2sparse_at_end(e);
         e = mod2sparse_next_in_row(e))
    { 
      j = mod2sparse_col(e);

      if (j==ii)
      { d = 1;
      }
      else
      { b ^= z[j];
      }
    }

    /* Check for no solution if the diagonal isn't 1. */

    if (!d && b!=y[i]) 
    { return 0;
    }

    /* Set bit of solution, zero if arbitrary. */

    z[ii] = b^y[i];
  }

  return 1;
}
Пример #20
0
int mod2sparse_decomp
( mod2sparse *A,	/* Input matrix, M by N */
  int K,		/* Size of sub-matrix to find LU decomposition of */
  mod2sparse *L,	/* Matrix in which L is stored, M by K */
  mod2sparse *U,	/* Matrix in which U is stored, K by N */
  int *rows,		/* Array where row indexes are stored, M long */
  int *cols,		/* Array where column indexes are stored, N long */
  mod2sparse_strategy strategy, /* Strategy to follow in picking rows/columns */
  int abandon_number,	/* Number of columns to abandon at some point */
  int abandon_when	/* When to abandon these columns */
)
{  
  int *rinv=NULL, *cinv=NULL, *acnt=NULL, *rcnt=NULL;
  mod2sparse *B=NULL;
  int M, N;

  mod2entry *e=NULL, *f=NULL, *fn=NULL, *e2=NULL;
  int i=0, j=0, k=0, cc=0, cc2=0, cc3=0, cr2=0, pr=0;
  int found, nnf;

  M = mod2sparse_rows(A);
  N = mod2sparse_cols(A);

  if (mod2sparse_cols(L)!=K || mod2sparse_rows(L)!=M
   || mod2sparse_cols(U)!=N || mod2sparse_rows(U)!=K)
  { fprintf (stderr,
      "mod2sparse_decomp: Matrices have incompatible dimensions\n");
    exit(1);
  }

  if (abandon_number>N-K)
  { fprintf(stderr,"Trying to abandon more columns than allowed\n");
    exit(1);
  }

  rinv = (int*)chk_alloc (M, sizeof *rinv);
  cinv = (int*)chk_alloc (N, sizeof *cinv);

  if (abandon_number>0)
  {
	  acnt = (int*)chk_alloc (M+1, sizeof *acnt);
  }

  if (strategy==Mod2sparse_minprod)
  {
	  rcnt = (int*)chk_alloc (M, sizeof *rcnt);
  }

  mod2sparse_clear(L);
  mod2sparse_clear(U);

  /* Copy A to B.  B will be modified, then discarded. */

  B = mod2sparse_allocate(M,N);
  mod2sparse_copy(A,B);

  /* Count 1s in rows of B, if using minprod strategy. */

  if (strategy==Mod2sparse_minprod)
  { for (i = 0; i<M; i++) 
    { rcnt[i] = mod2sparse_count_row(B,i);
    }
  }

  /* Set up initial row and column choices. */

  for (i = 0; i<M; i++) rows[i] = rinv[i] = i;
  for (j = 0; j<N; j++) cols[j] = cinv[j] = j;
 
  /* Find L and U one column at a time. */

  nnf = 0;

  for (i = 0; i<K; i++)
  { 
    /* Choose the next row and column of B. */

    switch (strategy)
    {
      case Mod2sparse_first: 
      { 
        found = 0;

        for (k = i; k<N; k++)
        { e = mod2sparse_first_in_col(B,cols[k]);
          while (!mod2sparse_at_end(e))
          { if (rinv[mod2sparse_row(e)]>=i)
            { found = 1;
              goto out_first;
            }
            e = mod2sparse_next_in_col(e);
          }
        }

      out_first:
        break;
      }

      case Mod2sparse_mincol:
      { 
        found = 0;

        for (j = i; j<N; j++)
        { cc2 = mod2sparse_count_col(B,cols[j]);
          if (!found || cc2<cc)
          { e2 = mod2sparse_first_in_col(B,cols[j]);
            while (!mod2sparse_at_end(e2))
            { if (rinv[mod2sparse_row(e2)]>=i)
              { found = 1;
                cc = cc2;
                e = e2;
                k = j;
                break;
              }
              e2 = mod2sparse_next_in_col(e2);
            }
          }
        }

        break;
      }

      case Mod2sparse_minprod:
      { 
        found = 0;

        for (j = i; j<N; j++)
        { cc2 = mod2sparse_count_col(B,cols[j]);
          e2 = mod2sparse_first_in_col(B,cols[j]);
          while (!mod2sparse_at_end(e2))
          { if (rinv[mod2sparse_row(e2)]>=i)
            { cr2 = rcnt[mod2sparse_row(e2)];
              if (!found || cc2==1 || (cc2-1)*(cr2-1)<pr)
              { found = 1;
                pr = cc2==1 ? 0 : (cc2-1)*(cr2-1);
                e = e2;
                k = j;
              }
            }
            e2 = mod2sparse_next_in_col(e2);
          }
        }

        break;
      }

      default:
      { fprintf(stderr,"mod2sparse_decomp: Unknown stategy\n");
        exit(1);
      }
    }

    if (!found) 
    { nnf += 1;
    }

    /* Update 'rows' and 'cols'.  Looks at 'k' and 'e' found above. */

    if (found)
    { 
      if (cinv[mod2sparse_col(e)]!=k) abort();

      cols[k] = cols[i];
      cols[i] = mod2sparse_col(e);

      cinv[cols[k]] = k;
      cinv[cols[i]] = i;

      k = rinv[mod2sparse_row(e)];

      if (k<i) abort();

      rows[k] = rows[i];
      rows[i] = mod2sparse_row(e);

      rinv[rows[k]] = k;
      rinv[rows[i]] = i;
    }

    /* Update L, U, and B. */

    f = mod2sparse_first_in_col(B,cols[i]); 

    while (!mod2sparse_at_end(f))
    { 
      fn = mod2sparse_next_in_col(f);
      k = mod2sparse_row(f);

      if (rinv[k]>i)
      { mod2sparse_add_row(B,k,B,mod2sparse_row(e));
        if (strategy==Mod2sparse_minprod) 
        { rcnt[k] = mod2sparse_count_row(B,k);
        }
        mod2sparse_insert(L,k,i);
      }
      else if (rinv[k]<i)
      { mod2sparse_insert(U,rinv[k],cols[i]);
      }
      else
      { mod2sparse_insert(L,k,i);
        mod2sparse_insert(U,i,cols[i]);
      }

      f = fn;
    }

    /* Get rid of all entries in the current column of B, just to save space. */

    for (;;)
    { f = mod2sparse_first_in_col(B,cols[i]);
      if (mod2sparse_at_end(f)) break;
      mod2sparse_delete(B,f);
    }

    /* Abandon columns of B with lots of entries if it's time for that. */

    if (abandon_number>0 && i==abandon_when)
    { 
      for (k = 0; k<M+1; k++) 
      { acnt[k] = 0;
      }
      for (j = 0; j<N; j++) 
      { k = mod2sparse_count_col(B,j);
        acnt[k] += 1;
      }

      cc = abandon_number;
      k = M;
      while (acnt[k]<cc)
      { cc -= acnt[k];
        k -= 1;
        if (k<0) abort();
      }

      cc2 = 0;
      for (j = 0; j<N; j++)
      { cc3 = mod2sparse_count_col(B,j);
        if (cc3>k || cc3==k && cc>0)
        { if (cc3==k) cc -= 1;
          for (;;)
          { f = mod2sparse_first_in_col(B,j);
            if (mod2sparse_at_end(f)) break;
            mod2sparse_delete(B,f);
          }
          cc2 += 1;
        }
      }

      if (cc2!=abandon_number) abort();

      if (strategy==Mod2sparse_minprod)
      { for (j = 0; j<M; j++) 
        { rcnt[j] = mod2sparse_count_row(B,j);
        }
      }
    }
  }

  /* Get rid of all entries in the rows of L past row K, after reordering. */

  for (i = K; i<M; i++)
  { for (;;)
    { f = mod2sparse_first_in_row(L,rows[i]);
      if (mod2sparse_at_end(f)) break;
      mod2sparse_delete(L,f);
    }
  }

  mod2sparse_free(B);
  free(rinv);
  free(cinv);
  if (strategy==Mod2sparse_minprod) free(rcnt);
  if (abandon_number>0) free(acnt);

  return nnf;
}
Пример #21
0
int main
( int argc,
  char **argv
)
{
  char *alist_file, *pchk_file;
  FILE *af, *pf;
  int mxrw, mxcw;
  int *rw, *cw;
  int i, j, k;
  mod2entry *e;
  int trans;
  int nozeros;
  int last;

  trans = 0;
  nozeros = 0;

  for (;;)
  {
    if (argc>1 && strcmp(argv[1],"-t")==0)
    { trans = 1;
      argc -= 1;
      argv += 1;
    }
    else if (argc>1 && strcmp(argv[1],"-z")==0)
    { nozeros = 1;
      argc -= 1;
      argv += 1;
    }
    else
    { break;
    }
  }

  if (argc!=3)
  { usage();
  }

  pchk_file = argv[1];
  alist_file = argv[2];

  read_pchk(pchk_file);

  if (trans)
  { mod2sparse *HT;
    HT = H;
    H = mod2sparse_allocate(N,M);
    mod2sparse_transpose(HT,H);
    M = mod2sparse_rows(H);
    N = mod2sparse_cols(H);
  }

  af = open_file_std(alist_file,"wb");

  if (af==NULL) 
  { fprintf(stderr,"Can't create alist file: %s\n",alist_file);
    exit(1);
  }

  fprintf(af,"%d %d\n",M,N);

  rw = (int *) chk_alloc (M, sizeof *rw);
  mxrw = 0;

  for (i = 0; i<M; i++)
  { rw[i] = mod2sparse_count_row(H,i);
    if (rw[i]>mxrw)
    { mxrw = rw[i];
    }
  }

  cw = (int *) chk_alloc (N, sizeof *cw);
  mxcw = 0;

  for (j = 0; j<N; j++)
  { cw[j] = mod2sparse_count_col(H,j);
    if (cw[j]>mxcw)
    { mxcw = cw[j];
    }
  }

  fprintf(af,"%d %d\n",mxrw,mxcw);

  for (i = 0; i<M; i++)
  { fprintf(af,"%d%c",rw[i],i==M-1?'\n':' ');
  }

  for (j = 0; j<N; j++)
  { fprintf(af,"%d%c",cw[j],j==N-1?'\n':' ');
  }

  for (i = 0; i<M; i++)
  { e = mod2sparse_first_in_row(H,i);
    last = 0;
    for (k = 0; !last; k++)
    { last = nozeros ? k==rw[i]-1 : k==mxrw-1;
      fprintf (af, "%d%c", mod2sparse_at_end(e)?0:mod2sparse_col(e)+1,
                           last?'\n':' ');
      if (!mod2sparse_at_end(e)) 
      { e = mod2sparse_next_in_row(e);
      }
    }
  }

  for (j = 0; j<N; j++)
  { e = mod2sparse_first_in_col(H,j);
    last = 0;
    for (k = 0; !last; k++)
    { last = nozeros ? k==cw[j]-1 : k==mxcw-1;
      fprintf (af, "%d%c", mod2sparse_at_end(e)?0:mod2sparse_row(e)+1,
                           last?'\n':' ');
      if (!mod2sparse_at_end(e)) 
      { e = mod2sparse_next_in_col(e);
      }
    }
  }

  if (ferror(af) || fclose(af)!=0)
  { fprintf(stderr,"Error writing to alist file %s\n",alist_file);
    exit(1);
  }

  return 0;
}