This module implements operations on matrices in which the elements are all 0 or 1, with addition and multiplication being done modulo 2. The matrices are represented by doubly-linked lists of entries representing the elements in each row and column that are 1s, with other elements being assumed to be zero.

This is an appropriate representation when the matrices are sparse (ie, 0s are much more frequent that 1s). Matrices in which 0s and 1s are about equally likely may be better handled with the dense modulo-2 matrix routines. Matrices can be converted between these two formats using the module-2 matrix conversion routines.

All procedures in this module display an error message on standard error and terminate the program if passed an invalid argument (indicative of a programming error), or if memory cannot be allocated. Errors from invalid contents of a file result in an error code being returned to the caller, with no message being printed by this module.

This module represents a non-zero element of a matrix (which must have
the value 1, since these are modulo-2 matrices) by a node of type
`mod2entry`, which contains the row and column of the element,
pointers to the next non-zero elements above and below in its column
and to the left and the right in its row, and two double-precision
floating-point numbers called **pr** and **lr**, which are
of no significance to this module, but which are used by the routines
for decoding LDPC codes by probability
propagation.

The `mod2sparse` type represents a matrix. It records the
number of rows and columns in the matrix, and contains arrays of
pointers to the `mod2entry` structures for the first non-zero
element in each row and the first non-zero element in each column.

Matrices must be created by the `mod2sparse_allocate` procedure, which
returns a pointer to a `mod2sparse` structure. When a matrix
is no longer needed, the space it occupies can be freed with `mod2sparse_free`. Elements within a matrix,
represented by `mod2entry` nodes, are allocated as needed, and
if deleted, they will be reused for new elements within the same
matrix. The space they occupy is not reusable for other matrices or
other purposes until the entire matrix is either freed, with `mod2sparse_free`, or cleared to all zeros,
with `mod2sparse_clear`, or used as
the result matrix for copying or arithmetic operations.

**Header files required**:
`mod2sparse.h`

The following macros take a pointer to a mod2sparse structure as their argument, and return the number of rows or the number of columns in the matrix pointed to, which will have been fixed when the matrix was created with mod2sparse_allocate:

mod2sparse_rows(m) /* Returns the number of rows in m */ mod2sparse_cols(m) /* Returns the number of columns in m */

The following macros are used to move around a sparse matrix by following the pointers from one non-zero element to the next or previous non-zero element in the same row or column. If such a movement takes one beyond the last or before first entry in a row or column, or if one tries to find the first or last non-zero entry in a row or column that has no non-zero entries, the entry returned will be a special one that can be identified using the

The macros for finding the first or last entry in a row or column
take as their arguments a pointer to the matrix (`mod2sparse
*`) and a row or column index, starting at zero. The other macros
take as their arguments a pointer to an entry (`mod2entry *`)
within some matrix.

mod2sparse_first_in_row(m,i) /* Returns the first entry in row i of m */ mod2sparse_first_in_col(m,j) /* Returns the first entry in column j of m */ mod2sparse_last_in_row(m,i) /* Returns the last entry in row i of m */ mod2sparse_last_in_col(m,j) /* Returns the last entry in column j of m */ mod2sparse_next_in_row(e) /* Returns the entry after e in its row */ mod2sparse_next_in_col(e) /* Returns the entry after e in its column */ mod2sparse_prev_in_row(e) /* Returns the entry before e in its row */ mod2sparse_prev_in_col(e) /* Returns the entry before e in its col */ mod2sparse_row(e) /* Returns the row index of entry e */ mod2sparse_col(e) /* Returns the column index of entry e */ mod2sparse_at_end(e) /* Returns 1 if e is a special entry obtained by moving past the end, returns 0 otherwise */

Allocates space for a matrix with the given number of rows and columns, and returns a pointer to it. The matrix will initially be all zero.mod2sparse *mod2sparse_allocate ( int n_rows, /* Number of rows in matrix */ int n_cols /* Number of columns in matrix */ )

If there is not enough memory available, a message is displayed on
standard error and the program is terminated. The matrix should be
freed with `mod2sparse_free` once it is no
longer in use.

Frees the space occupied by the matrix for re-use. The pointer passed should not be used afterward. Note that space for the individual matrix elements (but not the matrix as a whole) is also freed whenvoid mod2sparse_free ( mod2sparse *m /* Pointer to matrix to free */ )

Sets all of the elements of the matrix passed to 0. The space occupied by the previous non-zero elements is freed for use in other matrices, or other purposes. The matrix itself is not freed, however. To do that, usevoid mod2sparse_clear ( mod2sparse *m /* Pointer to matrix to clear */ )

Copies the contents of the first matrix passed,void mod2sparse_copy ( mod2sparse *m /* Pointer to matrix to copy from */ mod2sparse *r /* Pointer to matrix to receive data */ )

