mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-01 16:13:57 -04:00
5ac886855d
git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6437 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
488 lines
18 KiB
HTML
Executable File
488 lines
18 KiB
HTML
Executable File
<HTML><HEAD>
|
|
|
|
<TITLE> Dense Modulo-2 Matrix Routines </TITLE>
|
|
|
|
</HEAD><BODY>
|
|
|
|
|
|
<H1> Dense Modulo-2 Matrix Routines </H1>
|
|
|
|
<P>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 stored with consecutive bits of a column packed into
|
|
32-bit words, and the procedures are implemented where possible using
|
|
bit operations on these words.
|
|
|
|
<P>This is an appropriate representation when the matrices are dense
|
|
(ie, 0s and 1s are about equally frequent). Matrices in which most
|
|
elements are 0s may be better handled with the <A
|
|
HREF="mod2sparse.html">sparse modulo-2 matrix routines</A>. Matrices
|
|
can be converted between these two formats using the <A
|
|
HREF="mod2convert.html">module-2 matrix conversion routines</A>.
|
|
|
|
<P>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.
|
|
|
|
|
|
<H2>Representation of dense matrices</H2>
|
|
|
|
<P>This module represents a matrix by a pointer to a structure of type
|
|
<TT>mod2dense</TT>. This structure records the number of rows and
|
|
columns in the matrix, and contains an array of pointers to where the
|
|
bits making up each column are stored. These bits are packed 32 per
|
|
word. When possible, bits in a column are manipulated 32 bits at a
|
|
time, which operations such as adding one column to another much
|
|
faster than the corresponding operations on rows. The pointer
|
|
structure also allows the columns of a matrix to easily be rearranged,
|
|
which may be necessary when doing matrix inversion.
|
|
|
|
|
|
<P><B>Header files required</B>:
|
|
<TT>mod2dense.h</TT>
|
|
|
|
|
|
<A NAME="dimension-sec">
|
|
<P><HR>
|
|
<CENTER><BIG>Dimension Macros</BIG></CENTER>
|
|
</A>
|
|
|
|
<HR>The following macros take a pointer to a mod2dense 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 <A HREF="#allocate">mod2dense_allocate</A>:
|
|
<BLOCKQUOTE><PRE>
|
|
mod2dense_rows(m) /* Returns the number of rows in m */
|
|
|
|
mod2dense_cols(m) /* Returns the number of columns in m */
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
|
|
<A NAME="alloc-sec">
|
|
<P><HR>
|
|
<CENTER><BIG>Allocating and Freeing Dense Modulo-2 Matrices</BIG></CENTER>
|
|
</A>
|
|
|
|
|
|
<A NAME="allocate"><HR><B>mod2dense_allocate</B>:
|
|
Allocate space for a dense module-2 matrix.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
mod2dense *mod2dense_allocate
|
|
( int n_rows, /* Number of rows in matrix */
|
|
int n_cols /* Number of columns in matrix */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Allocates space for a matrix with the given number of rows and
|
|
columns, and returns a pointer to it. 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 <A
|
|
HREF="#free"><TT>mod2dense_free</TT></A> once it is no longer in use.
|
|
|
|
<P><A NAME="free"><HR><B>mod2dense_free</B>:
|
|
Free the space occupied by a dense module-2 matrix.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_free
|
|
( mod2dense *m /* Pointer to matrix to free */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Frees the space occupied by the matrix for re-use. The pointer passed
|
|
should no longer be used.
|
|
|
|
|
|
<A NAME="copy-clear-sec">
|
|
<P><HR>
|
|
<CENTER><BIG>Copying and Clearing Dense Modulo-2 Matrices</BIG></CENTER>
|
|
</A>
|
|
|
|
<A NAME="clear"><HR><B>mod2dense_clear</B>:
|
|
Set all elements of a matrix to zero.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_clear
|
|
( mod2dense *m /* Pointer to matrix to clear */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Sets all of the elements of the matrix passed to 0.
|
|
|
|
<P><A NAME="copy"><HR><B>mod2dense_copy</B>:
|
|
Copy the contents of one matrix to another.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_copy
|
|
( mod2dense *m /* Pointer to matrix to copy from */
|
|
mod2dense *r /* Pointer to matrix to receive data */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Copies the contents of the first matrix passed, <B>m</B>, to the
|
|
second matrix passed, <B>r</B>, which must already have been
|
|
allocated, and must have at least as many rows and columns as the
|
|
first. If <B>r</B> is larger than <B>m</B>, its elements that have
|
|
row or column indexes greater than the dimension of <B>m</B> are set
|
|
to zeros.
|
|
|
|
|
|
<P><A NAME="copyrows"><HR><B>mod2dense_copyrows</B>:
|
|
Copy selected rows from one matrix to another.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_copyrows
|
|
( mod2dense *m, /* Pointer to matrix to copy columns from */
|
|
mod2dense *r, /* Pointer to matrix in which to store data */
|
|
int *rows /* Indexes of rows, numbered from 0 */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Copies selected rows of the first matrix, <B>m</B>, to the second
|
|
matrix, <B>r</B>, which must already have been allocated, and which
|
|
must have at least as many columns as <B>m</B>. The indexes of the
|
|
rows to copy are given in order as an array of length the same as
|
|
the number of rows in <B>r</B>; duplicates are allowed. Row
|
|
indexes start at 0. These rows are copied to <B>r</B>, with the
|
|
row indexed by the first entry in <B>rows</B> going to the first
|
|
row of <B>r</B>, and so forth. If <B>r</B> has more columns than
|
|
<B>m</B>, the extra entries in each row are set to zeros.
|
|
|
|
|
|
<P><A NAME="copycols"><HR><B>mod2dense_copycols</B>:
|
|
Copy selected columns from one matrix to another.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_copycols
|
|
( mod2dense *m, /* Pointer to matrix to copy columns from */
|
|
mod2dense *r, /* Pointer to matrix in which to store data */
|
|
int *cols /* Indexes of columns, numbered from 0 */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Copies selected columns of the first matrix, <B>m</B>, to the second
|
|
matrix, <B>r</B>, which must already have been allocated, and which
|
|
must have at least as many rows as <B>m</B>. The indexes of the
|
|
columns to copy are given in order as an array of length the same as
|
|
the number of columns in <B>r</B>; duplicates are allowed. Column
|
|
indexes start at 0. These columns are copied to <B>r</B>, with the
|
|
column indexed by the first entry in <B>cols</B> going to the first
|
|
column of <B>r</B>, and so forth. If <B>r</B> has more rows than
|
|
<B>m</B>, the extra entries in each column are set to zeros.
|
|
|
|
|
|
<A NAME="input-output-sec">
|
|
<P><HR>
|
|
<CENTER><BIG>Input and Output of Dense Modulo-2 Matrices</BIG></CENTER>
|
|
</A>
|
|
|
|
<A NAME="print"><HR><B>mod2dense_print</B>:
|
|
Print a dense modulo-2 matrix in human-readable form.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_print
|
|
( FILE *f, /* File to print to */
|
|
mod2dense *m /* Pointer to matrix to print */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
The matrix is printed on standard output as "0" and "1" characters,
|
|
each preceded by a space, with one line of "0"s and "1"s for each row
|
|
of the matrix.
|
|
|
|
<P><A NAME="write"><HR><B>mod2dense_write</B>:
|
|
Write a dense modulo-2 matrix to a file in machine-readable format.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
int mod2dense_write
|
|
( FILE *f, /* File to write data to */
|
|
mod2dense *m /* Pointer to matrix write out */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Writes a machine-readable representation the dense matrix <B>m</B> to
|
|
the file <B>f</B>. The file should have been opened in binary mode
|
|
(with a "b" in the mode passed to fopen). The contents written will
|
|
not be text, and will not be human-readable. Other binary data may
|
|
precede or follow the data for the matrix written.
|
|
|
|
<P>The data written to the file consists of the number of rows and the
|
|
number of columns, followed by the bits in each column, packed into
|
|
32-bit words. The data should be readable by <A
|
|
HREF="#read"><TT>mod2dense_read</TT></A> even on a machine with a
|
|
different byte-ordering.
|
|
|
|
<P>The value returned by <TT>mod2dense_write</TT> is one if the
|
|
operation was successful, zero if an error of some sort occurred.
|
|
|
|
<P><A NAME="read"><HR><B>mod2dense_read</B>:
|
|
Read a dense modulo-2 matrix from a file.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
mod2dense *mod2dense_read
|
|
( FILE *f, /* File to read data from */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Reads a dense modulo-2 matrix from the file <B>f</B>. This file
|
|
should have been opened in binary mode (with a "b" in the mode passed
|
|
to fopen). The contents of the file at the point when
|
|
<TT>mod2dense_read</TT> is called should have been written by <A
|
|
HREF="#write"><TT>mod2dense_write</TT></A>. Other binary data may
|
|
precede or follow this data.
|
|
|
|
<P>The value returned is a pointer to the matrix read, for which space
|
|
will have been allocated by <TT>mod2dense_read</TT>, or zero if an
|
|
error occurred (either an error reading the file, or data not in the
|
|
right format).
|
|
|
|
|
|
<A NAME="elementary-sec">
|
|
<P><HR>
|
|
<CENTER><BIG>Elementary Operations on Dense Modulo-2 Matrices</BIG></CENTER>
|
|
</A>
|
|
|
|
<A NAME="get"><HR><B>mod2dense_get</B>:
|
|
Get an element of a dense modulo-2 matrix.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
int mod2dense_get
|
|
( mod2dense *m, /* Pointer to matrix to get element from */
|
|
int row, /* Row of element (indexed from zero) */
|
|
int col /* Column of element (indexed from zero) */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Returns the value (0 or 1) of the element in the given row and column
|
|
of the matrix <B>m</B>.
|
|
|
|
<P><A NAME="set"><HR><B>mod2dense_set</B>:
|
|
Set an element of a dense modulo-2 matrix.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_set
|
|
( mod2dense *m, /* Pointer to matrix to get element from */
|
|
int row, /* Row of element (indexed from zero) */
|
|
int col, /* Column of element (indexed from zero) */
|
|
int value /* New value of element (0 or 1) */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Set the element in the given row and column of the matrix <B>m</B> to
|
|
the specified value.
|
|
|
|
<P><A NAME="flip"><HR><B>mod2dense_flip</B>:
|
|
Flip an element of a dense modulo-2 matrix.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
int mod2dense_flip
|
|
( mod2dense *m, /* Pointer to matrix to get element from */
|
|
int row, /* Row of element (indexed from zero) */
|
|
int col /* Column of element (indexed from zero) */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Flips the value of the element in the given row and column of the
|
|
matrix <B>m</B>, changing it to 0 if it was 1, and to 1 if it was 0.
|
|
Returns the new value of this element.
|
|
|
|
|
|
<A NAME="arith-sec">
|
|
<P><HR>
|
|
<CENTER><BIG>Dense Modulo-2 Matrix Arithmetic and Comparison</BIG></CENTER>
|
|
</A>
|
|
|
|
<A NAME="transpose"><HR><B>mod2dense_transpose</B>:
|
|
Compute the transpose of a dense modulo-2 matrix.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_transpose
|
|
( mod2dense *m, /* Matrix to compute transpose of */
|
|
mod2dense *r /* Result of transpose operation */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Stores the transpose of its first argument, <B>m</B>, in the matrix
|
|
pointed to by its second argument, <B>r</B>, which must already have
|
|
been allocated, and which must have as many rows as <B>m</B> has
|
|
columns, and as many columns as <B>m</B> has rows. The two matrices
|
|
<B>m</B> and <B>r</B> must not be the same (ie, the two pointers
|
|
passed must be different).
|
|
|
|
<P><A NAME="add"><HR><B>mod2dense_add</B>:
|
|
Add two dense modulo-2 matrices.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_add
|
|
( mod2dense *m1, /* Left operand of add */
|
|
mod2dense *m2, /* Right operand of add */
|
|
mod2dense *r /* Place to store result of add */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Adds matrices <B>m1</B> and <B>m2</B>, storing the result in the
|
|
matrix pointed to by <B>r</B>. All three matrices must have the same
|
|
numbers of rows and columns. It is permissible for <B>r</B> to be the
|
|
same as <B>m1</B> and/or <B>m2</B>. Neither of the first two matrices is
|
|
changed by this procedure (unless they are the same as <B>r</B>).
|
|
|
|
|
|
<P><A NAME="multiply"><HR><B>mod2dense_multiply</B>:
|
|
Multiply two dense modulo-2 matrices.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
void mod2dense_multiply
|
|
( mod2dense *m1, /* Left operand of multiply */
|
|
mod2dense *m2, /* Right operand of multiply */
|
|
mod2dense *r /* Place to store result of multiply */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Does a matrix multiplication of <B>m1</B> by <B>m2</B>, and stores the
|
|
result in the matrix pointed to by <B>r</B>. The matrices must have
|
|
compatible numbers of rows and columns. Neither of the first two
|
|
matrices is changed by this procedure. The result matrix, <B>r</B>,
|
|
must not be the same as either <B>m1</B> or <B>m2</B>.
|
|
|
|
<P>The algorithm used runs faster if <B>m2</B> contains mostly 0s, but
|
|
it is also appropriate for matrices with many 1s.
|
|
|
|
<P><A NAME="equal"><HR><B>mod2dense_equal</B>:
|
|
Check whether two dense modulo-2 matrices are equal.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
int mod2dense_equal
|
|
( mod2dense *m1, /* Pointers to the two matrices */
|
|
mod2dense *m2 /* to compare */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Returns one if every element of <B>m1</B> is equal to the
|
|
corresponding element of <B>m2</B>, and otherwise returns zero. The
|
|
two matrices must have the same number of rows and the same number of
|
|
columns.
|
|
|
|
<A NAME="invert-sec">
|
|
<P><HR>
|
|
<CENTER><BIG>Dense Modulo-2 Matrix Inversion</BIG></CENTER>
|
|
</A>
|
|
|
|
<A NAME="invert"><HR><B>mod2dense_invert</B>:
|
|
Invert a dense modulo-2 matrix.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
int mod2dense_invert
|
|
( mod2dense *m, /* Matrix to find inverse of (destroyed) */
|
|
mod2dense *r /* Place to store the inverse */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<P>Inverts the first matrix passed, <B>m</B>, and stores its inverse in
|
|
the second matrix, <B>r</B>. The contents of <B>m</B> are destroyed
|
|
by this operation, though it remains a valid matrix for storing into
|
|
later. The matrix <B>m</B> must have the same number of rows as
|
|
columns. The matrix <B>r</B> must already have been allocated, and
|
|
must have the same number of rows and columns as <B>m</B>. The
|
|
two matrices passed must not be the same.
|
|
|
|
<P>The value returned is one if the inversion was successful and zero
|
|
if the matrix turned out to be singular (in which case the contents of
|
|
both the original matrix and the result matrix will be garbage).
|
|
|
|
<P>The algorithm used is based on inverting M by transforming the equation
|
|
MI = M to the equation MR = I using column operations, at which point R
|
|
is the inverse of M. The representation of matrices used allows easy
|
|
swapping of columns as needed by fiddling pointers.
|
|
|
|
<P><A NAME="forcibly_invert"><HR><B>mod2dense_forcibly_invert</B>:
|
|
Forcibly invert a matrix by changing bits if necessary.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
int mod2dense_forcibly_invert
|
|
( mod2dense *m, /* Matrix to find inverse of (destroyed) */
|
|
mod2dense *r, /* Place to store the inverse */
|
|
int *a_row, /* Place to store row indexes of altered elements */
|
|
int *a_col /* Place to store column indexes of altered elements */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<P>Inverts the first matrix passed, <B>m</B>, and stores its inverse
|
|
in the second matrix, <B>r</B>, proceeding with the inversion even if
|
|
<B>m</B> is singular, by changing some elements as necessary. The
|
|
contents of <B>m</B> are destroyed by this operation, though it
|
|
remains a valid matrix for storing into later. The matrix <B>m</B>
|
|
must have the same number of rows as columns. The matrix <B>r</B>
|
|
must already have been allocated, and must have the same number of
|
|
rows and columns as <B>m</B>. The two matrices passed must not be the
|
|
same.
|
|
|
|
<P>The value returned is the number of elements of <B>m</B> that had
|
|
to be changed to make inversion possible (zero, if the original matrix
|
|
was non-singular). The row and column indexes of the elements of the
|
|
original matrix that were changed are stored in the arrays passed as
|
|
the last two elements. These arrays must have as many elements as the
|
|
dimension of the matrix. (This is so even if it is known that fewer
|
|
elements than this will be changed, as these arrays are also used as
|
|
temporary storage by this routine.)
|
|
|
|
<P>See <A HREF="#invert"><TT>mod2dense_invert</TT></A> for the algorithm used.
|
|
|
|
<P><A NAME="invert_selected"><HR><B>mod2dense_invert_selected</B>:
|
|
Invert a matrix with columns selected from a bigger matrix.</A>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
int mod2dense_invert_selected
|
|
( mod2dense *m, /* Matrix from which a submatrix is inverted (destroyed) */
|
|
mod2dense *r, /* Place to store the inverse */
|
|
int *rows, /* Place to store indexes of rows used and not used */
|
|
int *cols /* Place to store indexes of columns used and not used */
|
|
)
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<P>Inverts a matrix obtained by selecting certain columns from the
|
|
first matrix passed, <B>m</B>, which must have at least as many
|
|
columns as rows. The second matrix passed, <B>r</B>, must already
|
|
exist, and must have the same number of rows and columns as <B>m</B>.
|
|
The result of inverting the sub-matrix of <B>m</B> is stored in the
|
|
corresponding columns of <B>r</B>, with the other columns being set to
|
|
garbage (or zero, see below). Normally, one would extract just the
|
|
relevant columns afterwards using <A
|
|
HREF="#copycols"><TT>mod2dense_copycols</TT></A>.) The contents of
|
|
<B>m</B> are destroyed (though it remains a valid matrix for storing
|
|
into later. The two matrices passed must not be the same.
|
|
|
|
<P>The indexes of the columns selected are stored, in order, in the last
|
|
argument, <B>cols</B>, followed by the columns not selected (in
|
|
arbitrary order). The argument <B>rows</B> is set to the indexes of
|
|
the rows used, which will be simply the indexes from zero up if the
|
|
matrix is invertible, and will otherwise give an ordering that allows
|
|
the inversion to proceed as far as possible.
|
|
|
|
<P>The value returned is zero if an invertible matrix was found, and
|
|
is otherwise the number of columns/rows that are redundant (ie, the
|
|
amount by which matrix falls short of being of full rank). If
|
|
inversion fails, partial results are stored in the columns and rows of
|
|
<B>r</B> identified by the initial portions of <B>cols</B> and
|
|
<B>rows</B>, such that if these rows and columns were extracted in
|
|
their new order, they would constitute the inverse of the
|
|
corresponding re-ordered submatrix of <B>m</B>. The remaining portion
|
|
of <B>cols</B> up to the number of rows in <B>m</B> will contain
|
|
indexes of columns of <B>r</B> that are selected arbitrarily; these
|
|
columns will, however, be set to contain all zeros.
|
|
|
|
<P>Note that when the first matrix is square, and non-singular, the
|
|
result is NOT in general the same as that obtained by calling <A
|
|
HREF="#invert"></TT>mod2dense_invert</TT></A>, since that procedure
|
|
orders the columns of the inverse so that it applies to the original
|
|
ordering of the columns of the first matrix.
|
|
|
|
<P>See <A HREF="#invert"><TT>mod2dense_invert</TT></A> for the algorithm used.
|
|
|
|
<HR>
|
|
|
|
<A HREF="index.html">Back to index for LDPC software</A>
|
|
|
|
</BODY></HTML>
|