The space occupied by the previous non-zero entries of **r** is
freed for general use (which may include being reused immediately for
the copies of the entries in **m**).

Copies selected rows of the first matrix,void mod2sparse_copyrows ( mod2sparse *m, /* Pointer to matrix to copy rows from */ mod2sparse *r, /* Pointer to matrix in which to store data */ int *rows /* Indexes of rows, numbered from 0 */ )

The space occupied by the previous non-zero entries of **r** is
freed for general use (which may include being reused immediately for
the copies of the entries in **m**).

Copies selected columns of the first matrix,void mod2sparse_copycols ( mod2sparse *m, /* Pointer to matrix to copy columns from */ mod2sparse *r, /* Pointer to matrix in which to store data */ int *cols /* Indexes of columns, numbered from 0 */ )

The space occupied by the previous non-zero entries of **r** is
freed for general use (which may include being reused immediately for
the copies of the entries in **m**).

The matrix is printed on standard output with one line of output per row, of the formvoid mod2sparse_print ( FILE *f, /* File to print to */ mod2sparse *m /* Pointer to matrix to print */ )

whererow:col col col ...

Writes a machine-readable representation the sparse matrixint mod2sparse_write ( FILE *f, /* File to write data to */ mod2sparse *m /* Pointer to matrix write out */ )

The data written to the file starts with the number of rows and the
number of columns. Following this are negative integers giving row
indexes (starting at 1), which apply until the next row index, and
positive integers giving column indexes (starting at 1) for a non-zero
entry in the matrix. The data should be readable by `mod2sparse_read` even on a machine with a
different byte-ordering.

The value returned by `mod2sparse_write` is one if the
operation was successful, zero if an error of some sort occurred.

Reads a sparse modulo-2 matrix from the filemod2sparse *mod2sparse_read ( FILE *f, /* File to read data from */ )

The value returned is a pointer to the matrix read, for which space
will have been allocated by `mod2sparse_read`, or zero if an
error occurred (either an error reading the file, or data not in the
right format).

Looks for an entry at the given row and column in the matrixmod2entry *mod2sparse_find ( mod2sparse *m, /* Matrix in which to look for entry */ int row, /* Row index (from 0) */ int col /* Column index (from 0) */ )

The search strategy is to first look at the end of the row and the end of the column. The entry might be found at one of these two places, or it might be determinable from these end entries that no entry exists at the given row and column. Otherwise, searches are done from the start of the row and the start of the column, in parallel, until an entry with the given row and column are found, or until it can be determined that such an entry does not exist. Searching in parallel ensures that the operation will be fast if either the row is sparse or the column is sparse.

Adds a new entry (representing an element with value 1) at the given row and column position in the matrixmod2entry *mod2sparse_insert ( mod2sparse *m, /* Matrix in which to insert an entry */ int row, /* Row index (from 0) */ int col /* Column index (from 0) */ )

The search strategy is to first look at the end of the row for an existing entry or for the place where the new entry belongs. If this fails, the row is searched from the beginning. If an existing entry is found, it is returned. Otherwise, a new entry is created, it is inserted in its correct place in the row, and it is inserted in its correct place in its column, once again by first looking at the end, and then if required searching from the beginning.

The effect of this strategy is that a sparse matrix can be efficiently created by either adding entries in increasing order by row and column or in decreasing order by row and column.

Deletes the entryvoid mod2sparse_delete ( mod2sparse *m, /* Matrix in which to delete an entry */ mod2entry *e /* Entry to delete - MUST be in m */ )

The time required for this operation does not depend on how many entries are currently in the matrix.

**Warning:** It is an error if **e** is not an entry of
**m**. This error is not currently diagnosed, but doing this may
cause serious problems, as it may lead later to entries for **m**
being erroneously freed when the matrix to which **e** properly
belongs is freed.

Stores the transpose of its first argument,void mod2sparse_transpose ( mod2sparse *m, /* Matrix to compute transpose of */ mod2sparse *r /* Result of transpose operation */ )

The space occupied by the previous non-zero entries of **r** is
freed for general use.

Adds matricesvoid mod2sparse_add ( mod2sparse *m1, /* Left operand of add */ mod2sparse *m2, /* Right operand of add */ mod2sparse *r /* Place to store result of add */ )

The space occupied by the previous non-zero entries of **r** is
freed for general use.

Does a matrix multiplication ofvoid mod2sparse_multiply ( mod2sparse *m1, /* Left operand of multiply */ mod2sparse *m2, /* Right operand of multiply */ mod2sparse *r /* Place to store result of multiply */ )

The space occupied by the previous non-zero entries of **r** is
freed for general use.

Multiplies the vectorvoid mod2sparse_mulvec ( mod2sparse *m, /* Pointer to matrix to multiply by, M rows, N columns */ char *u, /* Pointer to unpacked vector to multiply, N long */ char *v /* Pointer to unpacked result vector, M long */ )

Returns one if every element ofint mod2sparse_equal ( mod2sparse *m1, /* Pointers to the two matrices */ mod2sparse *m2 /* to compare */ )

Returns the number of 1s in the given row of the matrix, by counting the number of entries in that row.int mod2sparse_count_row ( mod2sparse *m, /* Pointer to matrix */ int row /* Index of row to count (from 0) */ )

Returns the number of 1s in the given column of the matrix, by counting the number of entries in that column.int mod2sparse_count_col ( mod2sparse *m, /* Pointer to matrix */ int col /* Index of column to count (from 0) */ )

Modifies the row with indexvoid 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 */ )

Modifies the column with indexvoid mod2sparse_add_col ( mod2sparse *m1, /* Matrix containing column to add to */ int col1, /* Index in this matrix of col to add to */ mod2sparse *m2, /* Matrix containing column to add from */ int col2 /* Index in this matrix of column to add from */ )

int mod2sparse_decomp ( mod2sparse *A, /* Matrix to find LU decomposition within, 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 */ )

Takes as input a matrix, **A**, having *M* rows and
*N* columns, and an integer *K*. Finds an LU decomposition
of a *K* by *K* sub-matrix of **A**. The decomposition
is stored in the matrix **L**, with *M* rows and *K*
columns, and the matrix **U**, with *K* rows and *N*
columns. The product of **L** and **U** will be equal to the
*K* by *K* submatrix of **A** obtained by taking only
rows and columns that are given in the first *K* elements of the
**rows** and **cols** arrays, which are set by this procedure,
with this sub-matrix distributed over the original *M* rows and
*N* columns. Furthermore, the ordering of the row and column
indexes in these arrays will be set so that if the rows of **L**
and the columns of **U** were rearranged in this order, **L**
would be lower triangular, with zeros in rows past row *K*, and
**U** would be upper triangular, with zeros in columns past column
*K*. The **rows** array is *M* long, and the **cols**
array is *N* long. The elements in both arrays after the first
*K* contain the indexes of the rows and columns not selected to
be part of the sub-matrix of **A**, in arbitrary order.

The rows and columns of **A** are selected in order to try to
make the LU decomposition as sparse as possible, using the strategy
identified by the **strategy**, **abandon_number**, and
**abandon_when** parameters. The possible strategies are
`Mod2sparse_first`, `Mod2sparse_mincol`, and
`Mod2sparse_minprod`. If **abandon_number** is greater than
zero, it is possible that the matrix will appear to have linearly
dependent rows when it actually does not. See the discussion of sparse LU decomposition
methods for details about these strategies.

If **A** is not of rank *K* or more, **L** will contain
some number less than *K* of non-zero columns, and **U** will
contain an equal number of non-zero rows. The entries in the
**rows** and **cols** arrays for the extra zero rows or columns
will be arbitrary (but valid). The number of extra zero columns is
returned as the value of this procedure (hence a return value of zero
indicates that a *K* by *K* sub-matrix of full rank was
found).

The matrix **A** is not altered. The previous contents of
**L** and **U** are cleared.

int mod2sparse_forward_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 */ )

Solves the system of equations **Ly**=**x** for **y** by
forward substitution, based on **L** being lower triangular after
its rows are reordered according to the given index array. The
vectors **x** and **y** are stored unpacked, one bit per
character. If **L** is *M* by *K*, then **x** should
be *M* long, but only the *K* bits indexed by **rows**
are looked at. The solution vector, **y**, must be *K* long.
Only *K* rows of **L** are used, as also determined by the
*K* indexes in the **rows** argument. If **rows** is null,
the first *K* rows of **L** and the first *K* elements of
**x** are used.

If the matrix **L** does not have 1s on its diagonal (after row
rearrangement), there may be no solution, depending on what **x**
is. If no solution exists, this procedure returns zero, otherwise it
returns one. Any arbitrary bits in the solution are set to zero.

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 */ )

Solves **Uz**=**y** for **z** by backward substitution,
based on **U** being upper triangular after its columns are
reordered according to the given index array. The vectors **y**
and **z** are stored unpacked, one bit per character. If **U**
is *K* by *N*, then the solution vector, *z*, should be
*N* long, but only the *K* bits indexed by **cols** are
set. The vector **y** must be *K* long. Only *K* columns
of **U** are used, as also determined by the *K* indexes in
the **cols** argument. The other columns of **U** must be zero
(this is not checked, but is necessary for the method used to work).
If **cols** is null, the first *K* columns of **U** and the
first *K* elements of **z** are used.

If the matrix **U** does not have 1s on its diagonal (after
column rearrangement) there may be no solution, depending on what y
is. If no solution exists, this procedure returns zero, otherwise it
returns one. Any arbitrary bits in the solution are set to zero.

Back to index for LDPC software