Add ldpc sandbox folder.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6437 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Steven Franke 2016-01-25 00:04:21 +00:00
parent bef405970f
commit 5ac886855d
99 changed files with 28805 additions and 0 deletions

15
lib/ldpc/COPYRIGHT Executable file
View File

@ -0,0 +1,15 @@
Except as otherwise specified, all program code and documentation in this
directory is copyright (c) 1995-2012 by Radford M. Neal.
Permission is granted for anyone to copy, use, modify, and distribute
these programs and accompanying documents for any purpose, provided
this copyright notice is retained and prominently displayed, and note
is made of any changes made to these programs. These programs and
documents are distributed without any warranty, express or implied.
As the programs were written for research purposes only, they have not
been tested to the degree that would be advisable in any important
application. All use of these programs is entirely at the user's own
risk.
Some routines in the module rand.c are taken from the GNU C Library,
and are copyrighted as described there and in the file LGPL.

28
lib/ldpc/LDPC-install Executable file
View File

@ -0,0 +1,28 @@
#!/bin/sh
# Copy the LPDC programs to the directory specified. The program file
# might be the name of the program, or (eg, on Cygwin) the name of the
# program with .exe appended.
if [ x$1 == x -o x$2 != x ]; then
echo Usage: LDPC-install bin-directory
exit 1
fi
echo Installing LPDC programs in $1
mkdir -p $1
for prog in make-pchk alist-to-pchk pchk-to-alist \
make-ldpc print-pchk make-gen print-gen \
rand-src encode transmit decode extract verify; do
if [ -f $prog ]; then
cp $prog $1
elif [ -f $prog.exe ]; then
cp $prog.exe $1
else
echo No program $prog to install
fi
done
echo Done

463
lib/ldpc/LGPL Executable file
View File

@ -0,0 +1,463 @@
The following is the license under which the portions of the GNU C
library used in the rand.c module is distributed. Note that this
license does not apply to the rest of this software.
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of e Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS

116
lib/ldpc/Makefile Executable file
View File

@ -0,0 +1,116 @@
# MAKEFILE FOR LDPC PROGRAMS & ASSOCIATED UTILITIES.
# Copyright (c) 1995-2012 by Radford M. Neal.
#
# Permission is granted for anyone to copy, use, modify, and distribute
# these programs and accompanying documents for any purpose, provided
# this copyright notice is retained and prominently displayed, and note
# is made of any changes made to these programs. These programs and
# documents are distributed without any warranty, express or implied.
# As the programs were written for research purposes only, they have not
# been tested to the degree that would be advisable in any important
# application. All use of these programs is entirely at the user's own
# risk.
# NOTE: The natural random numbers in "randfile" are accessed by the
# 'rand' module via a path to this directory. Change the definition of
# RAND_FILE in the compilation command for rand.c below if this is not
# appropriate.
# NOTE: This makefile is trivial, simply recompiling everything from
# scratch every time. Since this takes only about 5 seconds on a modern
# PC, there's no point in putting in dependency-based rules, which just
# make things more complex and error-prone.
COMPILE = cc -c -O # Command to compile a module from .c to .o
LINK = cc # Command to link a program
# MAKE ALL THE MAIN PROGRAMS. First makes the modules used.
progs: modules
$(COMPILE) make-pchk.c
$(LINK) make-pchk.o mod2sparse.o mod2dense.o mod2convert.o \
rcode.o alloc.o intio.o open.o -lm -o make-pchk
$(COMPILE) alist-to-pchk.c
$(LINK) alist-to-pchk.o mod2sparse.o mod2dense.o mod2convert.o \
rcode.o alloc.o intio.o open.o -lm -o alist-to-pchk
$(COMPILE) pchk-to-alist.c
$(LINK) pchk-to-alist.o mod2sparse.o mod2dense.o mod2convert.o \
rcode.o alloc.o intio.o open.o -lm -o pchk-to-alist
$(COMPILE) make-ldpc.c
$(LINK) make-ldpc.o mod2sparse.o mod2dense.o mod2convert.o \
rcode.o rand.o alloc.o intio.o open.o distrib.o -lm -o make-ldpc
$(COMPILE) print-pchk.c
$(LINK) print-pchk.o mod2sparse.o mod2dense.o mod2convert.o \
rcode.o rand.o alloc.o intio.o open.o -lm -o print-pchk
$(COMPILE) make-gen.c
$(LINK) make-gen.o mod2sparse.o mod2dense.o mod2convert.o \
rcode.o alloc.o intio.o open.o -lm -o make-gen
$(COMPILE) print-gen.c
$(LINK) print-gen.o mod2sparse.o mod2dense.o mod2convert.o \
rcode.o rand.o alloc.o intio.o open.o -lm -o print-gen
$(COMPILE) rand-src.c
$(LINK) rand-src.o rand.o open.o -lm -o rand-src
$(COMPILE) encode.c
$(LINK) encode.o mod2sparse.o mod2dense.o mod2convert.o \
enc.o rcode.o rand.o alloc.o intio.o blockio.o open.o -lm -o encode
$(COMPILE) transmit.c
$(LINK) transmit.o channel.o rand.o open.o -lm -o transmit
$(COMPILE) decode.c
$(LINK) decode.o channel.o mod2sparse.o mod2dense.o mod2convert.o \
enc.o check.o \
rcode.o rand.o alloc.o intio.o blockio.o dec.o open.o -lm -o decode
$(COMPILE) extract.c
$(LINK) extract.o mod2sparse.o mod2dense.o mod2convert.o \
rcode.o alloc.o intio.o blockio.o open.o -lm -o extract
$(COMPILE) verify.c
$(LINK) verify.o mod2sparse.o mod2dense.o mod2convert.o check.o \
rcode.o alloc.o intio.o blockio.o open.o -lm -o verify
# MAKE THE TEST PROGRAMS. First makes the modules used.
tests: modules
$(COMPILE) mod2dense-test.c
$(LINK) mod2dense-test.o mod2dense.o alloc.o intio.o \
-lm -o mod2dense-test
$(COMPILE) mod2sparse-test.c
$(LINK) mod2sparse-test.o mod2sparse.o alloc.o intio.o \
-lm -o mod2sparse-test
$(COMPILE) mod2convert-test.c
$(LINK) mod2convert-test.o mod2convert.o mod2dense.o mod2sparse.o \
alloc.o intio.o rand.o open.o -lm -o mod2convert-test
$(COMPILE) rand-test.c
$(LINK) rand-test.o rand.o -lm -o rand-test
# MAKE THE MODULES USED BY THE PROGRAMS.
modules:
$(COMPILE) rcode.c
$(COMPILE) channel.c
$(COMPILE) dec.c
$(COMPILE) enc.c
$(COMPILE) alloc.c
$(COMPILE) intio.c
$(COMPILE) blockio.c
$(COMPILE) check.c
$(COMPILE) open.c
$(COMPILE) mod2dense.c
$(COMPILE) mod2sparse.c
$(COMPILE) mod2convert.c
$(COMPILE) distrib.c
$(COMPILE) -DRAND_FILE=\"`pwd`/randfile\" rand.c
# CLEAN UP ALL PROGRAMS AND REMOVE ALL FILES PRODUCED BY TESTS AND EXAMPLES.
clean:
rm -f core *.o *.exe ex-*.* test-file \
make-pchk alist-to-pchk pchk-to-alist \
make-ldpc print-pchk make-gen print-gen \
rand-src encode transmit decode extract verify \
mod2dense-test mod2sparse-test mod2convert-test rand-test

6
lib/ldpc/README Executable file
View File

@ -0,0 +1,6 @@
This is a collection of programs and modules, written in C, that
support research and education concerning Low Density Parity Check
(LDPC) codes.
See index.html in this directory for an index to the documentation.
Copyright information can be found there, and in the file COPYRIGHT.

168
lib/ldpc/alist-to-pchk.c Executable file
View File

@ -0,0 +1,168 @@
/* ALIST-TO-PCHK.C - Convert a parity check matrix from alist format. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "alloc.h"
#include "intio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
void bad_alist_file(void);
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *alist_file, *pchk_file;
FILE *af, *pf;
int mxrw, mxcw;
int *rw, *cw;
int i, j, k;
int tot, trans;
int nxt;
trans = 0;
for (;;)
{
if (argc>1 && strcmp(argv[1],"-t")==0)
{ trans = 1;
argc -= 1;
argv += 1;
}
else
{ break;
}
}
if (argc!=3)
{ usage();
}
pchk_file = argv[2];
alist_file = argv[1];
af = open_file_std(alist_file,"r");
if (af==NULL)
{ fprintf(stderr,"Can't open alist file: %s\n",alist_file);
exit(1);
}
if (fscanf(af,"%d",&M)!=1 || M<1
|| fscanf(af,"%d",&N)!=1 || N<1
|| fscanf(af,"%d",&mxrw)!=1 || mxrw<0 || mxrw>N
|| fscanf(af,"%d",&mxcw)!=1 || mxcw<0 || mxcw>M)
{ bad_alist_file();
}
rw = (int *) chk_alloc (M, sizeof *rw);
for (i = 0; i<M; i++)
{ if (fscanf(af,"%d",&rw[i])!=1 || rw[i]<0 || rw[i]>N)
{ bad_alist_file();
}
}
cw = (int *) chk_alloc (N, sizeof *cw);
for (j = 0; j<N; j++)
{ if (fscanf(af,"%d",&cw[j])!=1 || cw[j]<0 || cw[j]>M)
{ bad_alist_file();
}
}
H = mod2sparse_allocate(M,N);
do { if (fscanf(af,"%d",&nxt)!=1) nxt = -1; } while (nxt==0);
tot = 0;
for (i = 0; i<M; i++)
{ for (k = 0; k<rw[i]; k++)
{ if (nxt<=0 || nxt>N || mod2sparse_find(H,i,nxt-1))
{ bad_alist_file();
}
mod2sparse_insert(H,i,nxt-1);
tot += 1;
do { if (fscanf(af,"%d",&nxt)!=1) nxt = -1; } while (nxt==0);
}
}
for (j = 0; j<N; j++)
{ for (k = 0; k<cw[j]; k++)
{ if (nxt<=0 || nxt>M || !mod2sparse_find(H,nxt-1,j))
{ bad_alist_file();
}
tot -= 1;
do { if (fscanf(af,"%d",&nxt)!=1) nxt = -1; } while (nxt==0);
}
}
if (tot!=0 || nxt!=-1 || !feof(af))
{ bad_alist_file();
}
if (trans)
{ mod2sparse *HT;
HT = H;
H = mod2sparse_allocate(N,M);
mod2sparse_transpose(HT,H);
}
pf = open_file_std(pchk_file,"wb");
if (pf==NULL)
{ fprintf(stderr,"Can't create parity check file: %s\n",pchk_file);
exit(1);
}
intio_write(pf,('P'<<8)+0x80);
if (ferror(pf) || !mod2sparse_write(pf,H) || fclose(pf)!=0)
{ fprintf(stderr,"Error writing to parity check file %s\n",pchk_file);
exit(1);
}
return 0;
}
/* COMPLAIN THAT ALIST FILE IS BAD. */
void bad_alist_file()
{ fprintf(stderr,"Alist file doesn't have the right format\n");
exit(1);
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: alist-to-pchk [ -t ] alist-file pchk-file\n");
exit(1);
}

42
lib/ldpc/alloc.c Executable file
View File

@ -0,0 +1,42 @@
/* ALLOC.C - Routine to allocate memory and complain if it doesn't work. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdlib.h>
#include <stdio.h>
#include "alloc.h"
/* ALLOCATE SPACE AND CHECK FOR ERROR. Calls 'calloc' to allocate space,
and then displays an error message and exits if the space couldn't be
found. */
void *chk_alloc
( unsigned n, /* Number of elements */
unsigned size /* Size of each element */
)
{
void *p;
p = calloc(n,size);
if (p==0)
{ fprintf(stderr,"Ran out of memory (while trying to allocate %d bytes)\n",
n*size);
exit(1);
}
return p;
}

18
lib/ldpc/alloc.h Executable file
View File

@ -0,0 +1,18 @@
/* ALLOC.H - Interface to memory allocation procedure. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
void *chk_alloc (unsigned, unsigned); /* Calls 'calloc' and exits with error
if it fails */

85
lib/ldpc/blockio.c Executable file
View File

@ -0,0 +1,85 @@
/* BLOCKIO.C - Routines to read/write blocks of bits from/to a text file. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdlib.h>
#include <stdio.h>
#include "blockio.h"
int blockio_flush = 0; /* Should blocks written be immediately flushed? */
/* READ A BLOCK OF BITS. The bits must be given as '0' or '1' characters,
with whitespace allowed (but not required) between bits. Returns 0 if
a block is read successfully, and EOF if eof or an error occurs. If
EOF is returned, a warning will be printed if a partial block had already
been read. */
int blockio_read
( FILE *f, /* File to read from */
char *b, /* Place to store bits read */
int l /* Length of block */
)
{
int i, c;
for (i = 0; i<l; i++)
{
do
{ c = getc(f);
if (c==EOF)
{ if (i>0)
{ fprintf(stderr,
"Warning: Short block (%d long) at end of input file ignored\n",i);
}
return EOF;
}
} while (c==' ' || c=='\t' || c=='\n' || c=='\r');
if (c!='0' && c!='1')
{ fprintf(stderr,"Bad character in binary file (not '0' or '1')\n");
exit(1);
}
b[i] = c=='1';
}
return 0;
}
/* WRITE A BLOCK OF BITS. Bits are written as '0' and '1' characters, with
no spaces between them, followed by a newline. */
void blockio_write
( FILE *f, /* File to write to */
char *b, /* Block of bits to write */
int l /* Length of block */
)
{
int i;
for (i = 0; i<l; i++)
{ if (b[i]!=0 && b[i]!=1) abort();
putc("01"[b[i]],f);
}
putc('\n',f);
if (blockio_flush)
{ fflush(f);
}
}

19
lib/ldpc/blockio.h Executable file
View File

@ -0,0 +1,19 @@
/* BLOCKIO.H - Interface to block input/output routines. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
extern int blockio_flush; /* Should blocks written be immediately flushed? */
int blockio_read (FILE *, char *, int);
void blockio_write (FILE *, char *, int);

99
lib/ldpc/channel.c Executable file
View File

@ -0,0 +1,99 @@
/* CHANNEL.C - Procedures and variables regarding channels. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "channel.h"
/* GLOBAL VARIABLES. Declared in channel.h. */
channel_type channel; /* Type of channel */
double error_prob; /* Error probability for BSC */
double std_dev; /* Noise standard deviation for AWGN */
double lwidth; /* Width of noise distribution for AWLN */
/* PARSE A COMMAND-LINE SPECIFICATION OF A CHANNEL. Takes a pointer to an
argument list and an argument count; returns the number of arguments that
make up a channel specification at this point in the command line. Returns
zero if the argument list does not start with a channel specification.
Returns -1 if there seems to be a channel specification here, but it's
invalid.
Sets the variables declared in channel.h to the type and parameters of
the channel.
*/
int channel_parse
( char **argv, /* Pointer to argument list */
int argc /* Number of arguments in list */
)
{
char junk;
if (argc==0) return 0;
if (strcmp(argv[0],"bsc")==0 || strcmp(argv[0],"BSC")==0)
{
channel = BSC;
if (argc<2 || sscanf(argv[1],"%lf%c",&error_prob,&junk)!=1
|| error_prob<=0 || error_prob>=1)
{ return -1;
}
else
{ return 2;
}
}
else if (strcmp(argv[0],"awgn")==0 || strcmp(argv[0],"AWGN")==0)
{
channel = AWGN;
if (argc<2 || sscanf(argv[1],"%lf%c",&std_dev,&junk)!=1
|| std_dev<=0)
{ return -1;
}
else
{ return 2;
}
}
else if (strcmp(argv[0],"awln")==0 || strcmp(argv[0],"AWLN")==0)
{
channel = AWLN;
if (argc<2 || sscanf(argv[1],"%lf%c",&lwidth,&junk)!=1
|| lwidth<=0)
{ return -1;
}
else
{ return 2;
}
}
else
{
return 0;
}
}
/* PRINT USAGE MESSAGE REGARDING CHANNEL SPECIFICATIONS. */
void channel_usage(void)
{
fprintf(stderr,
"Channel: bsc error-probability | awgn standard-deviation | awln width\n");
}

32
lib/ldpc/channel.h Executable file
View File

@ -0,0 +1,32 @@
/* CHANNEL.H - Declarations regarding channels. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* TYPES OF CHANNEL, AND CHANNEL PARAMETERS. The global variables declared
here are located in channel.c. */
typedef enum { BSC, AWGN, AWLN } channel_type;
extern channel_type channel; /* Type of channel */
extern double error_prob; /* Error probability for BSC */
extern double std_dev; /* Noise standard deviation for AWGN */
extern double lwidth; /* Width of noise distributoin for AWLN */
/* PROCEDURES TO DO WITH CHANNELS. */
int channel_parse (char **, int);
void channel_usage (void);

182
lib/ldpc/channel.html Executable file
View File

@ -0,0 +1,182 @@
<HTML><HEAD>
<TITLE> Transmission Through a Simulated Channel </TITLE>
</HEAD><BODY>
<H1> Transmission Through a Simulated Channel </H1>
<P>Once a codeword has been found to represent a source message, it
can be sent through a <I>channel</I>, with the result that certain
data is received as the output of the channel, which will be related
to the codeword sent, but with random noise. This software currently
handles only memoryless binary channels, for which each bit sent
through the channel results in a separate piece of data being
received, and the noise affecting one bit is independent of the noise
affecting other bits.
<P>For a <I>Binary Symmetric Channel</I> (BSC), each bit sent
results in a bit being received. The bit received differs from the
bit sent with some error probability, <I>p</I>, which is the same for
0 bits and for 1 bits. In other words, the probability distribution
for the bit received given the bit sent is as follows:
<BLOCKQUOTE>
P(receive 1 | send 1) = P(receive 0 | send 0) = 1-<I>p</I><BR>
P(receive 1 | send 0) = P(receive 0 | send 1) = <I>p</I>
</BLOCKQUOTE>
<P>For an <I>Additive White Gaussian Noise</I> (AWGN) channel, the
data received at each time is equal to the data sent plus Gaussian
noise with mean zero and some standard deviation, <I>s</I>,
independently for each bit. For this software, the data sent is -1
for a 0 bit and +1 for a 1 bit. In other words, the distribution
of the received data given the bit sent is as follows:
<BLOCKQUOTE>
data received | send 1 ~ N(+1,<I>s</I><SUP><SMALL>2</SMALL></SUP>)<BR>
data received | send 0 ~ N(-1,<I>s</I><SUP><SMALL>2</SMALL></SUP>)
</BLOCKQUOTE>
<P>It is typically assumed that the standard deviation of the noise
varies with the rate at which bits are sent, increasing in proportion
to the square root of the rate. The error rate obtained from sending
unencoded bits at rate <I>R</I> will then be the same as is obtained
using a code that repeats each bit <I>n</I> times, and sends these
bits at rate <I>nR</I> (assuming optimal decoding of each bit by
thresholding the sum of the <I>n</I> channel outputs corresponding to
that bit). Another way of looking at this scaling for <I>s</I> is
that when bits are send at a lower rate, the receiver will be
accumulating the channel output for a longer time, with the result
that the amount of noise will decrease (relative to the signal) as a
result of averaging.
<P>To account for this, it is common to compare codes for AWGN
channels in terms of their bit error rate and the value of
<BLOCKQUOTE>
<I>E<SUB><SMALL>b</SMALL></SUB></I> / <I>N<SUB><SMALL>0</SMALL></SUB></I>
= 1 / 2<I>R</I><I>s</I><SUP><SMALL>2</SMALL></SUP>
</BLOCKQUOTE>
at which they operate, where <I>R</I>=<I>K</I>/<I>N</I> is the rate
of the code, and <I>s</I> is the noise level at which the code
achieves the quoted bit error rate. Hence, a code operating at a lower
rate is allowed to assume a lower noise level to make the comparison fair.
It is common to quote
<I>E<SUB><SMALL>b</SMALL></SUB></I> /
<I>N<SUB><SMALL>0</SMALL></SUB></I> in decibels (db), equal to
10 log<SUB><SMALL>10</SMALL></SUB>(<I>E<SUB><SMALL>b</SMALL></SUB></I>
/ <I>N<SUB><SMALL>0</SMALL></SUB></I>).
<P>The <I>Additive White Logistic Noise</I> (AWLN) channel is similar
to the AWGN channel, except that the noise comes from a logistic rather
than a Gaussian distribution. The probability density function for the
noise is
<BLOCKQUOTE>
(1/<I>w</I>) exp(-<I>n</I>/<I>w</I>) / [1 + exp(-<I>n</I>/<I>w</I>)]<SUP>2</SUP>
</BLOCKQUOTE>
where <I>n</I> is the amount of noise, and <I>w</I> is a width parameter
for the distribution, analogous to the <I>s</I> parameter for
Gaussian noise. (However, <I>w</I> is not equal to the standard deviation
for the logistic distribution, which is
sqrt(pi<SUP><SMALL>2</SMALL></SUP>/3)<I>w</I>.) <B>Note:</B> Although I've
named this channel in analogy with the AWGN channel, it does not share
the properties discussed above regarding how noise levels would be expected
to change when the data rate changes.
<P><A NAME="transmit"><HR><B>transmit</B>: Transmit bits through a
simulated channel.
<BLOCKQUOTE><PRE>
transmit <I>encoded-file</I>|<I>n-zeros received-file seed channel</I>
</PRE>
<BLOCKQUOTE>
where <TT><I>channel</I></TT> is one of the following:
<BLOCKQUOTE><PRE>
bsc <I>error-probability</I>
awgn <I>standard-deviation</I>
awln <I>width</I>
</PRE></BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P>Simulates the transmission of the bits in
<TT><I>encoded-file</I></TT> through a channel, with the received data
being stored in <TT><I>received-file</I></TT>. Typically,
<TT><I>encoded-file</I></TT> will have been produced by the <A
HREF="encoding.html#encode"><TT>encode</TT></A> program, but it could
also come from <A HREF="support.html#rand-src"><TT>rand-src</TT></A>
or another program. If newlines separate blocks in
<TT><I>encoded-file</I></TT>, these block boundaries will be preserved
in <TT><I>received-file</I></TT>.
<P>Alternatively, a count of zeros to transmit can be given, rather
than a <I>encoded-file</I>. This count can be the product of the
block size and the number of blocks, written with <TT>x</TT>
separating these numbers, with no spaces. The
<TT><I>received-file</I></TT> will mark the block boundaries with
newlines, assuming a block size of one if a simple bit count is given.
Note that zero messages are sufficient for assessing the performance
of a linear code with a symmetrical channel and a symmetrical decoding
algorithm. <B>Warning:</B> Ties, messages that lead to floating-point
overflow, and program bugs can easily make a decoding algorithm
non-symmetrical, so it's best not to test exclusively on zero
messages. Indeed, it is best not to do this at all unless you
really need to avoid the time needed to generate and encode random
messages.
<P>The transmission will be corrupted by random noise, which will be
generated pseudo-randomly based on <TT><I>seed</I></TT>. The actual
random seed used will be <TT><I>seed</I></TT> times 10 plus 3, so that
the stream of pseudo-random numbers will not be the same as any that
might have been used by another program.
<P>The fourth argument specifies the type of channel, currently either
<TT>bsc</TT> (or <TT>BSC</TT>) for the Binary Symmetric Channel, or
<TT>awgn</TT> (or <TT>AWGN</TT>) for the Additive White Gaussian
Noise channel, or <TT>awln</TT> (or <TT>AWLN</TT>) for the Additive White
Logistic Noise channel. The channel type is followed by an argument
specifying the characteristics of the channel, as follows:
<BLOCKQUOTE>
<P>BSC: The probability that a bit will be flipped by noise - ie, the
probability that the bit received is an error.
<P>AWGN: The standard deviation of the Gaussian noise that is added to the
encodings of the bits.
<P>AWLN: The width parameter of the logistic distribution for the noise
that is added to the encodings of the bits.
</BLOCKQUOTE>
See the description of <A HREF="channel.html">channel transmission</A>
for more details.
<P><B>Examples</B>: The command:
<UL><PRE>
<LI>transmit 10x3 rec 1 bsc 0.1
</PRE></UL>
will simulate the transmission of 30 zero bits (3 blocks of size 10) through
a Binary Symmetric Channel with error probability of 0.1. The result will
be to store something like the following in the file <TT>rec</TT>:
<BLOCKQUOTE><PRE>
0000000000
1000000000
0100000000
</PRE></BLOCKQUOTE>
If an AWGN channel is used instead, as follows:
<UL><PRE>
<LI>transmit 10x3 rec 1 awgn 0.5
</PRE></UL>
then the file <TT>rec</TT> will contain data such as:
<BLOCKQUOTE><PRE>
-1.36 -0.86 -0.80 -1.19 -1.18 -0.64 -0.31 -1.16 -1.56 -0.79
-2.20 -1.62 -0.53 -1.29 -1.08 -2.05 -0.75 -1.22 -0.81 -0.52
-0.86 -0.34 -1.10 -1.30 -1.10 -1.20 -0.37 -1.07 -0.22 -1.46
</PRE></BLOCKQUOTE>
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

177
lib/ldpc/check.c Executable file
View File

@ -0,0 +1,177 @@
/* CHECK.C - Compute parity checks and other stats on decodings. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mod2sparse.h"
#include "check.h"
/* COMPUTE PARITY CHECKS. Returns the number of parity checks violated by
dblk. The results of all the parity checks are stored in pchk. */
int check
( mod2sparse *H, /* Parity check matrix */
char *dblk, /* Guess for codeword */
char *pchk /* Place to store parity checks */
)
{
int M, i, c;
M = mod2sparse_rows(H);
mod2sparse_mulvec (H, dblk, pchk);
c = 0;
for (i = 0; i<M; i++)
{ c += pchk[i];
}
return c;
}
/* COUNT HOW MANY BITS HAVED CHANGED FROM BIT INDICATED BY LIKELIHOOD. The
simple decoding based on likelihood ratio is compared to the given decoding.
A bit for which the likelihood ratio is exactly one counts as half a
change, which explains why the result is a double rather than an int.
*/
double changed
( double *lratio, /* Likelihood ratios for bits */
char *dblk, /* Candidate decoding */
int N /* Number of bits */
)
{
double changed;
int j;
changed = 0;
for (j = 0; j<N; j++)
{ changed += lratio[j]==1 ? 0.5 : dblk[j] != (lratio[j]>1);
}
return changed;
}
/* COMPUTE THE EXPECTED NUMBER OF PARITY CHECK ERRORS. Computes the
expected number of parity check errors with respect to the distribution
given by the bit probabilities passed, with bits assumed to be independent.
*/
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;
}
/* COMPUTE LOG LIKELIHOOD OF A DECODING. */
double loglikelihood
( double *lratio, /* Likelihood ratios for bits */
char *bits, /* Bits in decoding */
int N /* Length of codeword */
)
{
double ll;
int j;
ll = 0;
for (j = 0; j<N; j++)
{ ll -= bits[j] ? log(1+1/lratio[j]) : log(1+lratio[j]);
}
return ll;
}
/* COMPUTE THE EXPECTED LOG LIKELIHOOD BASED ON BIT PROBABILITIES. Computes
the expected value of the log likelihood with respect to the distribution
given by the bit probabilities passed, with bits assumed to be independent.
*/
double expected_loglikelihood
( double *lratio, /* Likelihood ratios for bits */
double *bpr, /* Bit probabilities */
int N /* Length of codeword */
)
{
double ll;
int j;
ll = 0;
for (j = 0; j<N; j++)
{ if (bpr[j]>0)
{ ll -= bpr[j]*log(1+1/lratio[j]);
}
if (bpr[j]<1)
{ ll -= (1-bpr[j])*log(1+lratio[j]);
}
}
return ll;
}
/* COMPUTE ENTROPY FROM BIT PROBABILITIES. Computes the entropy of the
distribution given by the bit probabilities, on the assumption that
bits are independent.
*/
double entropy
( double *bpr, /* Bit probabilities */
int N /* Length of codeword */
)
{
double e;
int j;
e = 0;
for (j = 0; j<N; j++)
{ if (bpr[j]>0 && bpr[j]<1)
{ e -= bpr[j]*log(bpr[j]) + (1-bpr[j])*log(1-bpr[j]);
}
}
return e/log(2.0);
}

25
lib/ldpc/check.h Executable file
View File

@ -0,0 +1,25 @@
/* CHECK.H - Interface to procedure for computing parity checks, etc. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
int check (mod2sparse *, char *, char *);
double changed (double *, char *, int);
double expected_parity_errors (mod2sparse *, double *);
double loglikelihood (double *, char *, int);
double expected_loglikelihood (double *, double *, int);
double entropy (double *, int);

385
lib/ldpc/dec.c Executable file
View File

@ -0,0 +1,385 @@
/* DEC.C - Decoding procedures. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* NOTE: See decoding.html for general documentation on the decoding methods */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "alloc.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rand.h"
#include "rcode.h"
#include "check.h"
#include "dec.h"
#include "enc.h"
/* GLOBAL VARIABLES. Declared in dec.h. */
decoding_method dec_method; /* Decoding method to use */
int table; /* Trace option, 2 for a table of decoding details */
int block_no; /* Number of current block, from zero */
int max_iter; /* Maximum number of iteratons of decoding to do */
char *gen_file; /* Generator file for Enum_block and Enum_bit */
/* DECODE BY EXHAUSTIVE ENUMERATION. Decodes by trying all possible source
messages (and hence all possible codewords, unless the parity check matrix
was redundant). If the last argument is 1, it sets dblk to the most likely
entire block; if this argument is 0, each bit of dblk is set to the most
likely value for that bit. The marginal probabilities of each bit being 1
are returned in bitpr.
The function value returned is the total number of codewords tried (which
will be the same for all blocks). The return valued is "unsigned" because
it might conceivably be as big as 2^31.
The parity check matrix and other data are taken from the global variables
declared in rcode.h.
The number of message bits should not be greater than 31 for this procedure.
The setup procedure immediately below checks this, reads the generator file,
and outputs headers for the detailed trace file, if required.
*/
void enum_decode_setup(void)
{
read_gen(gen_file,0,0);
if (N-M>31)
{ fprintf(stderr,
"Trying to decode messages with %d bits by exhaustive enumeration is absurd!\n",
N-M);
exit(1);
}
if (table==2)
{ printf(" block decoding likelihood\n");
}
}
unsigned enum_decode
( double *lratio, /* Likelihood ratios for bits */
char *dblk, /* Place to stored decoded message */
double *bitpr, /* Place to store marginal bit probabilities */
int max_block /* Maximize probability of whole block being correct? */
)
{
mod2dense *u, *v;
double lk, maxlk, tpr;
double *bpr, *lk0, *lk1;
char sblk[31];
char *cblk;
unsigned d;
int i, j;
if (N-M>31) abort();
/* Allocate needed space. */
bpr = bitpr;
if (bpr==0 && max_block==0)
{ bpr = chk_alloc (N, sizeof *bpr);
}
cblk = chk_alloc (N, sizeof *cblk);
if (type=='d')
{ u = mod2dense_allocate(N-M,1);
v = mod2dense_allocate(M,1);
}
if (type=='m')
{ u = mod2dense_allocate(M,1);
v = mod2dense_allocate(M,1);
}
lk0 = chk_alloc (N, sizeof *lk0);
lk1 = chk_alloc (N, sizeof *lk1);
/* Pre-compute likelihoods for bits. */
for (j = 0; j<N; j++)
{ lk0[j] = 1/(1+lratio[j]);
lk1[j] = 1 - lk0[j];
}
/* Initialize marginal bit probabilities. */
if (bpr)
{ for (j = 0; j<N; j++) bpr[j] = 0.0;
}
/* Exhaustively try all possible decoded messages. */
tpr = 0.0;
for (d = 0; d<=(1<<(N-M))-1; d++)
{
/* Unpack message into source block. */
for (i = N-M-1; i>=0; i--)
{ sblk[i] = (d>>i)&1;
}
/* Find full codeword for this message. */
switch (type)
{ case 's':
{ sparse_encode (sblk, cblk);
break;
}
case 'd':
{ dense_encode (sblk, cblk, u, v);
break;
}
case 'm':
{ mixed_encode (sblk, cblk, u, v);
break;
}
}
/* Compute likelihood for this decoding. */
lk = 1;
for (j = 0; j<N; j++)
{ lk *= cblk[j]==0 ? lk0[j] : lk1[j];
}
/* Update maximum likelihood decoding. */
if (max_block)
{ if (d==0 || lk>maxlk)
{ for (j = 0; j<N; j++)
{ dblk[j] = cblk[j];
}
maxlk = lk;
}
}
/* Update bit probabilities. */
if (bpr)
{ for (j = 0; j<N; j++)
{ if (cblk[j]==1)
{ bpr[j] += lk;
}
}
tpr += lk;
}
/* Output data to trace file. */
if (table==2)
{ printf("%7d %10x %10.4e\n",block_no,d,lk);
}
}
/* Normalize bit probabilities. */
if (bpr)
{ for (j = 0; j<N; j++) bpr[j] /= tpr;
}
/* Decoding to maximize bit-by-bit success, if that's what's wanted.
In case of a tie, decode to a 1. */
if (!max_block)
{ for (j = 0; j<N; j++)
{ dblk[j] = bpr[j]>=0.5;
}
}
/* Free space. */
if (bpr!=0 && bpr!=bitpr) free(bpr);
free(cblk);
free(lk0);
free(lk1);
return 1<<(N-M);
}
/* DECODE USING PROBABILITY PROPAGATION. Tries to find the most probable
values for the bits of the codeword, given a parity check matrix (H), and
likelihood ratios (lratio) for each bit. If max_iter is positive, up to
that many iterations of probability propagation are done, stopping before
then if the tentative decoding is a valid codeword. If max_iter is
negative, abs(max_iter) iterations are done, regardless of whether a
codeword was found earlier.
Returns the number of iterations done (as an "unsigned" for consistency
with enum_decode). Regardless of whether or not a valid codeword was
reached, the bit vector from thresholding the bit-by-bit probabilities is
stored in dblk, and the resulting parity checks are stored in pchk (all
will be zero if the codeword is valid). The final probabilities for each
bit being a 1 are stored in bprb.
The setup procedure immediately below outputs headers for the detailed trace
file, if required.
*/
void prprp_decode_setup (void)
{
if (table==2)
{ printf(
" block iter changed perrs loglik Eperrs Eloglik entropy\n");
}
}
unsigned prprp_decode
( mod2sparse *H, /* Parity check matrix */
double *lratio, /* Likelihood ratios for bits */
char *dblk, /* Place to store decoding */
char *pchk, /* Place to store parity checks */
double *bprb /* Place to store bit probabilities */
)
{
int N, n, c;
N = mod2sparse_cols(H);
/* Initialize probability and likelihood ratios, and find initial guess. */
initprp(H,lratio,dblk,bprb);
/* Do up to abs(max_iter) iterations of probability propagation, stopping
early if a codeword is found, unless max_iter is negative. */
for (n = 0; ; n++)
{
c = check(H,dblk,pchk);
if (table==2)
{ printf("%7d %5d %8.1f %6d %+9.2f %8.1f %+9.2f %7.1f\n",
block_no, n, changed(lratio,dblk,N), c, loglikelihood(lratio,dblk,N),
expected_parity_errors(H,bprb), expected_loglikelihood(lratio,bprb,N),
entropy(bprb,N));
}
if (n==max_iter || n==-max_iter || (max_iter>0 && c==0))
{ break;
}
iterprp(H,lratio,dblk,bprb);
}
return n;
}
/* INITIALIZE PROBABILITY PROPAGATION. Stores initial ratios, probabilities,
and guess at decoding. */
void initprp
( mod2sparse *H, /* Parity check matrix */
double *lratio, /* Likelihood ratios for bits */
char *dblk, /* Place to store decoding */
double *bprb /* Place to store bit probabilities, 0 if not wanted */
)
{
mod2entry *e;
int N;
int j;
N = mod2sparse_cols(H);
for (j = 0; j<N; j++)
{ for (e = mod2sparse_first_in_col(H,j);
!mod2sparse_at_end(e);
e = mod2sparse_next_in_col(e))
{ e->pr = lratio[j];
e->lr = 1;
}
if (bprb) bprb[j] = 1 - 1/(1+lratio[j]);
dblk[j] = lratio[j]>=1;
}
}
/* DO ONE ITERATION OF PROBABILITY PROPAGATION. */
void iterprp
( mod2sparse *H, /* Parity check matrix */
double *lratio, /* Likelihood ratios for bits */
char *dblk, /* Place to store decoding */
double *bprb /* Place to store bit probabilities, 0 if not wanted */
)
{
double pr, dl, t;
mod2entry *e;
int N, M;
int i, j;
M = mod2sparse_rows(H);
N = mod2sparse_cols(H);
/* Recompute likelihood ratios. */
for (i = 0; i<M; i++)
{ dl = 1;
for (e = mod2sparse_first_in_row(H,i);
!mod2sparse_at_end(e);
e = mod2sparse_next_in_row(e))
{ e->lr = dl;
dl *= 2/(1+e->pr) - 1;
}
dl = 1;
for (e = mod2sparse_last_in_row(H,i);
!mod2sparse_at_end(e);
e = mod2sparse_prev_in_row(e))
{ t = e->lr * dl;
e->lr = (1-t)/(1+t);
dl *= 2/(1+e->pr) - 1;
}
}
/* Recompute probability ratios. Also find the next guess based on the
individually most likely values. */
for (j = 0; j<N; j++)
{ pr = lratio[j];
for (e = mod2sparse_first_in_col(H,j);
!mod2sparse_at_end(e);
e = mod2sparse_next_in_col(e))
{ e->pr = pr;
pr *= e->lr;
}
if (isnan(pr))
{ pr = 1;
}
if (bprb) bprb[j] = 1 - 1/(1+pr);
dblk[j] = pr>=1;
pr = 1;
for (e = mod2sparse_last_in_col(H,j);
!mod2sparse_at_end(e);
e = mod2sparse_prev_in_col(e))
{ e->pr *= pr;
if (isnan(e->pr))
{ e->pr = 1;
}
pr *= e->lr;
}
}
}

43
lib/ldpc/dec.h Executable file
View File

@ -0,0 +1,43 @@
/* DEC.H - Interface to decoding procedures. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* DECODING METHOD, ITS PARAMETERS, AND OTHER VARIABLES. The global variables
declared here are located in dec.c. */
typedef enum
{ Enum_block, Enum_bit, Prprp
} decoding_method;
extern decoding_method dec_method; /* Decoding method to use */
extern int table; /* Trace option, 2 for a table of decoding details */
extern int block_no; /* Number of current block, from zero */
extern int max_iter; /* Maximum number of iteratons of decoding to do */
extern char *gen_file; /* Generator file for Enum_block and Enum_bit */
/* PROCEDURES RELATING TO DECODING METHODS. */
void enum_decode_setup (void);
unsigned enum_decode (double *, char *, double *, int);
void prprp_decode_setup (void);
unsigned prprp_decode
(mod2sparse *, double *, char *, char *, double *);
void initprp (mod2sparse *, double *, char *, double *);
void iterprp (mod2sparse *, double *, char *, double *);

99
lib/ldpc/decode-detail.html Executable file
View File

@ -0,0 +1,99 @@
<HTML><HEAD>
<TITLE> Detailed Decoding Trace Information </TITLE>
</HEAD><BODY>
<H1> Detailed Decoding Trace Information </H1>
The <B>-T</B> option to <A HREF="decoding.html#decode"><TT>decode</TT></A>
causes a detailed trace of information on the process of decoding to
be written to standard output, in a multi-column format, with the first
line containing the headers for each column. This format is suitable
for reading into S-Plus or R.
The first column is always the number of the block being decoded;
several lines may be output for each block. The other columns vary
with the decoding method used, as described below.
<H2>Enum-bit and Enum-block decoding methods</H2>
For source messages with <I>K</I> bits, 2<SUP><I>K</I></SUP> lines are output
for each block, containing the following information:
<BLOCKQUOTE>
<TABLE>
<tr align="left" valign="top">
<td> <B>block</B> </td>
<td>The number of the block, from zero</td></tr>
<tr align="left" valign="top">
<td> <B>decoding</B> </td>
<td>A possible decoding for the message bits, expressed as a hexadecimal
number. The other bits are determined by the message bits.</td></tr>
<tr align="left" valign="top">
<td> <B>likelihood</B> </td>
<td>The likelihood for this decoding (ie, the probability of obtaining
the data received if this was the message sent).</td></tr>
</TABLE>
</BLOCKQUOTE>
For these methods, the number of "iterations" (output with the
<B>-t</B> option) is always 2<SUP><I>K</I></SUP>.
<H2>Prprp decoding method</H2>
Each block results in one line of output for the initial state (based
on individual likelihood ratios), and one line for each subsequent
iteration, containing the following information:
<BLOCKQUOTE>
<TABLE>
<tr align="left" valign="top">
<td> <B>block</B> </td>
<td>The number of the block, from zero</td></tr>
<tr align="left" valign="top">
<td> <B>iter</B> </td>
<td>The number of an iteration, zero for the initial state.</td></tr>
<tr align="left" valign="top">
<td> <B>changed</B> </td>
<td>The number of bits in the decoding that differ from the bit that would
be chosen based just on the likelihood ratio for that bit. Bits whose
likelihood ratios are exactly one contribute 0.5 to this
count. (Likelihood ratios of exactly one can arise when the output
of an AWGN channel rounds to exactly 0.00.)</td></tr>
<tr align="left" valign="top">
<td> <B>perrs</B> </td>
<td>The number of parity check errors in the current tentative
decoding.</td></tr>
<tr align="left" valign="top">
<td> <B>loglik</B> </td>
<td>The log likelihood of the current tentative decoding.</td></tr>
<tr align="left" valign="top">
<td> <B>Eperrs</B> </td>
<td>The expected number of parity check errors in a decoding found
by randomly picking a value for each bit, independently, according
to the current bit probabilities.</td></tr>
<tr align="left" valign="top">
<td> <B>Eloglik</B> </td>
<td>The expected log likelihood of a decoding found by randomly picking
a value for each bit, independently, according to the current bit
probabilities.
</td></tr>
<tr align="left" valign="top">
<td> <B>entropy</B> </td>
<td>The entropy (in bits) of the distribution defined by the current bit
probablities, assumed to apply to bits independently.</td></tr>
</TABLE>
</BLOCKQUOTE>
The number of "iterations" (output with the <B>-t</B> option) is
the obvious count of probability propagation iterations. The
initial state does not count as an iteration.
<HR>
<A HREF="decoding.html">Back to decoding documentation</A><BR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

384
lib/ldpc/decode.c Executable file
View File

@ -0,0 +1,384 @@
/* DECODE.C - Decode blocks of received data. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "rand.h"
#include "alloc.h"
#include "blockio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "channel.h"
#include "rcode.h"
#include "check.h"
#include "dec.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *pchk_file, *rfile, *dfile, *pfile;
char **meth;
FILE *rf, *df, *pf;
char *dblk, *pchk;
double *lratio;
double *bitpr;
double *awn_data; /* Places to store channel data */
int *bsc_data;
unsigned iters; /* Unsigned because can be huge for enum */
double tot_iter; /* Double because can be huge for enum */
double chngd, tot_changed; /* Double because can be fraction if lratio==1*/
int tot_valid;
char junk;
int valid;
int i, j, k;
/* Look at initial flag arguments. */
table = 0;
blockio_flush = 0;
while (argc>1)
{
if (strcmp(argv[1],"-t")==0)
{ if (table!=0) usage();
table = 1;
}
else if (strcmp(argv[1],"-T")==0)
{ if (table!=0) usage();
table = 2;
}
else if (strcmp(argv[1],"-f")==0)
{ if (blockio_flush!=0) usage();
blockio_flush = 1;
}
else
{ break;
}
argc -= 1;
argv += 1;
}
/* Look at arguments up to the decoding method specification. */
if (!(pchk_file = argv[1])
|| !(rfile = argv[2])
|| !(dfile = argv[3]))
{ usage();
}
if (argv[4]==0 || argv[5]==0) usage();
k = channel_parse(argv+4,argc-4);
if (k<=0)
{ pfile = argv[4];
k = channel_parse(argv+5,argc-5);
if (k<=0) usage();
meth = argv+5+k;
}
else
{ pfile = 0;
meth = argv+4+k;
}
/* Look at the specification of the decoding method, which starts at meth and
continues to the end of the command line (marked by a zero pointer). */
if (!meth[0]) usage();
if (strcmp(meth[0],"prprp")==0)
{ dec_method = Prprp;
if (!meth[1] || sscanf(meth[1],"%d%c",&max_iter,&junk)!=1 || meth[2])
{ usage();
}
}
else if (strcmp(meth[0],"enum-block")==0)
{ dec_method = Enum_block;
if (!(gen_file = meth[1]) || meth[2]) usage();
}
else if (strcmp(meth[0],"enum-bit")==0)
{ dec_method = Enum_bit;
if (!(gen_file = meth[1]) || meth[2]) usage();
}
else
{ usage();
}
/* Check that we aren't overusing standard input or output. */
if ((strcmp(pchk_file,"-")==0)
+ (strcmp(rfile,"-")==0) > 1)
{ fprintf(stderr,"Can't read more than one stream from standard input\n");
exit(1);
}
if ((table>0)
+ (strcmp(dfile,"-")==0)
+ (pfile!=0 && strcmp(pfile,"-")==0) > 1)
{ fprintf(stderr,"Can't send more than one stream to standard output\n");
exit(1);
}
/* Read parity check file. */
read_pchk(pchk_file);
if (N<=M)
{ fprintf(stderr,
"Number of bits (%d) should be greater than number of checks (%d)\n",N,M);
exit(1);
}
/* Open file of received data. */
rf = open_file_std(rfile,"r");
if (rf==NULL)
{ fprintf(stderr,"Can't open file of received data: %s\n",rfile);
exit(1);
}
/* Create file for decoded data. */
df = open_file_std(dfile,"w");
if (df==NULL)
{ fprintf(stderr,"Can't create file for decoded data: %s\n",dfile);
exit(1);
}
/* Create file for bit probabilities, if specified. */
if (pfile)
{ pf = open_file_std(pfile,"w");
if (pf==NULL)
{ fprintf(stderr,"Can't create file for bit probabilities: %s\n",pfile);
exit(1);
}
}
/* Allocate space for data from channel. */
switch (channel)
{ case BSC:
{ bsc_data = chk_alloc (N, sizeof *bsc_data);
break;
}
case AWGN: case AWLN:
{ awn_data = chk_alloc (N, sizeof *awn_data);
break;
}
default:
{ abort();
}
}
/* Allocate other space. */
dblk = chk_alloc (N, sizeof *dblk);
lratio = chk_alloc (N, sizeof *lratio);
pchk = chk_alloc (M, sizeof *pchk);
bitpr = chk_alloc (N, sizeof *bitpr);
/* Print header for summary table. */
if (table==1)
{ printf(" block iterations valid changed\n");
}
/* Do the setup for the decoding method. */
switch (dec_method)
{ case Prprp:
{ prprp_decode_setup();
break;
}
case Enum_block: case Enum_bit:
{ enum_decode_setup();
break;
}
default: abort();
}
/* Read received blocks, decode, and write decoded blocks. */
tot_iter = 0;
tot_valid = 0;
tot_changed = 0;
for (block_no = 0; ; block_no++)
{
/* Read block from received file, exit if end-of-file encountered. */
for (i = 0; i<N; i++)
{ int c;
switch (channel)
{ case BSC:
{ c = fscanf(rf,"%1d",&bsc_data[i]);
break;
}
case AWGN: case AWLN:
{ c = fscanf(rf,"%lf",&awn_data[i]);
break;
}
default: abort();
}
if (c==EOF)
{ if (i>0)
{ fprintf(stderr,
"Warning: Short block (%d long) at end of received file ignored\n",i);
}
goto done;
}
if (c<1 || channel==BSC && bsc_data[i]!=0 && bsc_data[i]!=1)
{ fprintf(stderr,"File of received data is garbled\n");
exit(1);
}
}
/* Find likelihood ratio for each bit. */
switch (channel)
{ case BSC:
{ for (i = 0; i<N; i++)
{ lratio[i] = bsc_data[i]==1 ? (1-error_prob) / error_prob
: error_prob / (1-error_prob);
}
break;
}
case AWGN:
{ for (i = 0; i<N; i++)
{ lratio[i] = exp(2*awn_data[i]/(std_dev*std_dev));
}
break;
}
case AWLN:
{ for (i = 0; i<N; i++)
{ double e, d1, d0;
e = exp(-(awn_data[i]-1)/lwidth);
d1 = 1 / ((1+e)*(1+1/e));
e = exp(-(awn_data[i]+1)/lwidth);
d0 = 1 / ((1+e)*(1+1/e));
lratio[i] = d1/d0;
}
break;
}
default: abort();
}
/* Try to decode using the specified method. */
switch (dec_method)
{ case Prprp:
{ iters = prprp_decode (H, lratio, dblk, pchk, bitpr);
break;
}
case Enum_block: case Enum_bit:
{ iters = enum_decode (lratio, dblk, bitpr, dec_method==Enum_block);
break;
}
default: abort();
}
/* See if it worked, and how many bits were changed. */
valid = check(H,dblk,pchk)==0;
chngd = changed(lratio,dblk,N);
tot_iter += iters;
tot_valid += valid;
tot_changed += chngd;
/* Print summary table entry. */
if (table==1)
{ printf ("%7d %10f %d %8.1f\n",
block_no, (double)iters, valid, (double)chngd);
/* iters is printed as a double to avoid problems if it's >= 2^31 */
fflush(stdout);
}
/* Write decoded block. */
blockio_write(df,dblk,N);
/* Write bit probabilities, if asked to. */
if (pfile)
{ for (j = 0; j<N; j++)
{ fprintf(pf," %.5f",bitpr[j]);
}
fprintf(pf,"\n");
}
/* Check for errors when writing. */
if (ferror(df) || pfile && ferror(pf))
{ break;
}
}
/* Finish up. */
done:
fprintf(stderr,
"Decoded %d blocks, %d valid. Average %.1f iterations, %.0f%% bit changes\n",
block_no, tot_valid, (double)tot_iter/block_no,
100.0*(double)tot_changed/(N*block_no));
if (ferror(df) || fclose(df)!=0)
{ fprintf(stderr,"Error writing decoded blocks to %s\n",dfile);
exit(1);
}
if (pfile)
{ if (ferror(pf) || fclose(pf)!=0)
{ fprintf(stderr,"Error writing bit probabilities to %s\n",dfile);
exit(1);
}
}
exit(0);
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage:\n");
fprintf(stderr,
" decode [ -f ] [ -t | -T ] pchk-file received-file decoded-file [ bp-file ] channel method\n");
channel_usage();
fprintf(stderr,
"Method: enum-block gen-file | enum-bit gen-file | prprp [-]max-iterations\n");
exit(1);
}

342
lib/ldpc/decoding.html Executable file
View File

@ -0,0 +1,342 @@
<HTML><HEAD>
<TITLE> Decoding Received Blocks </TITLE>
</HEAD><BODY>
<H1> Decoding Received Blocks </H1>
Transmitted codewords are decoded from the received data on the basis
of the <I>likelihood</I> of the possible codewords, which is the
probability of receiving the data that was actually received if the
codeword is question were the one that was sent. This software
presently deals only with memoryless channels, in which the noise is
independent from bit to bit. For such a channel, the likelihood
factorizes into a product of likelihoods for each bit.
For decoding purposes, all that matters is the relative likelihood
for a bit to be 1 versus 0. This is captured by the <I>likelihood
ratio</I> in favour of a 1, which is P(data | bit is 1) / P(data |
bit is 0).
<P>For a Binary Symmetric Channel with error probability <I>p</I>,
the likelihood ratio in favour of a 1 bit is as follows:
<BLOCKQUOTE>
If the received data was +1: (1-<I>p</I>) / <I>p</I><BR>
If the received data was -1: <I>p</I> / (1-<I>p</I>)
</BLOCKQUOTE>
For an Additive White Gaussian Noise channel, with signals of +1 for a 1 bit
and or -1 for a 0 bit, and with noise standard deviation <I>s</I>, the
likelihood ratio in favour of a 1 bit when data <I>y</I> was received is
<BLOCKQUOTE>
exp ( 2y / s<SUP><SMALL>2</SMALL></SUP> )
</BLOCKQUOTE>
For an Additive White Logistic Noise channel, the corresponding
likelihood ratio is
<I>d</I><SUB><SMALL>1</SMALL></SUB>/<I>d</I><SUB><SMALL>0</SMALL></SUB>,
where
<I>d</I><SUB><SMALL>1</SMALL></SUB>=<I>e</I><SUB><SMALL>1</SMALL></SUB>
/ (1+<I>e</I><SUB><SMALL>1</SMALL></SUB>)<SUP><SMALL>2</SMALL></SUP> and
<I>d</I><SUB><SMALL>0</SMALL></SUB>=<I>e</I><SUB><SMALL>0</SMALL></SUB>
/ (1+<I>e</I><SUB><SMALL>0</SMALL></SUB>)<SUP><SMALL>2</SMALL></SUP>,
with <I>e</I><SUB><SMALL>1</SMALL></SUB>=exp(-(<I>y</I>-1)/<I>w</I>) and
<I>e</I><SUB><SMALL>0</SMALL></SUB>=exp(-(<I>y</I>+1)/<I>w</I>).
<BLOCKQUOTE> </BLOCKQUOTE>
<P>It is usual to consider codewords to be equally likely <I>a
priori</I>. This is reasonable if the source messages are all equally
likely (any source redundancy being ignored, or remove by a
preliminary data compression stage), provided that the mapping from
source messages to codewords is onto. Decoding can then be done using
only the parity check matrix defining the codewords, without reference
to the generator matrix defining the mapping from source messages to
codewords. Note that the condition that this mapping be onto isn't
true with this software in the atypical case where the code is defined
by a parity check matrix with redundant rows; see the discussion of <A
HREF="dep-H.html">linear dependence in parity check matrices</A>.
This minor complication is mostly ignored here, except by the exhaustive
enumeration decoding methods.
<P>Assuming equal <I>a priori</I> probabilities for codewords, the
probability of correctly decoding an entire codeword is minimized by
picking the codeword with the highest likelihood. One might instead
wish to decode each bit to the value that is most probable. This
minimizes the bit error rate, but is not in general guaranteed to lead
a decoding for each block to the most probable complete codeword;
indeed, the decoding may not be a codeword at all. Minimizing the bit
error rate seems nevertheless to be the most sensible objective,
unless block boundaries have some significance in a wider context.
<P>Optimal decoding by either criterion is infeasible for general
linear codes when messages are more than about 20 or 30 bits in
length. The fundamental advantage of Low Density Parity Check codes
is that good (though not optimal) decodings can be obtained by methods
such as probability propagation, described next.
<A NAME="prprp"><H2>Decoding by probability propagation</H2></A>
<P>The probability propagation algorithm was originally devised by
Robert Gallager in the early 1960's and later reinvented by David
MacKay and myself. It can be seen as an instance of the sum-product
algorithm for inference on factor graphs, and as an instance of belief
propagation in probabilistic networks. See the <A
HREF="refs.html">references</A> for details. Below, I give a fairly
intuitive description of the algorithm.
<P>The algorithm uses only the parity check matrix for the code, whose
columns correspond to codeword bits, and whose rows correspond to
parity checks, and the likelihood ratios for the bits derived from the
data. It aims to find the probability of each bit of the transmitted
codeword being 1, though the results of the algorithm are in general
only approximate.
<P>The begin, information about each bit of the codeword derived from
the received data for that bit alone is expressed as a <I>probability
ratio</I>, the probability of the bit being 1 divided by the
probability of the bit being 0. This probability ratio is equal to
the likelihood ratio (see above) for that bit, since 0 and 1 are
assumed to be equally likely <I>a priori</I>. As the algorithm
progresses, these probability ratios will be modified to take account
of information obtained from other bits, in conjunction with the
requirement that the parity checks be satisfied. To avoid double
counting of information, for every bit, the algorithm maintains a
separate probability ratio for each parity check that that bit
participates in, giving the probability for that bit to be 1 versus 0
based only on information derived from <I>other</I> parity checks,
along with the data received for the bit.
<P>For each parity check, the algorithm maintains separate
<I>likelihood ratios</I> (analogous to, but distinct from, the
likelihood ratios based on received data), for every bit that
participates in that parity check. These ratios give the probability
of that parity check being satisfied if the bit in question is 1
divided by the probability of the check being satisfied if the bit is
0, taking account of the probabilities of each of the <I>other</I>
bits participating in this check being 1, as derived from the
probability ratios for these bits with respect to this check.
<P>The algorithm alternates between recalculating the likelihood
ratios for each check, which are stored in the <B>lr</B> fields of the
parity check matrix entries, and recalculating the probability ratios
for each bit, which are stored in the <B>pr</B> fields of the entries
in the sparse matrix representation of the parity check matrix. (See
the documentation on <A HREF="mod2sparse.html#rep">representation of
sparse matrices</A> for details on these entries.)
<P>Recalculating the likelihood ratio for a check with respect to some
bit may appear time consuming, requiring that all possible
combinations of values for the other bits participating in the check
be considered. Fortunately, there is a short cut. One can calculate
<BLOCKQUOTE>
<I>t</I>
= product of [ 1 / (1+<I>p<SUB><SMALL>i</SMALL></SUB></I>)
- <I>p<SUB><SMALL>i</SMALL></SUB></I> /
(1+<I>p<SUB><SMALL>i</SMALL></SUB></I>) ]
= product of [ 2 / (1+<I>p<SUB><SMALL>i</SMALL></SUB></I>) - 1 ]
</BLOCKQUOTE>
where the product is over the probability ratios
<I>p<SUB><SMALL>i</SMALL></SUB></I> for the other bits participating
in this check. Factor <I>i</I> in this product is equal to probability
of bit <I>i</I> being 0 minus the probability that it is 1. The terms
in the expansion of this product (in the first form above) correspond to
possible combinations of values for the other bits, with the result that
<I>t</I> will be the probability of the check being satisfied if the bit
in question is 0 minus the probability if the bit in question is 1. The
likelihood ratio for this check with respect to the bit in question can then
be calculated as (1-<I>t</I>)/(1+<I>t</I>).
<P>For a particular check, the product above differs for different
bits, with respect to which we wish to calculate a likelihood ratio,
only in that for each bit the factor corresponding to that bit is left
out. We can calculate all these products easily by ordering the bits
arbitrarily, computing running products of the factor for the first
bit, the factors for the first two bits, etc., and also running
products of the factor for the last bit, the factors for the last two
bits, etc. Multiplying the running product of the factors up to
<I>i</I>-1 by the running product of the factors from <I>i</I>+1 on
gives the product needed for bit <I>i</I>. The second form of the
factors above is used, as it requires less computation, and is still
well defined even if some ratios are infinite.
<P>To recalculate the probability ratio for a bit with respect to a
check, all that is need is to multiply together the likelihood ratio
for this bit derived from the received data (see above), and the
current values of the likelihood ratios for all the <I>other</I>
checks that this bit participates in, with respect to this bit. To
save time, these products are computed by combining forward and
backward products, similarly to the method used for likelihood ratios.
<P>By including likelihood ratios from all checks, a similar
calculation produces the current probability ratio for the bit to be 1
versus 0 based on all information that has propagated to the bit so
far. This ratio can be thresholded at one to produce the current best
guess as to whether this bit is a 1 or a 0.
<P>The hope is that this algorithm will eventually converge to a state
where these bit probabilities give a near-optimal decoding. This is
does not always occur, but the algorithm behaves well enough to
produce very good results at rates approaching (though not yet
reaching) the theoretical Shannon limit.
<P><A NAME="decode"><HR><B>decode</B>: Decode blocks of received data
into codewords.
<BLOCKQUOTE><PRE>
decode [ -f ] [ -t | -T ] <I>pchk-file received-file decoded-file</I> [ <I>bp-file</I> ] <I>channel method</I>
</PRE>
<BLOCKQUOTE>
where <TT><I>channel</I></TT> is one of:
<BLOCKQUOTE><PRE>
bsc <I>error-probability</I>
awgn <I>standard-deviation</I>
awln <I>width</I>
</PRE></BLOCKQUOTE>
and <TT><I>method</I></TT> is one of:
<BLOCKQUOTE><PRE>
enum-block <TT><I>gen-file</I></TT>
enum-bit <TT><I>gen-file</I></TT>
prprp <TT>[-]<I>max-iterations</I></TT>
</PRE></BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P>Decodes the blocks in <TT><I>received-file</I></TT>, which are
assumed to be have been received through the specified channel. The
results written to <TT><I>decoded-file</I></TT> are the specified
decoding method's guesses as to what bits were sent through the
channel, given what was received. The probability of each bit being a
1, as judged by the decoding method being used, is written to
<TT><I>bp-file</I></TT>, if given.
<P>A newline is output at the end of each block written to
<TT><I>decoded-file</I></TT> and <TT><I>bp-file</I></TT>. Newlines in
<TT><I>received-file</I></TT> are ignored. A warning is displayed on
standard error if the number of bits in <TT><I>received-file</I></TT>
is not a multiple of the block length.
<P>A summary is displayed on standard error, giving the total number
of blocks decoded, the number of blocks that decoded to valid
codewords, the average number of iterations of the decoding algorithm
used, and the percent of bits that were changed from the values one
would guess for them based just on their individual likelihood ratios.
<P>If the <B>-t</B> option is given, a line of information regarding each block
decoded is written to standard output, preceded by a line of headers.
The information for each block is as follows:
<BLOCKQUOTE>
<TABLE>
<tr align="left" valign="top">
<td> <B>block</B> </td>
<td>The number of the block, from zero</td></tr>
<tr align="left" valign="top">
<td> <B>iterations</B> </td>
<td>The number of "iterations" used in decoding. What exactly an iteration
is depends on the decoding method used (see
<A HREF="decode-detail.html">here</A>).</td></tr>
<tr align="left" valign="top">
<td> <B>valid</B> </td>
<td>Has the value 1 if the decoding is a valid codeword, 0 if not.</td></tr>
<tr align="left" valign="top">
<td> <B>changed</B> </td>
<td>The number of bits in the decoding that differ from the bit that would
be chosen based just on the likelihood ratio for that bit. Bits whose
likelihood ratios are exactly one contribute 0.5 to this count.</td></tr>
</TABLE>
</BLOCKQUOTE>
The file produced is is suitable for
reading into the S-Plus or R statistics packages, with a command such as
<BLOCKQUOTE><PRE>
data <- read.table(<I>file</I>,header=T)
</PRE></BLOCKQUOTE>
<P>If instead the <B>-T</B> option is given, detailed information on
the process of decoding each block will be written to standard output.
For a description, see the <A HREF="decode-detail.html">documentation
on detailed decoding trace information</A>.
<P>The type of channel that is assumed is specified after the file
name arguments. This may currently be either <TT>bsc</TT> (or
<TT>BSC</TT>) for the Binary Symmetric Channel, or <TT>awgn</TT> (or
<TT>AWGN</TT>) for the Additive White Gaussian Noise channel, or
<TT>awln</TT> (or <TT>AWLN</TT>) for the Additive White Logistic Noise
channel. The channel type is followed by an argument specifying the
assumed characteristics of the channel, as follows:
<BLOCKQUOTE>
<P>BSC: The probability that a bit will be flipped by noise - ie, the
probability that the bit received is an error.
<P>AWGN: The standard deviation of the Gaussian noise added to the
encodings of the bits.
<P>AWLN: The width parameter of the logistic distribution for the noise
that is added to the encodings of the bits.
</BLOCKQUOTE>
See the description of <A HREF="channel.html">channel transmission</A>
for more about these channels.
<P>Following the channel specification is a specification of the
decoding method to use. The <TT>enum-block</TT> and <TT>enum-bit</TT>
methods find the optimal decoding by exhaustive enumeration of
codewords derived from all possible source messages. They differ in
that <TT>enum-block</TT> decodes to the most likely codeword, whereas
<TT>enum-bit</TT> decodes to the bits that are individually most
probable. These methods require that a file containing a
representation of a generator matrix be given, to allow enumeration of
codewords. If the parity check matrix has no redundant rows, any
valid generator matrix will give the same decoding (except perhaps if
there is a tie). If redundant rows exist, the generator matrix should
specify the same set of message bits as the generator matrix that was
used for the actual encoding, since the redundancy will lead to some
codeword bits being fixed at zero (see <A HREF="dep-H.html">linear
dependence in parity check matrices</A>).
<P>The <TT>prprp</TT> decoding method decodes using <A
HREF="#prprp">probability propagation</A>. The maximum number of
iterations of probability propagation to do is given following
<TT>prprp</TT>. If a minus sign precedes this number, the maximum
number of iterations is always done. If no minus sign is present, the
algorithm stops once the tentative decoding, based on bit-by-bit
probabilities, is a valid codeword. Note that continuing to the
maximum number of iterations will usually result in
at least slightly different bit probabilities (written to
<TT><I>bp-file</I></TT> if specified), and could conceivably change
the decoding compared to stopping at the first valid codeword, or
result in a failure to decode to a valid codeword even though one was
found earlier.
<P>If the <B>-f</B> option is given, output to <TT><I>decoded-file</I></TT>
is flushed after each block. This allows one to use decode as a server,
reading blocks to decode from a named pipe, and writing the decoded block
to another named pipe.
<P><A NAME="extract"><HR><B>extract</B>: Extract the message bits from a block.
<BLOCKQUOTE><PRE>
extract <I>gen-file decoded-file extracted-file</I>
</PRE></BLOCKQUOTE>
<P>Given a file of codewords in <TT><I>decoded-file</I></TT> (usually,
decoded blocks output by <A HREF="#decode"><TT>decode</TT></A>), and a
generator matrix from <TT><I>gen-file</I></TT> (needed only to
determine where the message bits are located in a codeword), this
program writes the message bits extracted from these codewords to the
file <TT><I>extracted-file</I></TT>.
<P>A newline is output at the end of each block written to
<TT><I>extracted-file</I></TT>. Newlines in
<TT><I>decoded-file</I></TT> are ignored. A warning is displayed on
standard error if the number of bits in <TT><I>decoded-file</I></TT>
is not a multiple of the block length.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

85
lib/ldpc/dep-H.html Executable file
View File

@ -0,0 +1,85 @@
<HTML><HEAD>
<TITLE> Linear Dependence in Parity Check Matrices </TITLE>
</HEAD><BODY>
<H1> Linear Dependence in Parity Check Matrices </H1>
<P>If a code is specified by means of a <I>M</I> by <I>N</I> parity
check matrix, <B>H</B>, in which some rows are linearly dependent - a
situation that is usually avoided - it would be possible to map more
than the usual <I>K=N-M</I> message bits into a codeword, since one or
more rows of <B>H</B> could have been deleted without affecting which
bit vectors are codewords.
<P>However, this software does not increase the number of message bits
in this case, but instead produces a generator matrix in which some
rows are all zero, which will cause some bits of the codeword to
always be zero, regardless of the source message. Referring to the <A
HREF="encoding.html#gen-rep">description of generator matrix
representations</A>, this is accomplished by partially computing
what would normally be <B>A</B><SUP><SMALL>-1</SMALL></SUP> (for a
dense or mixed representations) or the <B>L</B> and <B>U</B> matrices
(for a sparse representation), even though singularity prevents this
computation from being carried out fully.
<P><B>Example:</B> The parity check matrix created below is redundant,
since the 10100 row is equal to the sum of the 11000 and 01100 rows.
<UL><PRE>
<LI>make-pchk dep.pchk 4 5 0:0 0:1 1:1 1:2 2:0 2:2 3:3 3:4
<LI>print-pchk -d dep.pchk
Parity check matrix in dep.pchk (dense format):
1 1 0 0 0
0 1 1 0 0
1 0 1 0 0
0 0 0 1 1
<LI>make-gen dep.pchk dep.gen dense
Note: Parity check matrix has 1 redundant checks
Number of 1s per check in Inv(A) X B is 0.2
<LI>print-gen dep.gen
Generator matrix (dense representation):
Column order (message bits at end):
0 1 3 2 4
Inv(A) X B:
0
0
1
0
</PRE></UL>
The generator matrix above can be used to encode message blocks containing
one bit. This message bit is copied unchanged to the last bit (numbered 4)
of the codeword, and the first four bits of the codeword are set by multiplying
this message bit (seen as a vector of length one) by
<B>A</B><SUP><SMALL>-1</SMALL></SUP><B>B</B>, shown above, and then
storing the results in positions given by the column ordering.
The result is that bit 3 of the codeword produced is
also set to the message bit, and bits 0, 1, and 2 are set to zero.
<P>Which bits are used for message bits, and which bits are fixed at
zero, depends on arbitrary choices in the algorithm, which may differ
from one encoding method to another. No attempt is made to make the
best choice.
<P>Note that codeword bits that are always zero can arise even when <B>H</B>
does not have linearly dependent rows. For example, if a row of <B>H</B>
has just one 1 in it, the codeword bit at that position must be zero in any
codeword. The way the software handles parity check matrices with less
than <I>M</I> independent rows is equivalent to adding additional rows
to <B>H</B> in which only one bit is 1, in order to produce <I>M</I>
independent checks.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

188
lib/ldpc/distrib.c Executable file
View File

@ -0,0 +1,188 @@
/* DISTRIB.C - Procedures for handling distributions over numbers. */
/* Copyright (c) 1995-2012 by Radford M. Neal and Peter Junteng Liu.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "alloc.h"
#include "distrib.h"
/* CREATE A DISTRIBUTION AS SPECIFIED IN A STRING. Space for the distribution
is allocated; the string is not freed.
The string must consist either of a single positive integer, representing
the distribution over just that number, or have a form such as the
following:
5x2/3.5x1/1.5x4
This specifies a distribution over 3 numbers, 2, 1, and 4, specified by
the second number in each pair, with proportions of 0.5, 0.35, and 0.15,
respectively, specified by the first number in each pair. The actual
proportions are found by dividing the first number in each pair by the sum
of these numbers.
The distrib type represents the distribution list. It stores a pointer to
an array of distrib_entry elements along with the length of this array.
Each distrib_entry contains a (number,proportion) pair.
*/
distrib *distrib_create
( char *c /* String describing distribution over numbers */
)
{
distrib *d;
char *str, *tstr;
int i, n, scan_num, size;
double prop, sum;
char junk;
/* Check for special case of a single number. */
if (sscanf(c,"%d%c",&n,&junk)==1 && n>0)
{ tstr = chk_alloc ( (int)(4.1+log10(n)), sizeof(*tstr));
sprintf(tstr,"1x%d",n);
d = distrib_create(tstr);
free(tstr);
return d;
}
/* Initial scan of string for size and proper usage. */
str = c;
size = 0;
sum = 0;
d = chk_alloc(1, sizeof *d);
for (;;)
{
scan_num = sscanf(str, "%lgx%d%c", &prop, &n, &junk);
if ((scan_num!=2 && scan_num!=3) || prop<=0 || n<=0)
{ return 0;
}
if (scan_num==3 && junk!='/')
{ return 0;
}
size += 1;
sum += prop;
if (scan_num==2)
{ break;
}
else
{ str = (char*)strchr(str, '/') + 1;
}
}
/* Allocate memory for the list and fill it in */
d->size = size;
d->list = chk_alloc (size, sizeof(distrib_entry));
i = 0;
str = c;
for (;;)
{
scan_num = sscanf(str, "%lgx%d%c", &prop, &n, &junk);
d->list[i].prop = prop/sum;
d->list[i].num = n;
i += 1;
if (scan_num==2)
{ break;
}
else if (scan_num==3)
{ str = (char*)strchr(str, '/') + 1;
}
else
{ abort();
}
}
return d;
}
/* FREE SPACE OCCUPIED A DISTRIBUTION LIST. */
void distrib_free
( distrib *d /* List to free */
)
{ free(d->list);
free(d);
}
/* RETURN THE MAXIMUM NUMBER IN A DISTRIBUTION LIST. Returns 0 if the list
pointer is 0. */
int distrib_max
( distrib *d /* List to examine */
)
{
int i;
int cur;
if (d==0) return 0;
cur = 0;
for (i = 1; i<d->size; i++)
{ if (d->list[i].num > d->list[cur].num)
{ cur = i;
}
}
return d->list[cur].num;
}
/* TEST PROGRAM. */
#ifdef TEST_DISTRIB
main
( int argc,
char **argv
)
{
distrib *d;
int i, j;
for (i = 1; i<argc; i++)
{ d = distrib_create(argv[i]);
if (d==0)
{ printf("Error\n\n");
}
else
{ for (j = 0; j<distrib_size(d); j++)
{ printf("%.3f %d\n",distrib_prop(d,j),distrib_num(d,j));
}
printf("\n");
}
}
exit(0);
}
#endif

49
lib/ldpc/distrib.h Executable file
View File

@ -0,0 +1,49 @@
/* DISTRIB.H - Interface to module for handling distributions over numbers. */
/* Copyright (c) 1995-2012 by Radford M. Neal and Peter Junteng Liu.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* DATA STRUCTURES USED TO STORE A DISTRIBUTION LIST. Entries in the list
* (distrib_entry) are stored in an array (distrib->list[]). */
typedef struct distrib_entry
{ int num; /* A positive number */
double prop; /* Proportion for this number */
} distrib_entry;
typedef struct distrib
{ struct distrib_entry *list; /* The list of numbers and proportions */
int size; /* Number of entries in the list */
} distrib;
/* MACROS TO ACCESS ELEMENTS OF A DISTRIBUTION LIST. Note that indexes for
entries start at 0. */
#define distrib_num(d,i) \
((d)->list[i].num) /* The number for the i'th entry */
#define distrib_prop(d,i) \
((d)->list[i].prop) /* The i'th entry's proportion [probability] */
#define distrib_size(d) \
((d)->size) /* The length of the list (integer) */
/* PROCEDURES FOR DISTRIBUTION LISTS. */
distrib *distrib_create (char *);
void distrib_free (distrib *);
int distrib_max(distrib *);

154
lib/ldpc/enc.c Executable file
View File

@ -0,0 +1,154 @@
/* ENC.C - Encoding procedures. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "rand.h"
#include "alloc.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
#include "enc.h"
/* The procedures in this module obtain the generator matrix to use for
encoding from the global variables declared in rcode.h */
/* ENCODE A BLOCK USING A SPARSE REPRESENTATION OF THE GENERATOR MATRIX. */
void sparse_encode
( char *sblk,
char *cblk
)
{
int i, j;
mod2entry *e;
char *x, *y;
x = chk_alloc (M, sizeof *x);
y = chk_alloc (M, sizeof *y);
/* Multiply the vector of source bits by the systematic columns of the
parity check matrix, giving x. Also copy these bits to the coded block. */
for (i = 0; i<M; i++) x[i] = 0;
for (j = M; j<N; j++)
{
cblk[cols[j]] = sblk[j-M];
if (sblk[j-M]==1)
{ for (e = mod2sparse_first_in_col(H,cols[j]);
!mod2sparse_at_end(e);
e = mod2sparse_next_in_col(e))
{ x[mod2sparse_row(e)] ^= 1;
}
}
}
/* Solve Ly=x for y by forward substitution, then U(cblk)=y by backward
substitution. */
if (!mod2sparse_forward_sub(L,rows,x,y)
|| !mod2sparse_backward_sub(U,cols,y,cblk))
{
abort(); /* Shouldn't occur, even if the parity check matrix has
redundant rows */
}
free(x);
free(y);
}
/* ENCODE A BLOCK USING DENSE REPRESENTATION OF GENERATOR MATRIX. */
void dense_encode
( char *sblk,
char *cblk,
mod2dense *u,
mod2dense *v
)
{
int j;
/* Copy source bits to the systematic part of the coded block. */
for (j = M; j<N; j++)
{ cblk[cols[j]] = sblk[j-M];
}
/* Multiply by Inv(A) X B to produce check bits. */
for (j = M; j<N; j++)
{ mod2dense_set(u,j-M,0,sblk[j-M]);
}
mod2dense_multiply(G,u,v);
/* Copy check bits to the right places in the coded block. */
for (j = 0; j<M; j++)
{ cblk[cols[j]] = mod2dense_get(v,j,0);
}
}
/* ENCODE A BLOCK USING MIXED REPRESENTATION OF GENERATOR MATRIX. */
void mixed_encode
( char *sblk,
char *cblk,
mod2dense *u,
mod2dense *v
)
{
mod2entry *e;
int j;
/* Multiply the vector of source bits by the message bit columns of the
parity check matrix. Also copy these bits to the coded block. Take
account of how columns have been reordered. */
mod2dense_clear(u);
for (j = M; j<N; j++)
{
cblk[cols[j]] = sblk[j-M];
if (sblk[j-M]==1)
{ for (e = mod2sparse_first_in_col(H,cols[j]);
!mod2sparse_at_end(e);
e = mod2sparse_next_in_col(e))
{ (void) mod2dense_flip(u,mod2sparse_row(e),0);
}
}
}
/* Multiply by Inv(A) to produce check bits. */
mod2dense_multiply(G,u,v);
/* Copy check bits to the right places in the coded block. */
for (j = 0; j<M; j++)
{ cblk[cols[j]] = mod2dense_get(v,j,0);
}
}

18
lib/ldpc/enc.h Executable file
View File

@ -0,0 +1,18 @@
/* ENC.H - Interface to encoding procedures. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
void sparse_encode (char *, char *);
void dense_encode (char *, char *, mod2dense *, mod2dense *);
void mixed_encode (char *, char *, mod2dense *, mod2dense *);

195
lib/ldpc/encode.c Executable file
View File

@ -0,0 +1,195 @@
/* ENCODE.C - Encode message blocks. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "rand.h"
#include "alloc.h"
#include "blockio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
#include "enc.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *source_file, *encoded_file;
char *pchk_file, *gen_file;
mod2dense *u, *v;
FILE *srcf, *encf;
char *sblk, *cblk, *chks;
int i, n;
/* Look at initial flag arguments. */
blockio_flush = 0;
while (argc>1)
{
if (strcmp(argv[1],"-f")==0)
{ if (blockio_flush!=0) usage();
blockio_flush = 1;
}
else
{ break;
}
argc -= 1;
argv += 1;
}
/* Look at remaining arguments. */
if (!(pchk_file = argv[1])
|| !(gen_file = argv[2])
|| !(source_file = argv[3])
|| !(encoded_file = argv[4])
|| argv[5])
{ usage();
}
if ((strcmp(pchk_file,"-")==0)
+ (strcmp(gen_file,"-")==0)
+ (strcmp(source_file,"-")==0) > 1)
{ fprintf(stderr,"Can't read more than one stream from standard input\n");
exit(1);
}
/* Read parity check file */
read_pchk(pchk_file);
if (N<=M)
{ fprintf(stderr,
"Can't encode if number of bits (%d) not greater than number of checks (%d)\n",
N,M);
exit(1);
}
/* Read generator matrix file. */
read_gen(gen_file,0,0);
/* Allocate needed space. */
if (type=='d')
{ u = mod2dense_allocate(N-M,1);
v = mod2dense_allocate(M,1);
}
if (type=='m')
{ u = mod2dense_allocate(M,1);
v = mod2dense_allocate(M,1);
}
/* Open source file. */
srcf = open_file_std(source_file,"r");
if (srcf==NULL)
{ fprintf(stderr,"Can't open source file: %s\n",source_file);
exit(1);
}
/* Create encoded output file. */
encf = open_file_std(encoded_file,"w");
if (encf==NULL)
{ fprintf(stderr,"Can't create file for encoded data: %s\n",encoded_file);
exit(1);
}
sblk = chk_alloc (N-M, sizeof *sblk);
cblk = chk_alloc (N, sizeof *cblk);
chks = chk_alloc (M, sizeof *chks);
/* Encode successive blocks. */
for (n = 0; ; n++)
{
/* Read block from source file. */
if (blockio_read(srcf,sblk,N-M)==EOF)
{ break;
}
/* Compute encoded block. */
switch (type)
{ case 's':
{ sparse_encode (sblk, cblk);
break;
}
case 'd':
{ dense_encode (sblk, cblk, u, v);
break;
}
case 'm':
{ mixed_encode (sblk, cblk, u, v);
break;
}
}
/* Check that encoded block is a code word. */
mod2sparse_mulvec (H, cblk, chks);
for (i = 0; i<M; i++)
{ if (chks[i]==1)
{ fprintf(stderr,"Output block %d is not a code word! (Fails check %d)\n",n,i);
abort();
}
}
/* Write encoded block to encoded output file. */
blockio_write(encf,cblk,N);
if (ferror(encf))
{ break;
}
}
fprintf(stderr,
"Encoded %d blocks, source block size %d, encoded block size %d\n",n,N-M,N);
if (ferror(encf) || fclose(encf)!=0)
{ fprintf(stderr,"Error writing encoded blocks to %s\n",encoded_file);
exit(1);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,
"Usage: encode [ -f ] pchk-file gen-file source-file encoded-file\n");
exit(1);
}

283
lib/ldpc/encoding.html Executable file
View File

@ -0,0 +1,283 @@
<HTML><HEAD>
<TITLE> Encoding Message Blocks </TITLE>
</HEAD><BODY>
<H1> Encoding Message Blocks </H1>
To use a code to send messages, we must define a mapping from a bit
vector, <B>s</B>, of length <I>K</I>, representing a source message,
to a codeword, <B>x</B>, of length <I>N</I>&gt;<I>K</I>. We will
consider only linear mappings, which can be written in the form
<B>x</B>=<B>G</B><SUP><SMALL>T</SMALL></SUP><B>s</B>, where <B>G</B>
is a <I>generator matrix</I>. For a code with parity check matrix
<B>H</B>, whose codewords satisfy <B>Hx</B>=<B>0</B>, the generator
matrix must satisfy <B>HG</B><SUP><SMALL>T</SMALL></SUP>=<B>0</B>.
This software assumes that the number of rows in the parity check
matrix, <I>M</I>, is equal to <I>N-K</I>, as would normally be the
case.
<P>This software deals only with <I>systematic</I> encodings, in which
the <I>K</I> bits of <B>s</B> are copied unchanged to some subset of
the <I>N</i> bits of <B>x</B> (the <I>message bits</I>), and the
remaining <I>M=N-K</I> <I>check bits</I> of <B>x</B> are then set so
as to make the result a codeword. For a linear code, a systematic
encoding scheme always exists, for some choice of which bits of a
codeword are message bits. It is conventional to rearrange the order
of the bits in a codeword so that the message bits come first. The
first <I>K</I> columns of the <I>K</I> by <I>N</I> generator matrix
will then be the identity matrix.
<P>However, this software does <I>not</I> assume that the message bits
come first, since different encoding methods prefer different
locations for the message bits. Instead, a vector of indexes of where
each message bit is located within a codeword is recorded in a file
along with a representation of the part of the generator matrix that
produces the check bits. More than one such generator matrix file can
be created for a single parity check file, in which the locations of
the message bits may be different. Decoding of a received message
into a codeword (with <A
HREF="decoding.html#decode"><TT>decode</TT></A>) does not depend on
knowing which are the message bits, though this does need to be known
in order to reconstruct the original message (with <A
HREF="decoding.html#extract"><TT>extract</TT></A>).
<P>This software stores representations of generator matrices in files
in a format that is not human-readable (except by using the <A
HREF="#print-gen"><TT>print-gen</TT></A> program). However, these
files <I>are</I> readable on a machine with a different architecture
than they were written on.
<A NAME="gen-rep"><H2>Generator matrix representations</H2></A>
<P>For simplicity of exposition, it will be assumed for the next few
paragraphs that the message bits are located at the <I>end</I> of the
codeword, so a codeword can be divided into <I>M</I> check bits,
<B>c</B>, followed by <I>K</I> message bits, <B>s</B>.
<P>On the above assumption, the parity check matrix, <B>H</B>, can be divided
into an <I>M</I> by <I>M</I> matrix <B>A</B> occupying
the first <I>M</I> columns of <B>H</B> and an <I>M</I> by <I>K</I> matrix
<B>B</B> occupying the remaining columns of <B>H</B>. The requirement that
a codeword, <B>x</B>, satisfy all parity checks (ie, that <B>Hx</B>=<B>0</B>)
can then be written as
<BLOCKQUOTE>
<B>Ac</B> + <B>Bs</B> = <B>0</B>
</BLOCKQUOTE>
Provided that <B>A</B> is non-singular, it follows that
<BLOCKQUOTE>
<B>c</B> = <B>A</B><SUP><SMALL>-1</SMALL></SUP><B>Bs</B>
</BLOCKQUOTE>
<B>A</B> may be singular for some choices of which codeword bits are message
bits, but a choice for which <B>A</B> is non-singular always exists if the
rows of <B>H</B> are linearly independent. It is possible, however, that the
rows of <B>H</B> are not linearly independent (ie, some rows are redundant).
This is an exceptional
and not particularly interesting case, which is mostly ignored in the
descriptions below; see the discussion of <A HREF="dep-H.html">linear
dependence in parity check matrices</A> for the details.
<P>The equation <B>c</B> = <B>A</B><SUP><SMALL>-1</SMALL></SUP><B>Bs</B>
defines what the check bits should be, but actual computation of these
check bits can be done in several ways, three of which are implemented
in this software. Each method involves a different representation of
the generator matrix. (Note that none of these methods involves the
explicit representation of the matrix <B>G</B> mentioned above.)
<P>In the <I>dense representation</I>, the <I>M</I> by <I>K</I> matrix
<B>A</B><SUP><SMALL>-1</SMALL></SUP><B>B</B> is computed, and stored
in a dense format (see the <A HREF="mod2dense.html">dense modulo-2
matrix package</A>). A message is encoded by multiplying the
source bits, <B>s</B>, by this matrix to obtain the required check bits.
<P>In the <I>mixed representation</I>, the <I>M</I> by <I>M</I> matrix
<B>A</B><SUP><SMALL>-1</SMALL></SUP> is computed and stored in a dense
format, and the <I>M</I> by <I>K</I> matrix <B>B</B>, the right
portion of the parity check matrix, is also stored, in a sparse format
(see the <A HREF="mod2sparse.html">sparse modulo-2 matrix package</A>).
To encode a message, the source vector <B>s</B> is first multiplied on
the left by <B>B</B>, an operation which can be done very quickly if
<B>B</B> is sparse (as it will be for LDPC codes). The result is then
multiplied on the left by <B>A</B><SUP><SMALL>-1</SMALL></SUP>. If
<I>M</I>&lt;<I>K</I>, the total time may be less than when using the
dense representation above.
<P>The <I>sparse representation</I> goes further, and avoids
explicitly computing <B>A</B><SUP><SMALL>-1</SMALL></SUP>, which tends
to be dense even if <B>H</B> is sparse. Instead, a <I>LU
decomposition</I> of <B>A</B> is found, consisting of a lower
triangular matrix <B>L</B> and an upper triangular matrix <B>U</B> for
which <B>LU</B>=<B>A</B>. The effect of multiplying <B>Bs</B>=<B>z</B> by
<B>A</B><SUP><SMALL>-1</SMALL></SUP> can then be obtained by
<BLOCKQUOTE>
Solving <B>Ly</B>=<B>z</B> for <B>y</B> using forward substitution.<BR>
Solving <B>Uc</B>=<B>y</B> for <B>c</B> using backward substitution.
</BLOCKQUOTE>
Both of these operations will be fast if <B>L</B> and <B>U</B> are
sparse. Heuristics are used to try to achieve this, by rearranging the
rows and columns of <B>H</B> in the process of selecting <B>A</B> and
finding its LU decomposition.
<P><A NAME="make-gen"><HR><B>make-gen</B>: Make a generator matrix from
a parity check matrix.
<BLOCKQUOTE><PRE>
make-gen <I>pchk-file gen-file method</I>
</PRE>
<BLOCKQUOTE>
where <TT><I>method</I></TT> is one of the following:
<BLOCKQUOTE><PRE>
sparse [ first | mincol | minprod ] [ <I>abandon-num abandon-when</I> ]
dense [ <I>other-gen-file </I> ]
mixed [ <I>other-gen-file </I> ]
</PRE></BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P>Finds a generator matrix for the code whose parity check matrix is
in <TT><I>pchk-file</I></TT>, and writes a representation of this
generator matrix to <TT><I>gen-file</I></TT>. The remaining arguments
specify what representation of the generator matrix is to be used (see
the <A HREF="#gen-rep">description above</A>), and the method to be
used in finding it. A message regarding the density of 1s in the
resulting representation is displayed on standard error. For a sparse
representation, a smaller number of 1s will produce faster encoding.
<P>All representations include a specification for how the columns of
the parity check matrix should be re-ordered so that the message bits
come last. References to columns of the parity check matrix below
refer to their order after this reordering. For the <I>dense</I> and
<I>mixed</I> representations, an <TT><I>other-gen-file</I></TT> may be
specified, in which case the ordering of columns will be the same as
the ordering stored in that file (which must produce a non-singular
<B>A</B> matrix; redundant rows of <B>H</B> are not allowed with this
option). Otherwise, <TT>make-gen</TT> decides on an appropriate
ordering of columns itself. Note that the column rearrangement is
recorded as part of the representation of the generator matrix; the
parity check matrix as stored in its file is not altered.
<P>The <I>dense</I> representation consists of a dense representation
of the matrix <B>A</B><SUP><SMALL>-1</SMALL></SUP><B>B</B>, where
<B>A</B> is the matrix consisting of the first <I>M</I> columns (after
reordering) of the parity check matrix, and <B>B</B> is the remaining
columns. If <B>H</B> contains redundant rows, there is an additional
reordering of columns of <B>A</B> in order create the same effect as
if the redundant rows came last.
<P>The <I>mixed</I> representation consists of a dense representation
of the matrix <B>A</B><SUP><SMALL>-1</SMALL></SUP>, where <B>A</B> is
the matrix consisting of the first <I>M</I> columns (after reordering)
of the parity check matrix. The remaining columns of the parity check
matrix, making up the matrix <B>B</B>, are also part of the
representation, but are not written to <TT><I>gen-file</I></TT>, since
they can be obtained from <TT><I>pchk-file</I></TT>. As for mixed
representations, an additional reordering of columns of <B>A</B> may
be needed if <B>H</B> has redundant rows.
<P>A <I>sparse</I> representation consists of sparse representations
of the <B>L</B> and <B>U</B> matrices, whose product is <B>A</B>, the
first <I>M</I> columns of the parity check matrix (whose columns and
rows may both have been reordered). The matrix <B>B</B>, consisting
of the remaining columns of the parity check matrix, is also part of
the representation, but it is not written to <TT><I>gen-file</I></TT>,
since it can be obtained from <TT><I>pchk-file</I></TT>.
<P>If a sparse representation is chosen, arguments after
<TT>sparse</TT> specify what heuristic is used when reordering columns
and rows in order to try to make <B>L</B> and <B>U</B> as sparse as
possible. The default if no heuristic is specified is
<TT>minprod</TT>. If the <TT><I>abandon-num</I></TT> and
<TT><I>abandon-when</I></TT> options are given, some information is
discarded in order to speed up the process of finding <B>L</B> and
<B>U</B>, at a possible cost in terms of how good a result is
obtained. For details on these heuristics, see the descriptions of <A
HREF="sparse-LU.html">sparse LU decomposition methods</A>.
<P><B>Example:</B> A dense representation of a generator matrix for the
Hamming code created by the example for <A
HREF="pchk.html#make-pchk"><TT>make-pchk</TT></A> can be created as follows:
<UL><PRE>
<LI>make-gen ham7.pchk ham7.gen dense
Number of 1s per check in Inv(A) X B is 3.0
</PRE></UL>
<P><A NAME="print-gen"><HR><B>print-gen</B>: Print a representation of a
generator matrix.
<BLOCKQUOTE><PRE>
print-gen [ -d ] <I>gen-file</I>
</PRE></BLOCKQUOTE>
<P>Prints in human-readable form the representation of the generator
matrix that is stored in <TT><I>gen-file</I></TT>. The <B>-d</B>
option causes the matrices involved to be printed in a dense format,
even if they are stored in the file in a sparse format. See the <A
HREF="#gen-rep">description above</A> for details of generator matrix
representations. Note that the <B>L</B> matrix for a sparse representation
will be lower triangular only after the rows are rearranged, and the <B>U</B>
matrix will be upper triangular only after the columns are rearranged.
The matrix <B>B</B> that is part of the sparse
and mixed representations is not printed, since it is not stored
in the <TT><I>gen-file</I></TT>, but is rather a subset of columns
of the parity check matrix.
<P><B>Example:</B> The generator matrix for the
Hamming code created by the example for <A
HREF="#make-gen"><TT>make-gen</TT></A> can be printed as follows:
<UL><PRE>
<LI>print-gen ham7.gen
Generator matrix (dense representation):
Column order:
0 1 2 3 4 5 6
Inv(A) X B:
1 1 1 0
1 1 0 1
0 1 1 1
</PRE></UL>
For this example, the columns did not need to be rearranged, and hence the
message bits will be in positions 3, 4, 5, and 6 of a codeword.
<P><A NAME="encode"><HR><B>encode</B>: Encode message blocks as codewords
<BLOCKQUOTE><PRE>
encode [ -f ] <I>pchk-file gen-file source-file encoded-file</I>
</PRE></BLOCKQUOTE>
Encodes message blocks of length <I>K</I>, read from
<TT><I>source-file</I></TT>, as codewords of length <I>N</I>, which
are written to <TT><I>encoded-file</I></TT>, replacing any previous
data in this file. Here, <I>N</I> is the number of columns in the
parity check matrix in <TT><I>pchk-file</I></TT>, and
<I>K</I>=<I>N-M</I>, where <I>M</I> is the number of rows in the
parity check matrix. The generator matrix used, from
<TT><I>gen-file</I></TT>, determines which bits of the codeword are
set to the message bits, and how the remaining check bits are
computed. The generator matrix is created from
<TT><I>pchk-file</I></TT> using <A HREF="#make-gen"><TT>make-gen</TT></A>.
<P>A newline is output at the end of each block written to
<TT><I>encoded-file</I></TT>. Newlines in <TT><I>source-file</I></TT>
are ignored.
<P>If the <B>-f</B> option is given, output to <TT><I>encoded-file</I></TT>
is flushed after each block. This allows one to use encode as a server,
reading blocks to encode from a named pipe, and writing the encoded block
to another named pipe.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

60
lib/ldpc/ex-dep Executable file
View File

@ -0,0 +1,60 @@
#!/bin/sh
# Examples of a how a parity check matrix with dependent rows is handled.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
# CODE 1
make-pchk ex-dep.pchk 4 6 0:0 0:5 3:1 3:2
print-pchk -d ex-dep.pchk
echo 00011011 >ex-dep.src
# SPARSE REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen sparse
print-gen -d ex-dep.gen
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
# DENSE REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen dense
print-gen -d ex-dep.gen
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
# MIXED REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen mixed
print-gen -d ex-dep.gen
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
# CODE 2
make-pchk ex-dep.pchk 4 5 0:0 0:1 1:1 1:2 2:0 2:2 3:3 3:4
print-pchk -d ex-dep.pchk
echo 01 >ex-dep.src
# SPARSE REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen sparse
print-gen -d ex-dep.gen
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
# DENSE REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen dense
print-gen -d ex-dep.gen
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
# MIXED REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen mixed
print-gen -d ex-dep.gen
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src

224
lib/ldpc/ex-dep-out Executable file
View File

@ -0,0 +1,224 @@
# CODE 1
make-pchk ex-dep.pchk 4 6 0:0 0:5 3:1 3:2
print-pchk -d ex-dep.pchk
Parity check matrix in ex-dep.pchk (dense format):
1 0 0 0 0 1
0 0 0 0 0 0
0 0 0 0 0 0
0 1 1 0 0 0
echo 00011011 >ex-dep.src
# SPARSE REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen sparse
Note: Parity check matrix has 2 redundant checks
Number of 1s per check in L is 0.8, U is 0.5, B is 0.2, total is 1.5
print-gen -d ex-dep.gen
Generator matrix in ex-dep.gen (sparse representation):
Column order (message bits at end):
5 2 1 3 4 0
Row order:
0 3 2 1
L:
1 0 0 0
0 0 0 0
0 0 0 0
0 1 0 0
U:
0 0 0 0 0 1
0 1 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
Encoded 4 blocks, source block size 2, encoded block size 6
000000
100001
000010
100011
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
Block counts: tot 4, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# DENSE REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen dense
Note: Parity check matrix has 2 redundant checks
Number of 1s per check in Inv(A) X B is 0.2
print-gen -d ex-dep.gen
Generator matrix in ex-dep.gen (dense representation):
Column order (message bits at end):
0 1 2 3 4 5
Inv(A) X B:
0 1
0 0
0 0
0 0
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
Encoded 4 blocks, source block size 2, encoded block size 6
000000
100001
000010
100011
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
Block counts: tot 4, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# MIXED REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen mixed
Note: Parity check matrix has 2 redundant checks
Number of 1s per check in Inv(A) is 0.5, in B is 0.2, total is 0.8
print-gen -d ex-dep.gen
Generator matrix in ex-dep.gen (mixed representation):
Column order (message bits at end):
0 1 2 3 4 5
Inv(A):
1 0 0 0
0 0 0 1
0 0 0 0
0 0 0 0
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
Encoded 4 blocks, source block size 2, encoded block size 6
000000
100001
000010
100011
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
Block counts: tot 4, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# CODE 2
make-pchk ex-dep.pchk 4 5 0:0 0:1 1:1 1:2 2:0 2:2 3:3 3:4
print-pchk -d ex-dep.pchk
Parity check matrix in ex-dep.pchk (dense format):
1 1 0 0 0
0 1 1 0 0
1 0 1 0 0
0 0 0 1 1
echo 01 >ex-dep.src
# SPARSE REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen sparse
Note: Parity check matrix has 1 redundant checks
Number of 1s per check in L is 1.0, U is 1.2, B is 0.5, total is 2.8
print-gen -d ex-dep.gen
Generator matrix in ex-dep.gen (sparse representation):
Column order (message bits at end):
4 1 2 3 0
Row order:
3 0 1 2
L:
0 1 0 0
0 1 1 0
0 0 1 0
1 0 0 0
U:
0 0 0 1 1
0 1 0 0 0
0 0 1 0 0
0 0 0 0 0
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
Encoded 2 blocks, source block size 1, encoded block size 5
00000
11100
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
Block counts: tot 2, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# DENSE REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen dense
Note: Parity check matrix has 1 redundant checks
Number of 1s per check in Inv(A) X B is 0.2
print-gen -d ex-dep.gen
Generator matrix in ex-dep.gen (dense representation):
Column order (message bits at end):
0 1 3 2 4
Inv(A) X B:
0
0
1
0
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
Encoded 2 blocks, source block size 1, encoded block size 5
00000
00011
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
Block counts: tot 2, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# MIXED REPRESENTATION
make-gen ex-dep.pchk ex-dep.gen mixed
Note: Parity check matrix has 1 redundant checks
Number of 1s per check in Inv(A) is 1.0, in B is 0.2, total is 1.2
print-gen -d ex-dep.gen
Generator matrix in ex-dep.gen (mixed representation):
Column order (message bits at end):
0 1 3 2 4
Inv(A):
1 1 0 0
0 1 0 0
0 0 0 1
0 0 0 0
encode ex-dep.pchk ex-dep.gen ex-dep.src ex-dep.enc; cat ex-dep.enc
Encoded 2 blocks, source block size 1, encoded block size 5
00000
00011
verify ex-dep.pchk ex-dep.enc ex-dep.gen ex-dep.src
Block counts: tot 2, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00

38
lib/ldpc/ex-ham7a Executable file
View File

@ -0,0 +1,38 @@
#!/bin/sh
# Example of decoding a (7,4) Hamming code using exhaustive enumeration and
# probability propagation, with an Additive White Gaussian Noise channel with
# noise standard deviation of 0.5, for which Eb/N0 = 5.44 dB.
#
# Testing is done by transmitting zero blocks, which is sufficient because
# both the channel and the decoding procedure are symmetrical. WARNING: But
# things can easily become non-symmetrical with bugs, so this technique should
# be used with caution, and only when necessary for performance reasons.
# Decoding is done three times, once minimizing block error probability, once
# minimizing bit error probability, and once by up to 200 iterations of
# probability propagation.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
make-pchk ex-ham7a.pchk 3 7 0:0 0:3 0:4 0:5 1:1 1:3 1:4 1:6 2:2 2:4 2:5 2:6
make-gen ex-ham7a.pchk ex-ham7a.gen dense
transmit 7x100000 ex-ham7a.rec 1 awgn 0.5
# DECODE BY ENUMERATION TO MINIMIZE BLOCK ERROR PROBABILITY
decode ex-ham7a.pchk ex-ham7a.rec ex-ham7a.dec-blk awgn 0.5 \
enum-block ex-ham7a.gen
verify ex-ham7a.pchk ex-ham7a.dec-blk ex-ham7a.gen
# DECODE BY ENUMERATION TO MINIMIZE BIT ERROR PROBABILITY
decode ex-ham7a.pchk ex-ham7a.rec ex-ham7a.dec-bit awgn 0.5 \
enum-bit ex-ham7a.gen
verify ex-ham7a.pchk ex-ham7a.dec-bit ex-ham7a.gen
# DECODE BY PROBABILITY PROPAGATION
decode ex-ham7a.pchk ex-ham7a.rec ex-ham7a.dec-prp awgn 0.5 \
prprp 200
verify ex-ham7a.pchk ex-ham7a.dec-prp ex-ham7a.gen

33
lib/ldpc/ex-ham7a-out Executable file
View File

@ -0,0 +1,33 @@
make-pchk ex-ham7a.pchk 3 7 0:0 0:3 0:4 0:5 1:1 1:3 1:4 1:6 2:2 2:4 2:5 2:6
make-gen ex-ham7a.pchk ex-ham7a.gen dense
Number of 1s per check in Inv(A) X B is 3.0
transmit 7x100000 ex-ham7a.rec 1 awgn 0.5
Transmitted 700000 bits
# DECODE BY ENUMERATION TO MINIMIZE BLOCK ERROR PROBABILITY
decode ex-ham7a.pchk ex-ham7a.rec ex-ham7a.dec-blk awgn 0.5 \
enum-block ex-ham7a.gen
Decoded 100000 blocks, 100000 valid. Average 16.0 iterations, 2% bit changes
verify ex-ham7a.pchk ex-ham7a.dec-blk ex-ham7a.gen
Block counts: tot 100000, with chk errs 0, with src errs 186, both 0
Bit error rate (on message bits only): 7.950e-04
# DECODE BY ENUMERATION TO MINIMIZE BIT ERROR PROBABILITY
decode ex-ham7a.pchk ex-ham7a.rec ex-ham7a.dec-bit awgn 0.5 \
enum-bit ex-ham7a.gen
Decoded 100000 blocks, 99988 valid. Average 16.0 iterations, 2% bit changes
verify ex-ham7a.pchk ex-ham7a.dec-bit ex-ham7a.gen
Block counts: tot 100000, with chk errs 12, with src errs 186, both 7
Bit error rate (on message bits only): 7.775e-04
# DECODE BY PROBABILITY PROPAGATION
decode ex-ham7a.pchk ex-ham7a.rec ex-ham7a.dec-prp awgn 0.5 \
prprp 200
Decoded 100000 blocks, 99927 valid. Average 0.3 iterations, 2% bit changes
verify ex-ham7a.pchk ex-ham7a.dec-prp ex-ham7a.gen
Block counts: tot 100000, with chk errs 73, with src errs 276, both 52
Bit error rate (on message bits only): 1.290e-03

21
lib/ldpc/ex-ham7b Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
# Example of coding using a (7,4) Hamming code, with transmission through
# a Binary Symmetric Channel with error probability of 0.05.
#
# This example shows how random source messages can be encoded as codewords,
# transmitted through the simulated channel, decoded, and the message bits
# extracted from the codewords. The final result is in ex-ham7b.ext, which can
# be compared to ex-ham7b.src.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
make-pchk ex-ham7b.pchk 3 7 0:0 0:3 0:4 0:5 1:1 1:3 1:4 1:6 2:2 2:4 2:5 2:6
make-gen ex-ham7b.pchk ex-ham7b.gen dense
rand-src ex-ham7b.src 1 4x1000
encode ex-ham7b.pchk ex-ham7b.gen ex-ham7b.src ex-ham7b.enc
transmit ex-ham7b.enc ex-ham7b.rec 1 bsc 0.05
decode ex-ham7b.pchk ex-ham7b.rec ex-ham7b.dec bsc 0.05 enum-bit ex-ham7b.gen
verify ex-ham7b.pchk ex-ham7b.dec ex-ham7b.gen ex-ham7b.src
extract ex-ham7b.gen ex-ham7b.dec ex-ham7b.ext

15
lib/ldpc/ex-ham7b-out Executable file
View File

@ -0,0 +1,15 @@
make-pchk ex-ham7b.pchk 3 7 0:0 0:3 0:4 0:5 1:1 1:3 1:4 1:6 2:2 2:4 2:5 2:6
make-gen ex-ham7b.pchk ex-ham7b.gen dense
Number of 1s per check in Inv(A) X B is 3.0
rand-src ex-ham7b.src 1 4x1000
encode ex-ham7b.pchk ex-ham7b.gen ex-ham7b.src ex-ham7b.enc
Encoded 1000 blocks, source block size 4, encoded block size 7
transmit ex-ham7b.enc ex-ham7b.rec 1 bsc 0.05
Transmitted 7000 bits
decode ex-ham7b.pchk ex-ham7b.rec ex-ham7b.dec bsc 0.05 enum-bit ex-ham7b.gen
Decoded 1000 blocks, 1000 valid. Average 16.0 iterations, 4% bit changes
verify ex-ham7b.pchk ex-ham7b.dec ex-ham7b.gen ex-ham7b.src
Block counts: tot 1000, with chk errs 0, with src errs 47, both 0
Bit error rate (on message bits only): 2.000e-02
extract ex-ham7b.gen ex-ham7b.dec ex-ham7b.ext

45
lib/ldpc/ex-ldpc-encode Executable file
View File

@ -0,0 +1,45 @@
#!/bin/sh
# Example of how an LDPC code can be encoded using using sparse,
# dense, and mixed representations of the generator matrix. The dense
# and mixed representations are based on the same set of message bits
# as the sparse method with minprod heuristic. This allows the correctness
# of these methods to be checked by verifying that they all produce the same
# result when encoding random messages. The results are also checked by
# 'verify'.
#
# A (400,200) LDPC code with 3 checks per bit is used for the test.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
make-ldpc ex-ldpc-encode.pchk 200 400 1 evenboth 3
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.genf sparse first
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.genc sparse mincol
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.genp sparse minprod
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.gend dense ex-ldpc-encode.genp
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.genm mixed ex-ldpc-encode.genp
rand-src ex-ldpc-encode.src 1 200x10
encode ex-ldpc-encode.pchk ex-ldpc-encode.genf ex-ldpc-encode.src \
ex-ldpc-encode.encf
encode ex-ldpc-encode.pchk ex-ldpc-encode.genc ex-ldpc-encode.src \
ex-ldpc-encode.encc
encode ex-ldpc-encode.pchk ex-ldpc-encode.genp ex-ldpc-encode.src \
ex-ldpc-encode.encp
encode ex-ldpc-encode.pchk ex-ldpc-encode.gend ex-ldpc-encode.src \
ex-ldpc-encode.encd
encode ex-ldpc-encode.pchk ex-ldpc-encode.genm ex-ldpc-encode.src \
ex-ldpc-encode.encm
cmp ex-ldpc-encode.encp ex-ldpc-encode.encd
cmp ex-ldpc-encode.encp ex-ldpc-encode.encm
verify ex-ldpc-encode.pchk ex-ldpc-encode.encf ex-ldpc-encode.genf \
ex-ldpc-encode.src
verify ex-ldpc-encode.pchk ex-ldpc-encode.encc ex-ldpc-encode.genc \
ex-ldpc-encode.src
verify ex-ldpc-encode.pchk ex-ldpc-encode.encp ex-ldpc-encode.genp \
ex-ldpc-encode.src

47
lib/ldpc/ex-ldpc-encode-out Executable file
View File

@ -0,0 +1,47 @@
make-ldpc ex-ldpc-encode.pchk 200 400 1 evenboth 3
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.genf sparse first
Number of 1s per check in L is 6.4, U is 6.4, B is 3.0, total is 15.8
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.genc sparse mincol
Number of 1s per check in L is 3.0, U is 3.3, B is 3.0, total is 9.3
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.genp sparse minprod
Number of 1s per check in L is 2.4, U is 3.2, B is 3.0, total is 8.6
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.gend dense ex-ldpc-encode.genp
Number of 1s per check in Inv(A) X B is 69.2
make-gen ex-ldpc-encode.pchk ex-ldpc-encode.genm mixed ex-ldpc-encode.genp
Number of 1s per check in Inv(A) is 64.7, in B is 3.0, total is 67.7
rand-src ex-ldpc-encode.src 1 200x10
encode ex-ldpc-encode.pchk ex-ldpc-encode.genf ex-ldpc-encode.src \
ex-ldpc-encode.encf
Encoded 10 blocks, source block size 200, encoded block size 400
encode ex-ldpc-encode.pchk ex-ldpc-encode.genc ex-ldpc-encode.src \
ex-ldpc-encode.encc
Encoded 10 blocks, source block size 200, encoded block size 400
encode ex-ldpc-encode.pchk ex-ldpc-encode.genp ex-ldpc-encode.src \
ex-ldpc-encode.encp
Encoded 10 blocks, source block size 200, encoded block size 400
encode ex-ldpc-encode.pchk ex-ldpc-encode.gend ex-ldpc-encode.src \
ex-ldpc-encode.encd
Encoded 10 blocks, source block size 200, encoded block size 400
encode ex-ldpc-encode.pchk ex-ldpc-encode.genm ex-ldpc-encode.src \
ex-ldpc-encode.encm
Encoded 10 blocks, source block size 200, encoded block size 400
cmp ex-ldpc-encode.encp ex-ldpc-encode.encd
cmp ex-ldpc-encode.encp ex-ldpc-encode.encm
verify ex-ldpc-encode.pchk ex-ldpc-encode.encf ex-ldpc-encode.genf \
ex-ldpc-encode.src
Block counts: tot 10, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
verify ex-ldpc-encode.pchk ex-ldpc-encode.encc ex-ldpc-encode.genc \
ex-ldpc-encode.src
Block counts: tot 10, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
verify ex-ldpc-encode.pchk ex-ldpc-encode.encp ex-ldpc-encode.genp \
ex-ldpc-encode.src
Block counts: tot 10, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00

50
lib/ldpc/ex-ldpc36-1000a Executable file
View File

@ -0,0 +1,50 @@
#!/bin/sh
# Example of a (2000,1000) LDPC code with 3 checks per bit and 6 bits per
# check, tested on Additive White Gaussian Noise channels with noise standard
# deviations varying from 0.80 to 0.95.
#
# Testing is done by transmitting random messages, which is safer (though
# slower) than using only zero messages. Decoding is done using a maximum
# of 250 iterations of probability propagation.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
make-ldpc ex-ldpc36-1000a.pchk 1000 2000 1 evenboth 3 no4cycle
make-gen ex-ldpc36-1000a.pchk ex-ldpc36-1000a.gen dense
rand-src ex-ldpc36-1000a.src 1 1000x100
encode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.gen ex-ldpc36-1000a.src \
ex-ldpc36-1000a.enc
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB
transmit ex-ldpc36-1000a.enc ex-ldpc36-1000a.rec 1 awgn 0.80
decode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.rec ex-ldpc36-1000a.dec awgn 0.80\
prprp 250
verify ex-ldpc36-1000a.pchk ex-ldpc36-1000a.dec ex-ldpc36-1000a.gen \
ex-ldpc36-1000a.src
# NOISE STANDARD DEVIATION 0.85, Eb/N0 = 1.41 dB
transmit ex-ldpc36-1000a.enc ex-ldpc36-1000a.rec 1 awgn 0.85
decode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.rec ex-ldpc36-1000a.dec awgn 0.85\
prprp 250
verify ex-ldpc36-1000a.pchk ex-ldpc36-1000a.dec ex-ldpc36-1000a.gen \
ex-ldpc36-1000a.src
# NOISE STANDARD DEVIATION 0.90, Eb/N0 = 0.92 dB
transmit ex-ldpc36-1000a.enc ex-ldpc36-1000a.rec 1 awgn 0.90
decode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.rec ex-ldpc36-1000a.dec awgn 0.90\
prprp 250
verify ex-ldpc36-1000a.pchk ex-ldpc36-1000a.dec ex-ldpc36-1000a.gen \
ex-ldpc36-1000a.src
# NOISE STANDARD DEVIATION 0.95, Eb/N0 = 0.45 dB
transmit ex-ldpc36-1000a.enc ex-ldpc36-1000a.rec 1 awgn 0.95
decode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.rec ex-ldpc36-1000a.dec awgn 0.95\
prprp 250
verify ex-ldpc36-1000a.pchk ex-ldpc36-1000a.dec ex-ldpc36-1000a.gen \
ex-ldpc36-1000a.src

57
lib/ldpc/ex-ldpc36-1000a-out Executable file
View File

@ -0,0 +1,57 @@
make-ldpc ex-ldpc36-1000a.pchk 1000 2000 1 evenboth 3 no4cycle
Eliminated 24 cycles of length four by moving checks within column
make-gen ex-ldpc36-1000a.pchk ex-ldpc36-1000a.gen dense
Number of 1s per check in Inv(A) X B is 400.3
rand-src ex-ldpc36-1000a.src 1 1000x100
encode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.gen ex-ldpc36-1000a.src \
ex-ldpc36-1000a.enc
Encoded 100 blocks, source block size 1000, encoded block size 2000
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB
transmit ex-ldpc36-1000a.enc ex-ldpc36-1000a.rec 1 awgn 0.80
Transmitted 200000 bits
decode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.rec ex-ldpc36-1000a.dec awgn 0.80\
prprp 250
Decoded 100 blocks, 100 valid. Average 10.8 iterations, 11% bit changes
verify ex-ldpc36-1000a.pchk ex-ldpc36-1000a.dec ex-ldpc36-1000a.gen \
ex-ldpc36-1000a.src
Block counts: tot 100, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# NOISE STANDARD DEVIATION 0.85, Eb/N0 = 1.41 dB
transmit ex-ldpc36-1000a.enc ex-ldpc36-1000a.rec 1 awgn 0.85
Transmitted 200000 bits
decode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.rec ex-ldpc36-1000a.dec awgn 0.85\
prprp 250
Decoded 100 blocks, 88 valid. Average 52.2 iterations, 12% bit changes
verify ex-ldpc36-1000a.pchk ex-ldpc36-1000a.dec ex-ldpc36-1000a.gen \
ex-ldpc36-1000a.src
Block counts: tot 100, with chk errs 12, with src errs 12, both 12
Bit error rate (on message bits only): 7.490e-03
# NOISE STANDARD DEVIATION 0.90, Eb/N0 = 0.92 dB
transmit ex-ldpc36-1000a.enc ex-ldpc36-1000a.rec 1 awgn 0.90
Transmitted 200000 bits
decode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.rec ex-ldpc36-1000a.dec awgn 0.90\
prprp 250
Decoded 100 blocks, 19 valid. Average 209.4 iterations, 11% bit changes
verify ex-ldpc36-1000a.pchk ex-ldpc36-1000a.dec ex-ldpc36-1000a.gen \
ex-ldpc36-1000a.src
Block counts: tot 100, with chk errs 81, with src errs 81, both 81
Bit error rate (on message bits only): 6.529e-02
# NOISE STANDARD DEVIATION 0.95, Eb/N0 = 0.45 dB
transmit ex-ldpc36-1000a.enc ex-ldpc36-1000a.rec 1 awgn 0.95
Transmitted 200000 bits
decode ex-ldpc36-1000a.pchk ex-ldpc36-1000a.rec ex-ldpc36-1000a.dec awgn 0.95\
prprp 250
Decoded 100 blocks, 1 valid. Average 248.0 iterations, 9% bit changes
verify ex-ldpc36-1000a.pchk ex-ldpc36-1000a.dec ex-ldpc36-1000a.gen \
ex-ldpc36-1000a.src
Block counts: tot 100, with chk errs 99, with src errs 99, both 99
Bit error rate (on message bits only): 1.055e-01

44
lib/ldpc/ex-ldpc36-5000a Executable file
View File

@ -0,0 +1,44 @@
#!/bin/sh
# Example of a (10000,5000) LDPC code with 3 checks per bit and 6 bits per
# check, tested on Additive White Gaussian Noise channels with noise standard
# deviations varying from 0.80 to 0.95.
#
# Testing is done by transmitting random messages, with pipes used so that
# intermediate files are avoided. Decoding is done using a maximum of 250
# iterations of probability propagation.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
make-ldpc ex-ldpc36-5000a.pchk 5000 10000 2 evenboth 3 no4cycle
make-gen ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen dense
rand-src ex-ldpc36-5000a.src 1 5000x100
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB
encode ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen ex-ldpc36-5000a.src - \
| transmit - - 1 awgn 0.80 \
| decode ex-ldpc36-5000a.pchk - - awgn 0.80 prprp 250 \
| verify ex-ldpc36-5000a.pchk - ex-ldpc36-5000a.gen ex-ldpc36-5000a.src
# NOISE STANDARD DEVIATION 0.85, Eb/N0 = 1.41 dB
encode ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen ex-ldpc36-5000a.src - \
| transmit - - 1 awgn 0.85 \
| decode ex-ldpc36-5000a.pchk - - awgn 0.85 prprp 250 \
| verify ex-ldpc36-5000a.pchk - ex-ldpc36-5000a.gen ex-ldpc36-5000a.src
# NOISE STANDARD DEVIATION 0.90, Eb/N0 = 0.92 dB
encode ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen ex-ldpc36-5000a.src - \
| transmit - - 1 awgn 0.90 \
| decode ex-ldpc36-5000a.pchk - - awgn 0.90 prprp 250 \
| verify ex-ldpc36-5000a.pchk - ex-ldpc36-5000a.gen ex-ldpc36-5000a.src
# NOISE STANDARD DEVIATION 0.95, Eb/N0 = 0.45 dB
encode ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen ex-ldpc36-5000a.src - \
| transmit - - 1 awgn 0.95 \
| decode ex-ldpc36-5000a.pchk - - awgn 0.95 prprp 250 \
| verify ex-ldpc36-5000a.pchk - ex-ldpc36-5000a.gen ex-ldpc36-5000a.src

54
lib/ldpc/ex-ldpc36-5000a-out Executable file
View File

@ -0,0 +1,54 @@
make-ldpc ex-ldpc36-5000a.pchk 5000 10000 2 evenboth 3 no4cycle
Eliminated 25 cycles of length four by moving checks within column
make-gen ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen dense
Number of 1s per check in Inv(A) X B is 2068.3
rand-src ex-ldpc36-5000a.src 1 5000x100
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB
encode ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen ex-ldpc36-5000a.src - \
| transmit - - 1 awgn 0.80 \
| decode ex-ldpc36-5000a.pchk - - awgn 0.80 prprp 250 \
| verify ex-ldpc36-5000a.pchk - ex-ldpc36-5000a.gen ex-ldpc36-5000a.src
Encoded 100 blocks, source block size 5000, encoded block size 10000
Transmitted 1000000 bits
Decoded 100 blocks, 100 valid. Average 11.1 iterations, 11% bit changes
Block counts: tot 100, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# NOISE STANDARD DEVIATION 0.85, Eb/N0 = 1.41 dB
encode ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen ex-ldpc36-5000a.src - \
| transmit - - 1 awgn 0.85 \
| decode ex-ldpc36-5000a.pchk - - awgn 0.85 prprp 250 \
| verify ex-ldpc36-5000a.pchk - ex-ldpc36-5000a.gen ex-ldpc36-5000a.src
Encoded 100 blocks, source block size 5000, encoded block size 10000
Transmitted 1000000 bits
Decoded 100 blocks, 95 valid. Average 33.7 iterations, 12% bit changes
Block counts: tot 100, with chk errs 5, with src errs 5, both 5
Bit error rate (on message bits only): 2.706e-03
# NOISE STANDARD DEVIATION 0.90, Eb/N0 = 0.92 dB
encode ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen ex-ldpc36-5000a.src - \
| transmit - - 1 awgn 0.90 \
| decode ex-ldpc36-5000a.pchk - - awgn 0.90 prprp 250 \
| verify ex-ldpc36-5000a.pchk - ex-ldpc36-5000a.gen ex-ldpc36-5000a.src
Encoded 100 blocks, source block size 5000, encoded block size 10000
Transmitted 1000000 bits
Decoded 100 blocks, 2 valid. Average 246.2 iterations, 10% bit changes
Block counts: tot 100, with chk errs 98, with src errs 98, both 98
Bit error rate (on message bits only): 7.650e-02
# NOISE STANDARD DEVIATION 0.95, Eb/N0 = 0.45 dB
encode ex-ldpc36-5000a.pchk ex-ldpc36-5000a.gen ex-ldpc36-5000a.src - \
| transmit - - 1 awgn 0.95 \
| decode ex-ldpc36-5000a.pchk - - awgn 0.95 prprp 250 \
| verify ex-ldpc36-5000a.pchk - ex-ldpc36-5000a.gen ex-ldpc36-5000a.src
Encoded 100 blocks, source block size 5000, encoded block size 10000
Transmitted 1000000 bits
Decoded 100 blocks, 0 valid. Average 250.0 iterations, 9% bit changes
Block counts: tot 100, with chk errs 100, with src errs 100, both 100
Bit error rate (on message bits only): 1.092e-01

46
lib/ldpc/ex-ldpcvar-5000a Executable file
View File

@ -0,0 +1,46 @@
#!/bin/sh
# Example of a (10000,5000) LDPC code with varying numbers of check per bit,
# tested on Additive White Gaussian Noise channels with noise standard
# deviations varying from 0.80 to 0.95. The code has 20% columns with two
# check bits, 70% columns with three check bits, and 10% columns with seven
# check bits.
#
# Testing is done by transmitting random messages, with pipes used so that
# intermediate files are avoided. Decoding is done using a maximum of 250
# iterations of probability propagation.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
make-ldpc ex-ldpcvar-5000a.pchk 5000 10000 2 evenboth 2x2/7x3/1x7 no4cycle
make-gen ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen dense
rand-src ex-ldpcvar-5000a.src 1 5000x100
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB
encode ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src - \
| transmit - - 1 awgn 0.80 \
| decode ex-ldpcvar-5000a.pchk - - awgn 0.80 prprp 250 \
| verify ex-ldpcvar-5000a.pchk - ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src
# NOISE STANDARD DEVIATION 0.85, Eb/N0 = 1.41 dB
encode ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src - \
| transmit - - 1 awgn 0.85 \
| decode ex-ldpcvar-5000a.pchk - - awgn 0.85 prprp 250 \
| verify ex-ldpcvar-5000a.pchk - ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src
# NOISE STANDARD DEVIATION 0.90, Eb/N0 = 0.92 dB
encode ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src - \
| transmit - - 1 awgn 0.90 \
| decode ex-ldpcvar-5000a.pchk - - awgn 0.90 prprp 250 \
| verify ex-ldpcvar-5000a.pchk - ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src
# NOISE STANDARD DEVIATION 0.95, Eb/N0 = 0.45 dB
encode ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src - \
| transmit - - 1 awgn 0.95 \
| decode ex-ldpcvar-5000a.pchk - - awgn 0.95 prprp 250 \
| verify ex-ldpcvar-5000a.pchk - ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src

54
lib/ldpc/ex-ldpcvar-5000a-out Executable file
View File

@ -0,0 +1,54 @@
make-ldpc ex-ldpcvar-5000a.pchk 5000 10000 2 evenboth 2x2/7x3/1x7 no4cycle
Eliminated 46 cycles of length four by moving checks within column
make-gen ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen dense
Number of 1s per check in Inv(A) X B is 1437.1
rand-src ex-ldpcvar-5000a.src 1 5000x100
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB
encode ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src - \
| transmit - - 1 awgn 0.80 \
| decode ex-ldpcvar-5000a.pchk - - awgn 0.80 prprp 250 \
| verify ex-ldpcvar-5000a.pchk - ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src
Encoded 100 blocks, source block size 5000, encoded block size 10000
Transmitted 1000000 bits
Decoded 100 blocks, 100 valid. Average 11.3 iterations, 11% bit changes
Block counts: tot 100, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# NOISE STANDARD DEVIATION 0.85, Eb/N0 = 1.41 dB
encode ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src - \
| transmit - - 1 awgn 0.85 \
| decode ex-ldpcvar-5000a.pchk - - awgn 0.85 prprp 250 \
| verify ex-ldpcvar-5000a.pchk - ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src
Encoded 100 blocks, source block size 5000, encoded block size 10000
Transmitted 1000000 bits
Decoded 100 blocks, 100 valid. Average 18.0 iterations, 12% bit changes
Block counts: tot 100, with chk errs 0, with src errs 0, both 0
Bit error rate (on message bits only): 0.000e+00
# NOISE STANDARD DEVIATION 0.90, Eb/N0 = 0.92 dB
encode ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src - \
| transmit - - 1 awgn 0.90 \
| decode ex-ldpcvar-5000a.pchk - - awgn 0.90 prprp 250 \
| verify ex-ldpcvar-5000a.pchk - ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src
Encoded 100 blocks, source block size 5000, encoded block size 10000
Transmitted 1000000 bits
Decoded 100 blocks, 65 valid. Average 119.8 iterations, 12% bit changes
Block counts: tot 100, with chk errs 35, with src errs 35, both 35
Bit error rate (on message bits only): 2.438e-02
# NOISE STANDARD DEVIATION 0.95, Eb/N0 = 0.45 dB
encode ex-ldpcvar-5000a.pchk ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src - \
| transmit - - 1 awgn 0.95 \
| decode ex-ldpcvar-5000a.pchk - - awgn 0.95 prprp 250 \
| verify ex-ldpcvar-5000a.pchk - ex-ldpcvar-5000a.gen ex-ldpcvar-5000a.src
Encoded 100 blocks, source block size 5000, encoded block size 10000
Transmitted 1000000 bits
Decoded 100 blocks, 0 valid. Average 250.0 iterations, 9% bit changes
Block counts: tot 100, with chk errs 100, with src errs 100, both 100
Bit error rate (on message bits only): 1.017e-01

124
lib/ldpc/ex-wrong-model Executable file
View File

@ -0,0 +1,124 @@
#!/bin/sh
# These tests investigate what happens when the wrong model is used for
# decoding. A (1800,1000) LDPC code with 3 check per bit is used.
# Testing is done by transmitting random messages. Decoding is done using
# a maximum of 100 iterations of probability propagation.
#
# The first set of tests compares decoding of messages sent through an
# AWGN channel using the correct AWGN model with sigma=0.90 to decoding
# using AWGN models with incorrect values for sigma and to decoding
# using AWLN models with varying width parameters for the logistic noise
# distribution.
#
# A second set of tests compares decoding of messages sent through an
# AWLN channel using the correct AWLN model with width=0.50 to decoding
# using AWLN models with incorrect values for width and to decoding
# using AWGN models with varying sigma parameters.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
make-ldpc ex-wrong-model.pchk 1000 1800 1 evenboth 3 no4cycle
make-gen ex-wrong-model.pchk ex-wrong-model.gen dense
rand-src ex-wrong-model.src 1 800x1000
encode ex-wrong-model.pchk ex-wrong-model.gen ex-wrong-model.src \
ex-wrong-model.enc
# FIRST SET OF TESTS, TRANSMITTING THROUGH AWGN CHANNEL WITH SIGMA=0.90
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awgn 0.90
# DECODING WITH CORRECT AWGN NOISE MODEL, SIGMA=0.90
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.40
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.40 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.50
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.60
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.60 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.65
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.65 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# SECOND SET OF TESTS, TRANSMITTING THROUGH AWLN CHANNEL WITH WIDTH=0.50
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awln 0.50
# DECODING WITH CORRECT AWLN NOISE MODEL, WIDTH=0.50
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.80
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.80 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.90
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.00
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.00 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.05
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.05 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src

163
lib/ldpc/ex-wrong-model-out Executable file
View File

@ -0,0 +1,163 @@
make-ldpc ex-wrong-model.pchk 1000 1800 1 evenboth 3 no4cycle
Eliminated 19 cycles of length four by moving checks within column
make-gen ex-wrong-model.pchk ex-wrong-model.gen dense
Number of 1s per check in Inv(A) X B is 318.6
rand-src ex-wrong-model.src 1 800x1000
encode ex-wrong-model.pchk ex-wrong-model.gen ex-wrong-model.src \
ex-wrong-model.enc
Encoded 1000 blocks, source block size 800, encoded block size 1800
# FIRST SET OF TESTS, TRANSMITTING THROUGH AWGN CHANNEL WITH SIGMA=0.90
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awgn 0.90
Transmitted 1800000 bits
# DECODING WITH CORRECT AWGN NOISE MODEL, SIGMA=0.90
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 910 valid. Average 25.8 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 90, with src errs 89, both 89
Bit error rate (on message bits only): 6.484e-03
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 909 valid. Average 25.7 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 91, with src errs 91, both 91
Bit error rate (on message bits only): 6.540e-03
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 900 valid. Average 27.7 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 100, with src errs 100, both 100
Bit error rate (on message bits only): 7.604e-03
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.40
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.40 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 755 valid. Average 42.3 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 245, with src errs 245, both 245
Bit error rate (on message bits only): 1.884e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 827 valid. Average 34.7 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 173, with src errs 172, both 172
Bit error rate (on message bits only): 1.306e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.50
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 849 valid. Average 31.7 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 151, with src errs 151, both 151
Bit error rate (on message bits only): 1.069e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 855 valid. Average 32.3 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 145, with src errs 145, both 145
Bit error rate (on message bits only): 1.022e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.60
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.60 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 790 valid. Average 40.0 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 210, with src errs 210, both 210
Bit error rate (on message bits only): 1.452e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.65
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.65 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 540 valid. Average 63.3 iterations, 11% bit changes
Block counts: tot 1000, with chk errs 460, with src errs 460, both 460
Bit error rate (on message bits only): 3.247e-02
# SECOND SET OF TESTS, TRANSMITTING THROUGH AWLN CHANNEL WITH WIDTH=0.50
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awln 0.50
Transmitted 1800000 bits
# DECODING WITH CORRECT AWLN NOISE MODEL, WIDTH=0.50
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 914 valid. Average 25.1 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 86, with src errs 86, both 86
Bit error rate (on message bits only): 6.130e-03
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 907 valid. Average 25.6 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 93, with src errs 93, both 93
Bit error rate (on message bits only): 6.474e-03
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 893 valid. Average 27.5 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 107, with src errs 107, both 107
Bit error rate (on message bits only): 7.744e-03
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.80
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.80 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 702 valid. Average 44.9 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 298, with src errs 298, both 298
Bit error rate (on message bits only): 2.245e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 765 valid. Average 39.4 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 235, with src errs 235, both 235
Bit error rate (on message bits only): 1.693e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.90
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 808 valid. Average 35.7 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 192, with src errs 192, both 192
Bit error rate (on message bits only): 1.374e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 814 valid. Average 34.6 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 186, with src errs 186, both 186
Bit error rate (on message bits only): 1.291e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.00
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.00 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 808 valid. Average 35.6 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 192, with src errs 192, both 192
Bit error rate (on message bits only): 1.320e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.05
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.05 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 771 valid. Average 40.7 iterations, 11% bit changes
Block counts: tot 1000, with chk errs 229, with src errs 228, both 228
Bit error rate (on message bits only): 1.524e-02

87
lib/ldpc/examples.html Executable file
View File

@ -0,0 +1,87 @@
<HTML><HEAD>
<TITLE> Examples of LDPC Program Usage </TITLE>
</HEAD><BODY>
<H1> Examples of LDPC Program Usage </H1>
<P>Below, are some command files containing examples of the use of
the <A HREF="progs.html">LDPC programs</A>, together with the output I
obtained for these examples. Output on other machines might
conceivably be slightly different, due to different round-off errors.
The <A HREF="run-examples"><TT>run-examples</TT></A> script runs all the example
scripts and compares their output with the outputs that I obtained (on
a Pentium machine).
<P><A HREF="ex-ham7b">ex-ham7b</A>,
output in <A HREF="ex-ham7b-out">ex-ham7b-out</A>
<BLOCKQUOTE>
A (7,4) Hamming code used with a BSC.
Demonstrates encoding of random messages and decoding to minimize
bit error rate by exhaustive enumeration.
</BLOCKQUOTE>
<P><A HREF="ex-ham7a">ex-ham7a</A>,
output in <A HREF="ex-ham7a-out">ex-ham7a-out</A>
<BLOCKQUOTE>
A (7,4) Hamming code used with an AWGN channel. Tested using zero messages.
Decoded by exhaustive enumeration to minimize either block or bit error rate,
and by probability propagation.
</BLOCKQUOTE>
<P><A HREF="ex-dep">ex-dep</A>,
output in <A HREF="ex-dep-out">ex-dep-out</A>
<BLOCKQUOTE>
Examples of how parity check matrices with linearly dependent rows (ie,
redundant parity checks) are handled. This is probably not of
great interest to most users.
</BLOCKQUOTE>
<P><A HREF="ex-ldpc-encode">ex-ldpc-encode</A>,
output in <A HREF="ex-ldpc-encode-out">ex-ldpc-encode-out</A>
<BLOCKQUOTE>
Encodes messages with an LDPC code using sparse, dense, and mixed
representations of the generator matrix.
</BLOCKQUOTE>
<P><A HREF="ex-ldpc36-1000a">ex-ldpc36-1000a</A>,
output in <A HREF="ex-ldpc36-1000a-out">ex-ldpc36-1000a-out</A>
<BLOCKQUOTE>
A (2000,1000) LDPC code with 3 checks per bit and 6 bits per check.
Three encoding methods are tried out, and the code is
tested on an AWGN channel at various noise levels, using random messages.
</BLOCKQUOTE>
<P><A HREF="ex-ldpc36-5000a">ex-ldpc36-5000a</A>,
output in <A HREF="ex-ldpc36-5000a-out">ex-ldpc36-5000a-out</A>
<BLOCKQUOTE>
A (10000,5000) LDPC code with 3 checks per bit and 6 bits per check.
Tested on an AWGN channel at various noise levels, using random messages.
Pipes are used to avoid creating lots of files.
</BLOCKQUOTE>
<P><A HREF="ex-ldpcvar-5000a">ex-ldpcvar-5000a</A>,
output in <A HREF="ex-ldpcvar-5000a-out">ex-ldpcvar-5000a-out</A>
<BLOCKQUOTE>
A (10000,5000) LDPC code with the number of checks per bit varying from 2 to 7.
Tested on an AWGN channel at various noise levels, using random messages.
Pipes are used to avoid creating lots of files. Performance is better than
for the code above in which the number of checks is the same for all bits.
</BLOCKQUOTE>
<P><A HREF="ex-wrong-model">ex-wrong-model</A>,
output in <A HREF="ex-wrong-model-out">ex-wrong-model-out</A>
<BLOCKQUOTE>
Tests what happens when messages are decoded using the wrong noise
model, including using the right type of model but with the wrong
noise level, and using the wrong type of model (ie, using an AWLN model
for messages transmitted through an AWGN channel, or vice versa).
</BLOCKQUOTE>
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

112
lib/ldpc/extract.c Executable file
View File

@ -0,0 +1,112 @@
/* EXTRACT.C - Extract message bits from coded blocks. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "alloc.h"
#include "blockio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *gen_file, *coded_file, *ext_file;
FILE *codef, *extf;
char *cblk;
int i;
/* Look at arguments. */
if (!(gen_file = argv[1])
|| !(coded_file = argv[2])
|| !(ext_file = argv[3])
|| argv[4])
{ usage();
}
if ((strcmp(gen_file,"-")==0) + (strcmp(coded_file,"-")==0) > 1)
{ fprintf(stderr,"Can't read more than one stream from standard input\n");
exit(1);
}
/* Read generator matrix file, up to the point of finding out which
are the message bits. */
read_gen(gen_file,1,1);
/* Open decoded file. */
codef = open_file_std(coded_file,"r");
if (codef==NULL)
{ fprintf(stderr,"Can't open coded file: %s\n",coded_file);
exit(1);
}
/* Open file to write extracted message bits to. */
extf = open_file_std(ext_file,"w");
if (extf==NULL)
{ fprintf(stderr,"Can't create file for extracted bits: %s\n",ext_file);
exit(1);
}
cblk = chk_alloc (N, sizeof *cblk);
for (;;)
{
/* Read block from coded file. */
if (blockio_read(codef,cblk,N)==EOF) break;
/* Extract message bits and write to file, followed by newline to mark
block boundary. */
for (i = M; i<N; i++)
{ putc("01"[cblk[cols[i]]],extf);
}
putc('\n',extf);
}
if (ferror(extf) || fclose(extf)!=0)
{ fprintf(stderr,"Error writing extracted data to %s\n",ext_file);
exit(1);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,
"Usage: extract gen-file decoded-file extracted-file\n");
exit(1);
}

67
lib/ldpc/github.html Executable file
View File

@ -0,0 +1,67 @@
<HTML><HEAD>
<TITLE> Github Facilities </TITLE>
</HEAD><BODY>
<H1> Github Facilities </H1>
<P>Starting with the Version of 2012-02-11, the source code repository
for this software is hosted by <A HREF="http://github.com">Github</A>,
and is located at <A
HREF="http://github.com/radfordneal/LDPC-codes">http://github.com/radfordneal/LDPC-codes</A>.
This repository includes the annotated log of changes made since the
Version of 2006-02-08.
<P>You can use the facilities at Github to obtain the source-code
repository, report bugs, and contribute to the wiki.
<H2>Obtaining the source repository, and modifying it</H2>
<P>To obtain a copy of the source-code repository, issue the following
command (in a Unix/Linux/Cygwin environment that has git installed):
<BLOCKQUOTE><PRE>
git clone git://github.com/radfordneal/LDPC-codes
</PRE></BLOCKQUOTE>
This will retrieve the current state of the software, storing it
in the directory <TT>LDPC-codes</TT>, which you should ensure does not
exist before issuing this command above.
<P>Note that if all you want to do is compile and use the current
version, you can instead download the source without development
history as described in the <A HREF="install.html">installation
instructions</A>.
<P>The <TT>LDPC-codes</TT> directory created by the <TT>git clone</TT>
command is a git repository, which can be manipulated with the various
forms of the <TT>git</TT> command, which are documented, for example,
<A HREF="http://git-scm.com/documentation">here</A>.
<P>Each stable version of the software is a separate branch of the
repository. The documentation on the most recent stable version is in
the "gh-pages" branch. The current development version is on the
"master" branch. The are other branches for each stable version that
was released.
<P>You can make local changes to your copy of the repository, and use
the modified software. If you wish, you can ask me
(radfordneal@gmail.com) to include your changes in a new release, or,
if you register as a <A HREF="http://github.com">Github</A> user, you can set
up your own fork of the software for you and other people to use.
<H2>Reporting Bugs</H2>
You can use the Github "Issues" facility to report bugs in the
software. You have to register as a <A HREF="github.com">Github</A>
user to do this (which is free). You can then go <A
HREF="https://github.com/radfordneal/LDPC-codes/issues">here</A> and
click on "New issue" to report a bug. You can also use this facility
to suggest new features or other revisions. I may not have time to
implement them, but perhaps someone else will.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

89
lib/ldpc/index.html Executable file
View File

@ -0,0 +1,89 @@
<HTML><HEAD>
<TITLE> Software for Low Density Parity Check Codes </TITLE>
</HEAD><BODY>
<H1> Software for Low Density Parity Check Codes </H1>
<P>Version in development.
<P>This collection of programs and modules, written in C, is intended
to support research and education concerning Low Density Parity Check
(LDPC) codes. (Note, however, that the copyright notice no longer
restricts use to these purposes). These error-correcting codes were
invented by Robert Gallager in the early 1960's, and re-invented and
shown to have very good performance by David MacKay and myself in the
mid-1990's. The decoding algorithm for LDPC codes is related to that
used for Turbo codes, and to probabilistic inference methods used in
other fields. Variations on LDPC and Turbo codes are currently the
best practical codes known, in terms of their ability to transmit data
at rates approaching channel capacity with very low error probability.
<p>This and past versions of the software are available <A
HREF="http://www.cs.utoronto.ca/~radford/ldpc.software.html">here</A>,
from <A HREF="http://www.cs.utoronto.ca/~radford/">Radford Neal<A>'s
web page. The source code for this software is also <A
HREF="http://github.com/radfordneal/LDPC-codes">hosted at Github</A>,
where there is a <A HREF="http://radfordneal.github.com/LDPC-codes/">copy
of these documentation pages</A> for the latest release. Github also
provides facilities for bug reporting and discussion.
<H2>Index to Documentation</H2>
<A HREF="install.html">Download and installation instructions</A>
<BLOCKQUOTE>
How to get and compile the programs and modules.
</BLOCKQUOTE>
<A HREF="github.html">Github facilities</A>
<BLOCKQUOTE>
How to get the source repository, report bugs, etc.
</BLOCKQUOTE>
<A HREF="release.html">Release notes</A>
<BLOCKQUOTE>
A log of changes made in each release of this software.
</BLOCKQUOTE>
<A HREF="progs.html">Software and program usage documentation</A>
<BLOCKQUOTE>
General documentation on the methods implemented, and details of
program usage.
</BLOCKQUOTE>
<A HREF="examples.html">Examples of program usage</A>
<BLOCKQUOTE>
Examples using simple Hamming codes, and using more interesting LDPC codes.
</BLOCKQUOTE>
<A HREF="modify.html">How to modify the programs</A>
<BLOCKQUOTE>
Notes on how to add new channel types, new decoding methods, etc.
</BLOCKQUOTE>
<A HREF="modules.html">Module documentation</A>
<BLOCKQUOTE>
Modules used by the programs for modulo-2 matrix
operations and random number generation.
</BLOCKQUOTE>
<A HREF="refs.html">References</A>
<BLOCKQUOTE>
Classic and more recent papers on LDPC codes and related topics.
</BLOCKQUOTE>
<H2> <A NAME="copyright">Copyright and Lack of Warranty</A> </H2>
<P> Except as otherwise specified, all of this software and
documentation is copyright &copy; 1995-2012 by Radford M. Neal.
<P>Permission is granted for anyone to copy, use, modify, and distribute
these programs and accompanying documents for any purpose, provided
this copyright notice is retained and prominently displayed, and note
is made of any changes made to these programs. These programs and
documents are distributed without any warranty, express or implied.
As the programs were written for research purposes only, they have not
been tested to the degree that would be advisable in any important
application. All use of these programs is entirely at the user's own
risk.
<P>Some routines in the module rand.c are taken from the GNU C Library,
and are copyrighted as described there and in the file LGPL.
</BODY></HTML>

82
lib/ldpc/install.html Executable file
View File

@ -0,0 +1,82 @@
<HTML><HEAD>
<TITLE> Installing the LDPC Software </TITLE>
</HEAD><BODY>
<H1> Installing the LDPC Software </H1>
The LDPC software is written in C, and may well work with any C
compiler, though it has been tested only with gcc, in Unix and Linux
environments, and in the <A HREF="http://www.cygwin.com">Cygwin</A>
Unix-like environment that runs under Microsoft Windows. The
installation instructions below assume that you are using a Unix-like
system.
<P>All the software, including the documentation you are viewing here,
is contained in a tar file, which you can download by clicking one
of the options below:
<BLOCKQUOTE>
<A HREF="http://www.cs.utoronto.ca/~radford/ftp/LDPC-yyyy-mm-dd/LDPC-yyyy-mm-dd.tar">Tar
file of LDPC software</A> (0.9 Megabytes)<BR>
<A HREF="http://www.cs.utoronto.ca/~radford/ftp/LDPC-yyyy-mm-dd/LDPC-yyyy-mm-dd.tar.gz">Gzipped
tar file of LDPC software</A> (0.4 Megabytes)
</BLOCKQUOTE>
<P>Once you obtain the tar file (and uncompress it with gunzip if
necessary), you should extract the files with the following Unix command:
<BLOCKQUOTE><PRE>
tar xf LDPC-yyyy-mm-dd.tar
</PRE></BLOCKQUOTE>
This will create a source directory called <TT>LDPC-yyyy-mm-dd</TT>, and place
all the source, documentation, and other files in this directory.
<P>If you prefer for this directory to be called something else,
rename it <B>now</B>, before compiling the programs, since the file
<TT>randfile</TT> in this directory, containing natural random numbers,
is accessed according to its path when the programs were compiled.
<P>Once the tar command above has finished, you should change into the
newly-created directory, and type
<BLOCKQUOTE><PRE>
make
</PRE></BLOCKQUOTE>
If all goes well, this should compile all the programs (except for some
test programs, which can be compiled with <TT>make test</TT>). You
may want to edit the file <TT>Makefile</TT> before running <TT>make</TT>
in order to change compilation options, such as the optimization level.
<P>You can run the programs from this source directory, or you can copy
them to some other directory by running the <TT>LDPC-install</TT>
shell file. For instance, to install them in a bin directory in your
home directory, do the following:
<BLOCKQUOTE><PRE>
./LDPC-install $HOME/bin
</PRE></BLOCKQUOTE>
<P>The source directory contains a copy of all the HTML files
documenting the software, such as the one you are reading now, with
the file <TT>index.html</TT> being the starting point. It is best to
use this local copy when referring to the documentation, rather than
get it off the web, since that is faster and also insures that the
documentation is for the version that you are using. Just tell your
browser to open the URL
<BLOCKQUOTE><PRE>
file:<I>path-to-software</I>/index.html
</PRE></BLOCKQUOTE>
where <TT><I>path-to-software</I></TT> is the full path (starting with "/")
to the directory where you've put the software.
<P>The command
<BLOCKQUOTE><PRE>
make clean
</PRE></BLOCKQUOTE>
will remove all the compiled programs, as well as the files created when
the <A HREF="examples.html">examples</A> are run, and <TT>core</TT>, if it
exists.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

110
lib/ldpc/intio.c Executable file
View File

@ -0,0 +1,110 @@
/* INTIO.C - Routines to read and write integers one byte at a time. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdlib.h>
#include <stdio.h>
#include "intio.h"
/* READ AN INTEGER ONE BYTE AT A TIME. Four bytes are read, ordered from
low to high order. These are considered to represent a signed integer,
in two's complement form. The value returned is this integer, converted
to whatever a C "int" is. The conversion should work as long as an "int"
is at least four bytes, even if it's not in two's complement representation
(except for the largest two's complement negative integer).
If an error or eof is encountered, zero is returned. The caller can
check for these events using feof and ferror.
The file read from should have been opened as "binary".
*/
int intio_read
( FILE *f /* File to read from */
)
{
unsigned char b[4];
int top;
int i;
for (i = 0; i<4; i++)
{ if (fread(&b[i],1,1,f) != 1) return 0;
}
top = b[3]>127 ? (int)b[3] - 256 : b[3];
return (top<<24) + (b[2]<<16) + (b[1]<<8) + b[0];
}
/* WRITE AN INTEGER ONE BYTE AT A TIME. Four bytes are written, ordered from
low to high order. These are considered to represent a signed integer,
in two's complement form. This should work as long as the integer passed
can be represented in four bytes, even if a C "int" is longer than this.
The file written to should have been opened as "binary".
*/
void intio_write
( FILE *f, /* File to write to */
int v /* Value to write to file */
)
{
unsigned char b;
int i;
for (i = 0; i<3; i++)
{ b = v&0xff;
fwrite(&b,1,1,f);
v >>= 8;
}
b = v>0 ? v : v+256;
fwrite(&b,1,1,f);
}
/* TEST PROGRAM. */
#ifdef TEST_INTIO
main(void)
{
FILE *f;
f = fopen("test","wb");
intio_write(f,334);
intio_write(f,-40000);
intio_write(f,0x8fffffff);
intio_write(f,-0x8fffffff);
fclose(f);
f = fopen("test","rb");
if (intio_read(f)!=334
|| intio_read(f)!=-40000
|| intio_read(f)!=0x8fffffff
|| intio_read(f)!=-0x8fffffff)
{ fprintf(stderr,"got back bad data\n");
exit(1);
}
if (intio_read(f)!=0 || !feof(f) || ferror(f))
{ fprintf(stderr,"eof not handled correctly\n");
exit(1);
}
fclose(f);
fprintf(stderr,"OK\n");
exit(0);
}
#endif

17
lib/ldpc/intio.h Executable file
View File

@ -0,0 +1,17 @@
/* INTIO.H - Interface for reading and writing integers one byte at a time. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
int intio_read (FILE *); /* Read an integer */
void intio_write (FILE *, int); /* Write an integer */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
#!/bin/sh
# this script characterizes a single code over a narrow range of Eb/No
# note relationship between noise standard deviation, sigma, and Eb/No:
# Ps/Pn = 1/(2*sigma^2)
# Ps/Pn = (Es/tau_s)/(W*No)=(Eb/R)/(tau_s*W*No)=(Eb/No)*(1/(tau_s*R*W))
# If pulses are sent at Nyquist signaling limit, then: 1/tau_s=2*W -> tau_s*W=1/2
# so Eb/No=(1/2*sigma^2)*(2*R) =
set -e # Stop if an error occurs
set -v # Echo commands as they are read
#make-ldpc ldpc-144-72.pchk 80 160 12 evenboth 6x3/4x4 no4cycle
#make-ldpc ldpc-144-72.pchk 72 144 33 evenboth 6x3/4x4 no4cycle
#make-ldpc ldpc-144-72.pchk 72 144 8 evenboth 3 no4cycle
cp ldpc-144-72-6x3-4x4-sf1.pchk ldpc-144-72.pchk
make-gen ldpc-144-72.pchk ldpc-144-72.gen dense
rand-src ldpc-144-72.src 1 72x1000000
encode ldpc-144-72.pchk ldpc-144-72.gen ldpc-144-72.src \
ldpc-144-72.enc
# NOISE STANDARD DEVIATION 0.75, Eb/N0 = 2.50 dB
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.75
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.75\
prprp 250
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \
ldpc-144-72.src
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.80
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.80\
prprp 250
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \
ldpc-144-72.src
# NOISE STANDARD DEVIATION 0.85, Eb/N0 = 1.41 dB
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.85
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.85\
prprp 250
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \
ldpc-144-72.src
# NOISE STANDARD DEVIATION 0.90, Eb/N0 = 0.92 dB
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.90
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.90\
prprp 250
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \
ldpc-144-72.src
# NOISE STANDARD DEVIATION 0.95, Eb/N0 = 0.45 dB
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.95
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.95\
prprp 250
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \
ldpc-144-72.src

Binary file not shown.

View File

@ -0,0 +1,34 @@
#!/bin/sh
# Example of a (144,72) LDPC code with 3 checks per bit and 6 bits per
# check, tested on Additive White Gaussian Noise channels with noise standard
# deviations varying from 0.80 to 0.95.
#
# Testing is done by transmitting random messages, which is safer (though
# slower) than using only zero messages. Decoding is done using a maximum
# of 250 iterations of probability propagation.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
for i in `seq 1 1000`;
do
seed=$i
echo seed $seed
make-ldpc ldpc-144-72.pchk 72 144 $seed evenboth 6x3/4x4 no4cycle
make-gen ldpc-144-72.pchk ldpc-144-72.gen dense
rand-src ldpc-144-72.src 2 72x100000
encode ldpc-144-72.pchk ldpc-144-72.gen ldpc-144-72.src \
ldpc-144-72.enc
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.80
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.80\
prprp 50
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \
ldpc-144-72.src
done

View File

@ -0,0 +1,85 @@
{\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww21500\viewh8400\viewkind0
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
\f0\fs30 \cf0 \CocoaLigature0 Stevens-MacBook-Air:LDPC-codes-master sfranke$ ldpc-144-72\
\
#make-ldpc ldpc-144-72.pchk 80 160 12 evenboth 6x3/4x4 no4cycle\
#make-ldpc ldpc-144-72.pchk 72 144 33 evenboth 6x3/4x4 no4cycle\
#make-ldpc ldpc-144-72.pchk 72 144 8 evenboth 3 no4cycle\
cp ldpc-144-72-6x3-4x4-sf1.pchk ldpc-144-72.pchk\
make-gen ldpc-144-72.pchk ldpc-144-72.gen dense\
Number of 1s per check in Inv(A) X B is 29.4\
rand-src ldpc-144-72.src 1 72x1000000\
encode ldpc-144-72.pchk ldpc-144-72.gen ldpc-144-72.src \\\
ldpc-144-72.enc\
Encoded 1000000 blocks, source block size 72, encoded block size 144\
\
# NOISE STANDARD DEVIATION 0.75, Eb/N0 = 2.50 dB\
\
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.75\
Transmitted 144000000 bits\
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.75\\\
prprp 250\
Decoded 1000000 blocks, 912331 valid. Average 28.0 iterations, 9% bit changes\
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \\\
ldpc-144-72.src \
Block counts: tot 1000000, with chk errs 87669, with src errs 87561, both 87506\
Total good frames: 912276 Total undetected errors: 55\
Bit error rate (on message bits only): 8.969e-03\
\
# NOISE STANDARD DEVIATION 0.80, Eb/N0 = 1.94 dB\
\
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.80\
Transmitted 144000000 bits\
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.80\\\
prprp 250\
Decoded 1000000 blocks, 747691 valid. Average 69.4 iterations, 10% bit changes\
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \\\
ldpc-144-72.src \
Block counts: tot 1000000, with chk errs 252309, with src errs 251953, both 251862\
Total good frames: 747600 Total undetected errors: 91\
Bit error rate (on message bits only): 2.627e-02\
\
# NOISE STANDARD DEVIATION 0.85, Eb/N0 = 1.41 dB\
\
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.85\
Transmitted 144000000 bits\
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.85\\\
prprp 250\
Decoded 1000000 blocks, 513359 valid. Average 126.8 iterations, 10% bit changes\
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \\\
ldpc-144-72.src \
Block counts: tot 1000000, with chk errs 486641, with src errs 485965, both 485838\
Total good frames: 513232 Total undetected errors: 127\
Bit error rate (on message bits only): 5.295e-02\
\
# NOISE STANDARD DEVIATION 0.90, Eb/N0 = 0.92 dB\
\
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.90\
Transmitted 144000000 bits\
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.90\\\
prprp 250\
Decoded 1000000 blocks, 287970 valid. Average 181.4 iterations, 9% bit changes\
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \\\
ldpc-144-72.src \
Block counts: tot 1000000, with chk errs 712030, with src errs 711238, both 711123\
Total good frames: 287855 Total undetected errors: 115\
Bit error rate (on message bits only): 8.316e-02\
\
# NOISE STANDARD DEVIATION 0.95, Eb/N0 = 0.45 dB\
\
transmit ldpc-144-72.enc ldpc-144-72.rec 1 awgn 0.95\
Transmitted 144000000 bits\
decode ldpc-144-72.pchk ldpc-144-72.rec ldpc-144-72.dec awgn 0.95\\\
prprp 250\
Decoded 1000000 blocks, 130537 valid. Average 219.2 iterations, 8% bit changes\
verify ldpc-144-72.pchk ldpc-144-72.dec ldpc-144-72.gen \\\
ldpc-144-72.src\
Block counts: tot 1000000, with chk errs 869463, with src errs 868761, both 868683\
Total good frames: 130459 Total undetected errors: 78\
Bit error rate (on message bits only): 1.110e-01\
Stevens-MacBook-Air:LDPC-codes-master sfranke$ \
}

File diff suppressed because it is too large Load Diff

350
lib/ldpc/make-gen.c Executable file
View File

@ -0,0 +1,350 @@
/* MAKE-GEN.C - Make generator matrix from parity-check matrix. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "alloc.h"
#include "intio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
typedef enum { Sparse, Dense, Mixed } make_method; /* Ways of making it */
void make_dense_mixed (FILE *, make_method, char *); /* Procs to make it */
void make_sparse (FILE *, mod2sparse_strategy, int, int);
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *pchk_file, *gen_file, *other_gen_file;
mod2sparse_strategy strategy;
int abandon_when, abandon_number;
make_method method;
char *meth;
char junk;
FILE *f;
/* Look at arguments. */
if (!(pchk_file = argv[1])
|| !(gen_file = argv[2])
|| !(meth = argv[3]))
{ usage();
}
if (strcmp(meth,"sparse")==0)
{ method = Sparse;
strategy = Mod2sparse_minprod;
abandon_number = 0;
if (argv[4])
{ if (strcmp(argv[4],"first")==0) strategy = Mod2sparse_first;
else if (strcmp(argv[4],"mincol")==0) strategy = Mod2sparse_mincol;
else if (strcmp(argv[4],"minprod")==0) strategy = Mod2sparse_minprod;
else
{ usage();
}
if (argv[5])
{ if (sscanf(argv[5],"%d%c",&abandon_number,&junk)!=1 || abandon_number<=0
|| !argv[6]
|| sscanf(argv[6],"%d%c",&abandon_when,&junk)!=1 || abandon_when<=0
|| argv[7])
{ usage();
}
}
}
}
else if (strcmp(meth,"dense")==0)
{ method = Dense;
other_gen_file = argv[4];
if (other_gen_file && argv[5])
{ usage();
}
}
else if (strcmp(meth,"mixed")==0)
{ method = Mixed;
other_gen_file = argv[4];
if (other_gen_file && argv[5])
{ usage();
}
}
else
{ usage();
}
/* Read parity check matrix. */
read_pchk(pchk_file);
if (N<=M)
{ fprintf(stderr,
"Can't encode if number of bits (%d) isn't greater than number of checks (%d)\n",N,M);
exit(1);
}
/* Create generator matrix file. */
f = open_file_std(gen_file,"wb");
if (f==NULL)
{ fprintf(stderr,"Can't create generator matrix file: %s\n",gen_file);
exit(1);
}
/* Allocate space for row and column permutations. */
cols = chk_alloc (N, sizeof *cols);
rows = chk_alloc (M, sizeof *rows);
/* Create generator matrix with specified method. */
switch (method)
{ case Sparse:
{ make_sparse(f,strategy,abandon_number,abandon_when);
break;
}
case Dense: case Mixed:
{ make_dense_mixed(f,method,other_gen_file);
break;
}
default: abort();
}
/* Check for error writing file. */
if (ferror(f) || fclose(f)!=0)
{ fprintf(stderr,"Error writing to generator matrix file\n");
exit(1);
}
return 0;
}
/* MAKE DENSE OR MIXED REPRESENTATION OF GENERATOR MATRIX. */
void make_dense_mixed
( FILE *f,
make_method method,
char *other_gen_file
)
{
mod2dense *DH, *A, *A2, *AI, *B;
int i, j, c, c2, n;
int *rows_inv;
DH = mod2dense_allocate(M,N);
AI = mod2dense_allocate(M,M);
B = mod2dense_allocate(M,N-M);
G = mod2dense_allocate(M,N-M);
mod2sparse_to_dense(H,DH);
/* If another generator matrix was specified, invert using the set of
columns it specifies. */
if (other_gen_file)
{
read_gen(other_gen_file,1,0);
A = mod2dense_allocate(M,M);
mod2dense_copycols(DH,A,cols);
if (!mod2dense_invert(A,AI))
{ fprintf(stderr,
"Couldn't invert sub-matrix with column order given in other file\n");
exit(1);
}
mod2dense_copycols(DH,B,cols+M);
}
/* If no other generator matrix was specified, invert using whatever
selection of rows/columns is needed to get a non-singular sub-matrix. */
if (!other_gen_file)
{
A = mod2dense_allocate(M,N);
A2 = mod2dense_allocate(M,N);
n = mod2dense_invert_selected(DH,A2,rows,cols);
mod2sparse_to_dense(H,DH); /* DH was destroyed by invert_selected */
if (n>0)
{ fprintf(stderr,"Note: Parity check matrix has %d redundant checks\n",n);
}
rows_inv = chk_alloc (M, sizeof *rows_inv);
for (i = 0; i<M; i++)
{ rows_inv[rows[i]] = i;
}
mod2dense_copyrows(A2,A,rows);
mod2dense_copycols(A,A2,cols);
mod2dense_copycols(A2,AI,rows_inv);
mod2dense_copycols(DH,B,cols+M);
}
/* Form final generator matrix. */
if (method==Dense)
{ mod2dense_multiply(AI,B,G);
}
else if (method==Mixed)
{ G = AI;
}
else
{ abort();
}
/* Compute and print number of 1s. */
if (method==Dense)
{ c = 0;
for (i = 0; i<M; i++)
{ for (j = 0; j<N-M; j++)
{ c += mod2dense_get(G,i,j);
}
}
fprintf(stderr,
"Number of 1s per check in Inv(A) X B is %.1f\n", (double)c/M);
}
if (method==Mixed)
{ c = 0;
for (i = 0; i<M; i++)
{ for (j = 0; j<M; j++)
{ c += mod2dense_get(G,i,j);
}
}
c2 = 0;
for (i = M; i<N; i++)
{ c2 += mod2sparse_count_col(H,cols[i]);
}
fprintf(stderr,
"Number of 1s per check in Inv(A) is %.1f, in B is %.1f, total is %.1f\n",
(double)c/M, (double)c2/M, (double)(c+c2)/M);
}
/* Write the represention of the generator matrix to the file. */
intio_write(f,('G'<<8)+0x80);
if (method==Dense)
{ fwrite ("d", 1, 1, f);
}
if (method==Mixed)
{ fwrite ("m", 1, 1, f);
}
intio_write(f,M);
intio_write(f,N);
for (i = 0; i<N; i++)
{ intio_write(f,cols[i]);
}
mod2dense_write (f, G);
}
/* MAKE SPARSE REPRESENTATION OF GENERATOR MATRIX. */
void make_sparse
( FILE *f,
mod2sparse_strategy strategy,
int abandon_number,
int abandon_when
)
{
int n, cL, cU, cB;
int i;
/* Find LU decomposition. */
L = mod2sparse_allocate(M,M);
U = mod2sparse_allocate(M,N);
n = mod2sparse_decomp(H,M,L,U,rows,cols,strategy,abandon_number,abandon_when);
if (n!=0 && abandon_number==0)
{ fprintf(stderr,"Note: Parity check matrix has %d redundant checks\n",n);
}
if (n!=0 && abandon_number>0)
{ fprintf(stderr,
"Note: Have %d dependent columns, but this could be due to abandonment.\n",n);
fprintf(stderr,
" Try again with lower abandonment number.\n");
exit(1);
}
/* Compute and print number of 1s. */
cL = cU = cB = 0;
for (i = 0; i<M; i++) cL += mod2sparse_count_row(L,i);
for (i = 0; i<M; i++) cU += mod2sparse_count_row(U,i);
for (i = M; i<N; i++) cB += mod2sparse_count_col(H,cols[i]);
fprintf(stderr,
"Number of 1s per check in L is %.1f, U is %.1f, B is %.1f, total is %.1f\n",
(double)cU/M, (double)cL/M, (double)cB/M, (double)(cL+cU+cB)/M);
/* Write it all to the generator matrix file. */
intio_write(f,('G'<<8)+0x80);
fwrite ("s", 1, 1, f);
intio_write(f,M);
intio_write(f,N);
for (i = 0; i<N; i++)
{ intio_write(f,cols[i]);
}
for (i = 0; i<M; i++)
{ intio_write(f,rows[i]);
}
mod2sparse_write (f, L);
mod2sparse_write (f, U);
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf (stderr,
"Usage: make-gen pchk-file gen-file method\n");
fprintf (stderr,
"Method: sparse [ \"first\" | \"mincol\" | \"minprod\" ] [ abandon_num abandon_when ]\n");
fprintf (stderr,
" or: dense [ other-gen-file ]\n");
fprintf (stderr,
" or: mixed [ other-gen-file ]\n");
exit(1);
}

415
lib/ldpc/make-ldpc.c Executable file
View File

@ -0,0 +1,415 @@
/* MAKE-LDPC.C - Make a Low Density Parity Check code's parity check matrix. */
/* Copyright (c) 1995-2012 by Radford M. Neal and Peter Junteng Liu.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "rand.h"
#include "alloc.h"
#include "intio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
#include "distrib.h"
/* METHODS FOR CONSTRUCTING CODES. */
typedef enum
{ Evencol, /* Uniform number of bits per column, with number specified */
Evenboth /* Uniform (as possible) over both columns and rows */
} make_method;
void make_ldpc (int, make_method, distrib *, int);
int *column_partition (distrib *, int);
void usage (void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
make_method method;
char *file, **meth;
int seed, no4cycle;
distrib *d;
char junk;
FILE *f;
/* Look at initial arguments. */
if (!(file = argv[1])
|| !argv[2] || sscanf(argv[2],"%d%c",&M,&junk)!=1 || M<=0
|| !argv[3] || sscanf(argv[3],"%d%c",&N,&junk)!=1 || N<=0
|| !argv[4] || sscanf(argv[4],"%d%c",&seed,&junk)!=1)
{ usage();
}
/* Look at the arguments specifying the method for producing the code. */
meth = argv+5;
if (!meth[0]) usage();
no4cycle = 0;
if (strcmp(meth[0],"evencol")==0 || strcmp(meth[0],"evenboth")==0)
{ method = strcmp(meth[0],"evencol")==0 ? Evencol : Evenboth;
if (!meth[1])
{ usage();
}
d = distrib_create(meth[1]);
if (d==0)
{ usage();
}
if (meth[2])
{ if (strcmp(meth[2],"no4cycle")==0)
{ no4cycle = 1;
if (meth[3])
{ usage();
}
}
else
{ usage();
}
}
}
else
{ usage();
}
/* Check for some problems. */
if (distrib_max(d)>M)
{ fprintf(stderr,
"At least one checks per bit (%d) is greater than total checks (%d)\n",
distrib_max(d), M);
exit(1);
}
if (distrib_max(d)==M && N>1 && no4cycle)
{ fprintf(stderr,
"Can't eliminate cycles of length four with this many checks per bit\n");
exit(1);
}
/* Make the parity check matrix. */
make_ldpc(seed,method,d,no4cycle);
/* Write out the parity check matrix. */
f = open_file_std(file,"wb");
if (f==NULL)
{ fprintf(stderr,"Can't create parity check file: %s\n",file);
exit(1);
}
intio_write(f,('P'<<8)+0x80);
if (ferror(f) || !mod2sparse_write(f,H) || fclose(f)!=0)
{ fprintf(stderr,"Error writing to parity check file %s\n",file);
exit(1);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: make-ldpc pchk-file n-checks n-bits seed method\n");
fprintf(stderr,"Method: evencol checks-per-col [ \"no4cycle\" ]\n");
fprintf(stderr," or: evencol checks-distribution [ \"no4cycle\" ]\n");
fprintf(stderr," or: evenboth checks-per-col [ \"no4cycle\" ]\n");
fprintf(stderr," or: evenboth checks-distribution [ \"no4cycle\" ]\n");
exit(1);
}
/* CREATE A SPARSE PARITY-CHECK MATRIX. Of size M by N, stored in H. */
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");
}
}
}
/* PARTITION THE COLUMNS ACCORDING TO THE SPECIFIED PROPORTIONS. It
may not be possible to do this exactly. Returns a pointer to an
array of integers containing the numbers of columns corresponding
to the entries in the distribution passed. */
int *column_partition
( distrib *d, /* List of proportions and number of check-bits */
int n /* Total number of columns to partition */
)
{
double *trunc;
int *part;
int cur, used;
int i, j;
trunc = chk_alloc (distrib_size(d), sizeof(double));
part = chk_alloc (distrib_size(d), sizeof(int));
used = 0;
for (i = 0; i<distrib_size(d); i++)
{ cur = floor(distrib_prop(d,i)*n);
part[i] = cur;
trunc[i] = distrib_prop(d,i)*n - cur;
used += cur;
}
if (used>n)
{ abort();
}
while (used<n)
{ cur = 0;
for (j = 1; j<distrib_size(d); j++)
{ if (trunc[j]>trunc[cur])
{ cur = j;
}
}
part[cur] += 1;
used += 1;
trunc[cur] = -1;
}
free(trunc);
return part;
}

93
lib/ldpc/make-pchk.c Executable file
View File

@ -0,0 +1,93 @@
/* MAKE-PCHK.C - Make a parity check matrix explicitly. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "alloc.h"
#include "intio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char **bit_specs;
char *file;
FILE *f;
int i, j, k;
char junk;
if (!(file = argv[1])
|| !argv[2] || sscanf(argv[2],"%d%c",&M,&junk)!=1 || M<=0
|| !argv[3] || sscanf(argv[3],"%d%c",&N,&junk)!=1 || N<=0)
{ usage();
}
bit_specs = argv+4;
if (bit_specs[0]==0)
{ usage();
}
H = mod2sparse_allocate(M,N);
for (k = 0; bit_specs[k]!=0; k++)
{ if (sscanf(bit_specs[k],"%d:%d%c",&i,&j,&junk)!=2 || i<0 || j<0)
{ usage();
}
if (i>=M || j>=N)
{ fprintf(stderr,"Bit %d:%d is out of range\n",i,j);
exit(1);
}
mod2sparse_insert(H,i,j);
}
f = open_file_std(file,"wb");
if (f==NULL)
{ fprintf(stderr,"Can't create parity check file: %s\n",file);
exit(1);
}
intio_write(f,('P'<<8)+0x80);
if (ferror(f) || !mod2sparse_write(f,H) || fclose(f)!=0)
{ fprintf(stderr,"Error writing to parity check file %s\n",file);
exit(1);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: make-pchk pchk-file n-checks n-bits row:col ...\n");
exit(1);
}

9
lib/ldpc/mod2convert-test-out Executable file
View File

@ -0,0 +1,9 @@
Creating sparse matrix.
Converting from sparse to dense.
Converting back to dense again.
Testing for equality of two sparse matrices: OK.
Converting to dense once again.
Testing for equality of two dense matrices: OK.
DONE WITH TESTS.

80
lib/ldpc/mod2convert-test.c Executable file
View File

@ -0,0 +1,80 @@
/* MOD2CONVERT-TEST. C - Program to test mod2convert module. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* Correct output for this program is saved in the file mod2convert-test-out */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mod2dense.h"
#include "mod2sparse.h"
#include "mod2convert.h"
#include "rand.h"
#define Rows 40 /* Dimensions of matrix to use in test */
#define Cols 13
#define N 100 /* Number of bits to set in test matrix (some may be
duplicates, leading to fewer 1's in matrix */
main(void)
{
mod2sparse *sm1, *sm2;
mod2dense *dm1, *dm2;
int i;
sm1 = mod2sparse_allocate(Rows,Cols);
sm2 = mod2sparse_allocate(Rows,Cols);
dm1 = mod2dense_allocate(Rows,Cols);
dm2 = mod2dense_allocate(Rows,Cols);
printf("\nCreating sparse matrix.\n");
fflush(stdout);
for (i = 0; i<N; i++)
{ mod2sparse_insert(sm1,rand_int(Rows),rand_int(Cols));
}
printf("Converting from sparse to dense.\n");
fflush(stdout);
mod2sparse_to_dense(sm1,dm1);
printf("Converting back to dense again.\n");
fflush(stdout);
mod2dense_to_sparse(dm1,sm2);
printf("Testing for equality of two sparse matrices: %s.\n",
mod2sparse_equal(sm1,sm2) ? "OK" : "NOT OK");
fflush(stdout);
printf("Converting to dense once again.\n");
fflush(stdout);
mod2sparse_to_dense(sm2,dm2);
printf("Testing for equality of two dense matrices: %s.\n",
mod2dense_equal(dm1,dm2) ? "OK" : "NOT OK");
fflush(stdout);
printf("\nDONE WITH TESTS.\n");
exit(0);
}

83
lib/ldpc/mod2convert.c Executable file
View File

@ -0,0 +1,83 @@
/* MOD2CONVERT.C - Routines converting between sparse and dense mod2 matrices.*/
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* NOTE: See mod2convert.html for documentation on these procedures. */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mod2dense.h"
#include "mod2sparse.h"
#include "mod2convert.h"
/* CONVERT A MOD2 MATRIX FROM SPARSE TO DENSE FORM. */
void mod2sparse_to_dense
( mod2sparse *m, /* Sparse matrix to convert */
mod2dense *r /* Place to store result */
)
{
mod2entry *e;
int i;
if (mod2sparse_rows(m)>mod2dense_rows(r)
|| mod2sparse_cols(m)>mod2dense_cols(r))
{ fprintf(stderr,
"mod2sparse_to_dense: Dimension of result matrix is less than source\n");
exit(1);
}
mod2dense_clear(r);
for (i = 0; i<mod2sparse_rows(m); i++)
{ e = mod2sparse_first_in_row(m,i);
while (!mod2sparse_at_end(e))
{ mod2dense_set(r,i,mod2sparse_col(e),1);
e = mod2sparse_next_in_row(e);
}
}
}
/* CONVERT A MOD2 MATRIX FROM DENSE TO SPARSE FORM. */
void mod2dense_to_sparse
( mod2dense *m, /* Dense matrix to convert */
mod2sparse *r /* Place to store result */
)
{
int i, j;
if (mod2dense_rows(m)>mod2sparse_rows(r)
|| mod2dense_cols(m)>mod2sparse_cols(r))
{ fprintf(stderr,
"mod2dense_to_sparse: Dimension of result matrix is less than source\n");
exit(1);
}
mod2sparse_clear(r);
for (i = 0; i<mod2dense_rows(m); i++)
{ for (j = 0; j<mod2dense_cols(m); j++)
{ if (mod2dense_get(m,i,j))
{ mod2sparse_insert(r,i,j);
}
}
}
}

18
lib/ldpc/mod2convert.h Executable file
View File

@ -0,0 +1,18 @@
/* MOD2CONVERT.H - Routines converting between sparse and dense mod2 matrices.*/
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
void mod2sparse_to_dense (mod2sparse *, mod2dense *);
void mod2dense_to_sparse (mod2dense *, mod2sparse *);

51
lib/ldpc/mod2convert.html Executable file
View File

@ -0,0 +1,51 @@
<HTML><HEAD>
<TITLE> Modulo-2 Matrix Sparse/Dense Conversion </TITLE>
</HEAD><BODY>
<H1> Modulo-2 Matrix Sparse/Dense Conversion </H1>
<P>The routines below convert modulo-2 matrices between the form used by
the <A HREF="mod2dense.html">routines for dense modulo-2 matrices</A>
and the form used by the <A HREF="mod2dense.html">routines for sparse
modulo-2 matrices</A>.
<P><B>Header files required</B>:
<TT>mod2sparse.h mod2dense.h mod2convert.h</TT>
<P><A NAME="sparse_to_dense"><HR><B>mod2sparse_to_dense</B>:
Convert a modulo-2 matrix from sparse to dense form.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_to_dense
( mod2sparse *m, /* Sparse matrix to convert */
mod2dense *r /* Place to store result */
)
</PRE></BLOCKQUOTE>
The dense matrix, r, must already have been allocated, and must have at
least as many rows and columns as m, the sparse matrix to be converted.
<P><A NAME="dense_to_sparse"><HR><B>mod2dense_to_sparse</B>:
Convert a modulo-2 matrix from dense to sparse form.</A>
<BLOCKQUOTE><PRE>
void mod2dense_to_sparse
( mod2dense *m, /* Dense matrix to convert */
mod2sparse *r /* Place to store result */
)
</PRE></BLOCKQUOTE>
The sparse matrix, r, must already have been allocated, and must have at
least as many rows and columns as m, the dense matrix to be converted.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

699
lib/ldpc/mod2dense-test-out Executable file
View File

@ -0,0 +1,699 @@
PART 1:
Matrix m1:
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
Matrix m2, as read from file. Should be same as m1 above.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
Test of equality of m1 & m2 (should be 1): 1
Matrix m3, copied from m1 above.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
Test of equality of m1 & m3 (should be 1): 1
Matrix m3 again, should now be all zeros.
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Test of equality of m1 & m3 (should be 0): 0
PART 2:
Transpose of m1.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
PART 3:
Matrix s0.
0 0 0 0 0 0 0
0 0 0 1 1 0 0
1 0 0 0 0 0 0
0 1 0 0 0 0 0
0 0 0 0 0 0 0
Matrix s1.
0 0 0 0 0 0 0
0 0 0 1 0 1 0
0 0 0 0 0 0 0
1 1 0 0 0 0 1
0 0 0 0 0 0 0
Matrix s2.
1 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 1 1 1
0 0 0 0
Sum of s0 and s1.
0 0 0 0 0 0 0
0 0 0 0 1 1 0
1 0 0 0 0 0 0
1 0 0 0 0 0 1
0 0 0 0 0 0 0
Product of s1 and s2.
0 0 0 0
0 1 1 1
0 0 0 0
1 1 0 0
0 0 0 0
Above matrix with (1,2) cleared.
0 0 0 0
0 1 0 1
0 0 0 0
1 1 0 0
0 0 0 0
PART 4:
Matrix s1.
0 0 0 1 0
0 1 0 0 1
1 0 0 0 0
0 1 1 0 0
1 0 1 0 0
Matrix s3, the inverse of s1 (return code 1).
0 0 1 0 0
0 0 1 1 1
0 0 1 0 1
1 0 0 0 0
0 1 1 1 1
Original matrix times inverse (should be identity).
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
Inverse times original matrix (should be identity).
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
Inverse of inverse (should be same as original s1).
0 0 0 1 0
0 1 0 0 1
1 0 0 0 0
0 1 1 0 0
1 0 1 0 0
Test of equality with original (should be 1): 1
Matrix s1.
0 0 0 0 1 0 0
0 1 0 0 0 0 1
1 0 0 0 0 0 0
0 1 1 0 0 0 0
1 0 1 0 0 0 0
Matrix s3, from invert_selected applied to s1 (return code 0).
0 0 0 0 1 0 0
1 0 1 0 0 0 1
1 0 0 0 0 0 0
1 0 0 0 0 0 1
1 1 1 0 0 0 1
row ordering returned: 0 1 2 3 4
column ordering returned: 4 1 0 2 6 5 3
Columns extracted in order from original matrix.
1 0 0 0 0
0 1 0 0 1
0 0 1 0 0
0 1 0 1 0
0 0 1 1 0
Inverse of above calculated using mod2dense_inverse (return code 1)
1 0 0 0 0
0 0 1 1 1
0 0 1 0 0
0 0 1 0 1
0 1 1 1 1
Columns extracted in order from s3 (should also be inverse of above).
1 0 0 0 0
0 0 1 1 1
0 0 1 0 0
0 0 1 0 1
0 1 1 1 1
Matrix s1.
1 1 0 0 0 0 0
0 1 1 0 0 0 0
1 0 1 0 0 0 0
0 0 0 1 1 0 0
0 0 0 0 0 0 0
Matrix s3, from invert_selected applied to s1 (return code 2).
1 1 0 0 0 0 0
0 1 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 0 0 0
row ordering returned: 0 1 3 4 2
column ordering returned: 0 1 3 2 4 5 6
Matrix s4, from copying rows in order from s3.
1 1 0 0 0 0 0
0 1 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
PART 5:
Matrix s1.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1
0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1
Matrix s3, the inverse of s1 (return code 1).
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 1 1 0 1 1 0 0 0 0 1 1 0 1 0 0 1 0 0 0 0 0 0 1 0 0 1 1
0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0
0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
1 0 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 1 0 0 1 1 0 0 0 0 1 1 0 1 0 0 1 0 0 0 0 0 0 1 0 0 1 1
0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
Original matrix times inverse (should be identity).
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
Inverse times original matrix (should be identity).
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
Inverse of inverse (should be same as original s1).
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1
0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1
Test of equality with original (should be 1): 1
PART 6:
Matrix s1.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Result of forcibly inverting s1 (needed to alter 7 elements).
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Altered elements at these indexes:
3 3
7 7
15 15
21 21
23 23
29 29
32 12
Inverse of inverse of altered matrix.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
DONE WITH TESTS.

560
lib/ldpc/mod2dense-test.c Executable file
View File

@ -0,0 +1,560 @@
/* MOD2DENSE-TEST. C - Program to test mod2dense module. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* Correct output for this program is saved in the file mod2dense-test-out */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mod2dense.h"
main(void)
{
mod2dense *m1, *m2, *m3, *m4;
mod2dense *s0, *s1, *s2, *s3, *s4, *s5;
int a_row[35], a_col[35];
int code;
int i, j;
FILE *f;
printf("\nPART 1:\n\n");
/* Set up m1 with bits on a diagonal plus a few more set to 1. */
m1 = mod2dense_allocate(35,40);
mod2dense_clear(m1);
for (i = 0; i<35; i++) mod2dense_set(m1,i,i,1);
mod2dense_set(m1,2,3,1);
mod2dense_set(m1,34,4,1);
mod2dense_set(m1,10,38,1);
/* Print m1. */
printf("Matrix m1:\n\n");
mod2dense_print(stdout,m1);
printf("\n"); fflush(stdout);
/* Store m1 in a file. */
f = fopen("test-file","wb");
if (f==0)
{ fprintf(stderr,"Can't create test-file\n");
exit(1);
}
if (!mod2dense_write(f,m1))
{ printf("Error from mod2dense_write\n");
}
fclose(f);
/* Read matrix written above back into m2. */
f = fopen("test-file","rb");
if (f==0)
{ fprintf(stderr,"Can't open test-file\n");
exit(1);
}
m2 = mod2dense_read(f);
if (m2==0)
{ printf("Error from mod2dense_read\n");
exit(1);
}
/* Print m2, along with result of equality test. */
printf("Matrix m2, as read from file. Should be same as m1 above.\n\n");
mod2dense_print(stdout,m2);
printf("\n"); fflush(stdout);
printf("Test of equality of m1 & m2 (should be 1): %d\n\n",
mod2dense_equal(m1,m2));
/* Copy m1 to m3. */
m3 = mod2dense_allocate(mod2dense_rows(m1),mod2dense_cols(m1));
mod2dense_copy(m1,m3);
/* Print m3, along with result of equality test. */
printf("Matrix m3, copied from m1 above.\n\n");
mod2dense_print(stdout,m3);
printf("\n"); fflush(stdout);
printf("Test of equality of m1 & m3 (should be 1): %d\n\n",
mod2dense_equal(m1,m3));
/* Clear m3. */
mod2dense_clear(m3);
/* Print m3 again. */
printf("Matrix m3 again, should now be all zeros.\n\n");
mod2dense_print(stdout,m3);
printf("\n"); fflush(stdout);
printf("Test of equality of m1 & m3 (should be 0): %d\n\n",
mod2dense_equal(m1,m3));
printf("\nPART 2:\n\n");
/* Compute transpose of m1. */
m4 = mod2dense_allocate(mod2dense_cols(m1),mod2dense_rows(m1));
mod2dense_transpose(m1,m4);
/* Print transpose. */
printf("Transpose of m1.\n\n");
mod2dense_print(stdout,m4);
printf("\n"); fflush(stdout);
/* Free space for m1, m2, and m3. */
mod2dense_free(m1);
mod2dense_free(m2);
mod2dense_free(m3);
printf("\nPART 3:\n\n");
/* Allocate some small matrices. */
s0 = mod2dense_allocate(5,7);
s1 = mod2dense_allocate(5,7);
s2 = mod2dense_allocate(7,4);
s3 = mod2dense_allocate(5,4);
s4 = mod2dense_allocate(5,7);
/* Set up the contents of s0, s1, and s2. */
mod2dense_clear(s0);
mod2dense_clear(s1);
mod2dense_clear(s2);
mod2dense_set(s0,1,3,1);
mod2dense_set(s0,1,4,1);
mod2dense_set(s0,2,0,1);
mod2dense_set(s0,3,1,1);
mod2dense_set(s1,1,3,1);
mod2dense_set(s1,1,5,1);
mod2dense_set(s1,3,0,1);
mod2dense_set(s1,3,1,1);
mod2dense_set(s1,3,6,1);
mod2dense_set(s2,5,1,1);
mod2dense_set(s2,5,2,1);
mod2dense_set(s2,5,3,1);
mod2dense_set(s2,0,0,1);
mod2dense_set(s2,1,1,1);
/* Print s0, s1, and s2. */
printf("Matrix s0.\n\n");
mod2dense_print(stdout,s0);
printf("\nMatrix s1.\n\n");
mod2dense_print(stdout,s1);
printf("\nMatrix s2.\n\n");
mod2dense_print(stdout,s2);
printf("\n"); fflush(stdout);
/* Add s0 and s1, storing the result in s4, then print s4. */
mod2dense_add(s0,s1,s4);
printf("Sum of s0 and s1.\n\n");
mod2dense_print(stdout,s4);
printf("\n"); fflush(stdout);
/* Multiply s1 and s2, storing the product in s3, and then print s3. */
mod2dense_multiply(s1,s2,s3);
printf("Product of s1 and s2.\n\n");
mod2dense_print(stdout,s3);
printf("\n"); fflush(stdout);
/* Try clearing a bit in s3, then printing the result. */
mod2dense_set(s3,1,2,0);
printf("Above matrix with (1,2) cleared.\n\n");
mod2dense_print(stdout,s3);
printf("\n"); fflush(stdout);
/* Free space for s0, s1, s2, s3, and s4. */
mod2dense_free(s0);
mod2dense_free(s1);
mod2dense_free(s2);
mod2dense_free(s3);
mod2dense_free(s4);
printf("\nPART 4:\n\n");
/* Set up a small square matrix, s1. Also copy it to s2. */
s1 = mod2dense_allocate(5,5);
s2 = mod2dense_allocate(5,5);
mod2dense_clear(s1);
mod2dense_set(s1,0,3,1);
mod2dense_set(s1,1,4,1);
mod2dense_set(s1,1,1,1);
mod2dense_set(s1,2,0,1);
mod2dense_set(s1,3,1,1);
mod2dense_set(s1,3,2,1);
mod2dense_set(s1,4,2,1);
mod2dense_set(s1,4,0,1);
mod2dense_copy(s1,s2);
/* Print s1. */
printf("Matrix s1.\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
/* Compute inverse of s1, storing it in s3. */
s3 = mod2dense_allocate(5,5);
code = mod2dense_invert(s1,s3);
/* Print inverse (s3). */
printf("Matrix s3, the inverse of s1 (return code %d).\n\n",code);
mod2dense_print(stdout,s3);
printf("\n"); fflush(stdout);
/* Compute and print product of inverse and original matrix, both ways. */
mod2dense_multiply(s2,s3,s1);
printf("Original matrix times inverse (should be identity).\n\n");
mod2dense_print(stdout,s1);
mod2dense_multiply(s3,s2,s1);
printf("\nInverse times original matrix (should be identity).\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
/* Compute and print inverse of inverse, and do equality check. */
mod2dense_invert(s3,s1);
printf("Inverse of inverse (should be same as original s1).\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
printf("Test of equality with original (should be 1): %d\n\n",
mod2dense_equal(s1,s2));
/* Free s1, s2, and s3. */
mod2dense_free(s1);
mod2dense_free(s2);
mod2dense_free(s3);
/* Set up a rectangular matrix like s1 above, but with two zero columns.
Copy to s4 as well. */
s1 = mod2dense_allocate(5,7);
mod2dense_clear(s1);
mod2dense_set(s1,0,4,1);
mod2dense_set(s1,1,6,1);
mod2dense_set(s1,1,1,1);
mod2dense_set(s1,2,0,1);
mod2dense_set(s1,3,1,1);
mod2dense_set(s1,3,2,1);
mod2dense_set(s1,4,2,1);
mod2dense_set(s1,4,0,1);
s4 = mod2dense_allocate(5,7);
mod2dense_copy(s1,s4);
/* Print s1. */
printf("Matrix s1.\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
/* Compute inverse of sub-matrix of s1, storing it in s3. Print results. */
s3 = mod2dense_allocate(5,7);
code = mod2dense_invert_selected(s1,s3,a_row,a_col);
printf("Matrix s3, from invert_selected applied to s1 (return code %d).\n\n",
code);
mod2dense_print(stdout,s3);
printf("\n row ordering returned:");
for (i = 0; i<5; i++) printf(" %d",a_row[i]);
printf("\n");
printf("\n column ordering returned:");
for (j = 0; j<7; j++) printf(" %d",a_col[j]);
printf("\n");
printf("\n"); fflush(stdout);
printf("Columns extracted in order from original matrix.\n\n");
s2 = mod2dense_allocate(5,5);
mod2dense_copycols(s4,s2,a_col);
mod2dense_print(stdout,s2);
printf("\n"); fflush(stdout);
s5 = mod2dense_allocate(5,5);
code = mod2dense_invert(s2,s5);
printf(
"Inverse of above calculated using mod2dense_inverse (return code %d)\n\n",
code);
mod2dense_print(stdout,s5);
printf("\n"); fflush(stdout);
printf(
"Columns extracted in order from s3 (should also be inverse of above).\n\n");
mod2dense_copycols(s3,s2,a_col);
mod2dense_print(stdout,s2);
printf("\n"); fflush(stdout);
/* Try out mod2dense_invert_selected again. */
mod2dense_clear(s1);
mod2dense_set(s1,0,0,1);
mod2dense_set(s1,0,1,1);
mod2dense_set(s1,1,1,1);
mod2dense_set(s1,1,2,1);
mod2dense_set(s1,2,0,1);
mod2dense_set(s1,2,2,1);
mod2dense_set(s1,3,3,1);
mod2dense_set(s1,3,4,1);
printf("Matrix s1.\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
code = mod2dense_invert_selected(s1,s3,a_row,a_col);
printf("Matrix s3, from invert_selected applied to s1 (return code %d).\n\n",
code);
mod2dense_print(stdout,s3);
printf("\n row ordering returned:");
for (i = 0; i<5; i++) printf(" %d",a_row[i]);
printf("\n");
printf("\n column ordering returned:");
for (j = 0; j<7; j++) printf(" %d",a_col[j]);
printf("\n");
printf("\n"); fflush(stdout);
printf("Matrix s4, from copying rows in order from s3.\n\n");
mod2dense_copyrows(s3,s4,a_row);
mod2dense_print(stdout,s4);
free(s1);
free(s2);
free(s3);
free(s4);
free(s5);
printf("\nPART 5:\n\n");
/* Set up a larger square matrix, s1. Also copy it to s2. */
s1 = mod2dense_allocate(35,35);
s2 = mod2dense_allocate(35,35);
mod2dense_clear(s1);
for (i = 0; i<35; i++) mod2dense_set(s1,i,i,1);
mod2dense_set(s1,10,3,1);
mod2dense_set(s1,11,4,1);
mod2dense_set(s1,11,11,1);
mod2dense_set(s1,12,20,1);
mod2dense_set(s1,13,31,1);
mod2dense_set(s1,23,12,1);
mod2dense_set(s1,24,12,1);
mod2dense_set(s1,14,10,1);
mod2dense_set(s1,2,20,1);
mod2dense_set(s1,3,31,1);
mod2dense_set(s1,3,12,1);
mod2dense_set(s1,24,2,1);
mod2dense_set(s1,24,0,1);
mod2dense_set(s1,5,3,1);
mod2dense_set(s1,18,3,1);
mod2dense_set(s1,17,11,1);
mod2dense_set(s1,32,23,1);
mod2dense_set(s1,9,24,1);
mod2dense_set(s1,19,11,1);
mod2dense_set(s1,11,30,1);
mod2dense_set(s1,21,27,1);
mod2dense_set(s1,21,22,1);
mod2dense_set(s1,23,33,1);
mod2dense_set(s1,24,23,1);
mod2dense_set(s1,24,25,1);
mod2dense_set(s1,30,34,1);
mod2dense_set(s1,31,10,1);
mod2dense_set(s1,33,17,1);
mod2dense_set(s1,33,18,1);
mod2dense_set(s1,34,8,1);
mod2dense_set(s1,34,11,1);
mod2dense_set(s1,34,3,1);
mod2dense_set(s1,34,24,1);
mod2dense_set(s1,25,34,1);
mod2dense_set(s1,13,34,1);
mod2dense_set(s1,3,3,0);
mod2dense_set(s1,11,11,0);
mod2dense_set(s1,23,23,0);
mod2dense_set(s1,24,24,0);
mod2dense_copy(s1,s2);
/* Print s1. */
printf("Matrix s1.\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
/* Compute inverse of s1, storing it in s3. */
s3 = mod2dense_allocate(35,35);
code = mod2dense_invert(s1,s3);
/* Print inverse (s3). */
printf("Matrix s3, the inverse of s1 (return code %d).\n\n",code);
mod2dense_print(stdout,s3);
printf("\n"); fflush(stdout);
/* Compute and print product of inverse and original matrix, both ways. */
mod2dense_multiply(s2,s3,s1);
printf("Original matrix times inverse (should be identity).\n\n");
mod2dense_print(stdout,s1);
mod2dense_multiply(s3,s2,s1);
printf("\nInverse times original matrix (should be identity).\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
/* Compute and print inverse of inverse, and do equality check. */
mod2dense_invert(s3,s1);
printf("Inverse of inverse (should be same as original s1).\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
printf("Test of equality with original (should be 1): %d\n\n",
mod2dense_equal(s1,s2));
/* Free s1, s2, and s3. */
mod2dense_free(s1);
mod2dense_free(s2);
mod2dense_free(s3);
printf("\nPART 6:\n\n");
/* Set up a largish square matrix, s1. Also copy it to s2. */
s1 = mod2dense_allocate(35,35);
s2 = mod2dense_allocate(35,35);
mod2dense_clear(s1);
for (i = 0; i<10; i++)
{ if (i!=3 && i!=7)
{ mod2dense_set(s1,i,i,1);
}
}
for (i = 10; i<35; i++)
{ if (i!=15 && i!=21 && i!=32)
{ mod2dense_set(s1,i,34-(i-10),1);
}
}
/* Print s1. */
printf("Matrix s1.\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
/* Forcibly invert s1, storing inverse in s3. */
s3 = mod2dense_allocate(35,35);
code = mod2dense_forcibly_invert(s1,s3,a_row,a_col);
/* Print inverse, and list of altered elements. */
printf("Result of forcibly inverting s1 (needed to alter %d elements).\n\n",
code);
mod2dense_print(stdout,s3);
printf("\n"); fflush(stdout);
printf("Altered elements at these indexes:\n\n");
for (i = 0; i<code; i++)
{ printf("%3d %3d\n",a_row[i],a_col[i]);
}
printf("\n"); fflush(stdout);
/* Compute and print inverse of inverse. */
mod2dense_invert(s3,s1);
printf("Inverse of inverse of altered matrix.\n\n");
mod2dense_print(stdout,s1);
printf("\n"); fflush(stdout);
printf("\nDONE WITH TESTS.\n");
exit(0);
}

752
lib/ldpc/mod2dense.c Executable file
View File

@ -0,0 +1,752 @@
/* MOD2DENSE.C - Procedures for handling dense mod2 matrices. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* NOTE: See mod2dense.html for documentation on these procedures. */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "alloc.h"
#include "intio.h"
#include "mod2dense.h"
/* ALLOCATE SPACE FOR A DENSE MOD2 MATRIX. */
mod2dense *mod2dense_allocate
( int n_rows, /* Number of rows in matrix */
int n_cols /* Number of columns in matrix */
)
{
mod2dense *m;
int j;
if (n_rows<=0 || n_cols<=0)
{ fprintf(stderr,"mod2dense_allocate: Invalid number of rows or columns\n");
exit(1);
}
m = chk_alloc (1, sizeof *m);
m->n_rows = n_rows;
m->n_cols = n_cols;
m->n_words = (n_rows+mod2_wordsize-1) >> mod2_wordsize_shift;
m->col = chk_alloc (m->n_cols, sizeof *m->col);
m->bits = chk_alloc(m->n_words*m->n_cols, sizeof *m->bits);
for (j = 0; j<m->n_cols; j++)
{ m->col[j] = m->bits + j*m->n_words;
}
return m;
}
/* FREE SPACE OCCUPIED BY A DENSE MOD2 MATRIX. */
void mod2dense_free
( mod2dense *m /* Matrix to free */
)
{ free(m->bits);
free(m->col);
free(m);
}
/* CLEAR A DENSE MOD2 MATRIX. */
void mod2dense_clear
( mod2dense *r
)
{
int k, j;
for (j = 0; j<mod2dense_cols(r); j++)
{ for (k = 0; k<r->n_words; k++)
{ r->col[j][k] = 0;
}
}
}
/* COPY A DENSE MOD2 MATRIX. */
void mod2dense_copy
( mod2dense *m, /* Matrix to copy */
mod2dense *r /* Place to store copy of matrix */
)
{
int k, j;
if (mod2dense_rows(m)>mod2dense_rows(r)
|| mod2dense_cols(m)>mod2dense_cols(r))
{ fprintf(stderr,"mod2dense_copy: Destination matrix is too small\n");
exit(1);
}
for (j = 0; j<mod2dense_cols(m); j++)
{ for (k = 0; k<m->n_words; k++)
{ r->col[j][k] = m->col[j][k];
}
for ( ; k<r->n_words; k++)
{ r->col[j][k] = 0;
}
}
for ( ; j<mod2dense_cols(r); j++)
{ for (k = 0; k<r->n_words; k++)
{ r->col[j][k] = 0;
}
}
}
/* COPY ROWS OF A DENSE MOD2 MATRIX. */
void mod2dense_copyrows
( mod2dense *m, /* Matrix to copy */
mod2dense *r, /* Place to store copy of matrix */
int *rows /* Indexes of rows to copy, from 0 */
)
{
int i, j;
if (mod2dense_cols(m)>mod2dense_cols(r))
{ fprintf(stderr,
"mod2dense_copyrows: Destination matrix has fewer columns than source\n");
exit(1);
}
mod2dense_clear(r);
for (i = 0; i<mod2dense_rows(r); i++)
{ if (rows[i]<0 || rows[i]>=mod2dense_rows(m))
{ fprintf(stderr,"mod2dense_copyrows: Row index out of range\n");
exit(1);
}
for (j = 0; j<mod2dense_cols(m); j++)
{ mod2dense_set(r,i,j,mod2dense_get(m,rows[i],j));
}
}
}
/* COPY COLUMNS OF A DENSE MOD2 MATRIX. */
void mod2dense_copycols
( mod2dense *m, /* Matrix to copy */
mod2dense *r, /* Place to store copy of matrix */
int *cols /* Indexes of columns to copy, from 0 */
)
{
int k, j;
if (mod2dense_rows(m)>mod2dense_rows(r))
{ fprintf(stderr,
"mod2dense_copycols: Destination matrix has fewer rows than source\n");
exit(1);
}
for (j = 0; j<mod2dense_cols(r); j++)
{ if (cols[j]<0 || cols[j]>=mod2dense_cols(m))
{ fprintf(stderr,"mod2dense_copycols: Column index out of range\n");
exit(1);
}
for (k = 0; k<m->n_words; k++)
{ r->col[j][k] = m->col[cols[j]][k];
}
for ( ; k<r->n_words; k++)
{ r->col[j][k] = 0;
}
}
}
/* PRINT A DENSE MOD2 MATRIX IN HUMAN-READABLE FORM. */
void mod2dense_print
( FILE *f,
mod2dense *m
)
{
int i, j;
for (i = 0; i<mod2dense_rows(m); i++)
{ for (j = 0; j<mod2dense_cols(m); j++)
{ fprintf(f," %d",mod2dense_get(m,i,j));
}
fprintf(f,"\n");
}
}
/* WRITE A DENSE MOD2 MATRIX TO A FILE IN MACHINE-READABLE FORM.
Data is written using intio_write, so that it will be readable on a machine
with a different byte-ordering. At present, this assumes that the words
used to pack bits into are no longer than 32 bits. */
int mod2dense_write
( FILE *f,
mod2dense *m
)
{
int j, k;
intio_write(f,m->n_rows);
if (ferror(f)) return 0;
intio_write(f,m->n_cols);
if (ferror(f)) return 0;
for (j = 0; j<mod2dense_cols(m); j++)
{
for (k = 0; k<m->n_words; k++)
{ intio_write(f,m->col[j][k]);
if (ferror(f)) return 0;
}
}
return 1;
}
/* READ A DENSE MOD2 MATRIX STORED IN MACHINE-READABLE FORM FROM A FILE. */
mod2dense *mod2dense_read
( FILE *f
)
{
int n_rows, n_cols;
mod2dense *m;
int j, k;
n_rows = intio_read(f);
if (feof(f) || ferror(f) || n_rows<=0) return 0;
n_cols = intio_read(f);
if (feof(f) || ferror(f) || n_cols<=0) return 0;
m = mod2dense_allocate(n_rows,n_cols);
for (j = 0; j<mod2dense_cols(m); j++)
{
for (k = 0; k<m->n_words; k++)
{ m->col[j][k] = intio_read(f);
if (feof(f) || ferror(f))
{ mod2dense_free(m);
return 0;
}
}
}
return m;
}
/* GET AN ELEMENT FROM A DENSE MOD2 MATRIX. */
int mod2dense_get
( mod2dense *m, /* Matrix to get element from */
int row, /* Row of element (starting with zero) */
int col /* Column of element (starting with zero) */
)
{
if (row<0 || row>=mod2dense_rows(m) || col<0 || col>=mod2dense_cols(m))
{ fprintf(stderr,"mod2dense_get: row or column index out of bounds\n");
exit(1);
}
return mod2_getbit (m->col[col][row>>mod2_wordsize_shift],
row&mod2_wordsize_mask);
}
/* SET AN ELEMENT IN A DENSE MOD2 MATRIX. */
void mod2dense_set
( mod2dense *m, /* Matrix to modify element of */
int row, /* Row of element (starting with zero) */
int col, /* Column of element (starting with zero) */
int value /* New value of element (0 or 1) */
)
{
mod2word *w;
if (row<0 || row>=mod2dense_rows(m) || col<0 || col>=mod2dense_cols(m))
{ fprintf(stderr,"mod2dense_set: row or column index out of bounds\n");
exit(1);
}
w = &m->col[col][row>>mod2_wordsize_shift];
*w = value ? mod2_setbit1(*w,row&mod2_wordsize_mask)
: mod2_setbit0(*w,row&mod2_wordsize_mask);
}
/* FLIP AN ELEMENT OF A DENSE MOD2 MATRIX. */
int mod2dense_flip
( mod2dense *m, /* Matrix to flip element in */
int row, /* Row of element (starting with zero) */
int col /* Column of element (starting with zero) */
)
{
mod2word *w;
int b;
if (row<0 || row>=mod2dense_rows(m) || col<0 || col>=mod2dense_cols(m))
{ fprintf(stderr,"mod2dense_flip: row or column index out of bounds\n");
exit(1);
}
b = 1 ^ mod2_getbit (m->col[col][row>>mod2_wordsize_shift],
row&mod2_wordsize_mask);
w = &m->col[col][row>>mod2_wordsize_shift];
*w = b ? mod2_setbit1(*w,row&mod2_wordsize_mask)
: mod2_setbit0(*w,row&mod2_wordsize_mask);
return b;
}
/* COMPUTE THE TRANSPOSE OF A DENSE MOD2 MATRIX. */
void mod2dense_transpose
( mod2dense *m, /* Matrix to compute transpose of (left unchanged) */
mod2dense *r /* Result of transpose operation */
)
{
mod2word w, v, *p;
int k1, j1, i2, j2;
if (mod2dense_rows(m)!=mod2dense_cols(r)
|| mod2dense_cols(m)!=mod2dense_rows(r))
{ fprintf(stderr,
"mod2dense_transpose: Matrices have incompatible dimensions\n");
exit(1);
}
if (r==m)
{ fprintf(stderr,
"mod2dense_transpose: Result matrix is the same as the operand\n");
exit(1);
}
mod2dense_clear(r);
for (j1 = 0; j1<mod2dense_cols(m); j1++)
{
i2 = j1 >> mod2_wordsize_shift;
v = 1 << (j1 & mod2_wordsize_mask);
p = m->col[j1];
k1 = 0;
for (j2 = 0; j2<mod2dense_cols(r); j2++)
{ if (k1==0)
{ w = *p++;
k1 = mod2_wordsize;
}
if (w&1)
{ r->col[j2][i2] |= v;
}
w >>= 1;
k1 -= 1;
}
}
}
/* ADD TWO DENSE MOD2 MATRICES. */
void mod2dense_add
( mod2dense *m1, /* Left operand of add */
mod2dense *m2, /* Right operand of add */
mod2dense *r /* Place to store result of add */
)
{
int j, k;
if (mod2dense_rows(m1)!=mod2dense_rows(r)
|| mod2dense_cols(m1)!=mod2dense_cols(r)
|| mod2dense_rows(m2)!=mod2dense_rows(r)
|| mod2dense_cols(m2)!=mod2dense_cols(r))
{ fprintf(stderr,"mod2dense_add: Matrices have different dimensions\n");
exit(1);
}
for (j = 0; j<mod2dense_cols(r); j++)
{ for (k = 0; k<r->n_words; k++)
{ r->col[j][k] = m1->col[j][k] ^ m2->col[j][k];
}
}
}
/* MULTIPLY TWO DENSE MOD2 MATRICES.
The algorithm used runs faster if the second matrix (right operand of the
multiply) is sparse, but it is also appropriate for dense matrices. This
procedure could be speeded up a bit by replacing the call of mod2dense_get
with in-line code that avoids division, but this doesn't seem worthwhile
at the moment.
*/
void mod2dense_multiply
( mod2dense *m1, /* Left operand of multiply */
mod2dense *m2, /* Right operand of multiply */
mod2dense *r /* Place to store result of multiply */
)
{
int i, j, k;
if (mod2dense_cols(m1)!=mod2dense_rows(m2)
|| mod2dense_rows(m1)!=mod2dense_rows(r)
|| mod2dense_cols(m2)!=mod2dense_cols(r))
{ fprintf(stderr,
"mod2dense_multiply: Matrices have incompatible dimensions\n");
exit(1);
}
if (r==m1 || r==m2)
{ fprintf(stderr,
"mod2dense_multiply: Result matrix is the same as one of the operands\n");
exit(1);
}
mod2dense_clear(r);
for (j = 0; j<mod2dense_cols(r); j++)
{ for (i = 0; i<mod2dense_rows(m2); i++)
{ if (mod2dense_get(m2,i,j))
{ for (k = 0; k<r->n_words; k++)
{ r->col[j][k] ^= m1->col[i][k];
}
}
}
}
}
/* SEE WHETHER TWO DENSE MOD2 MATRICES ARE EQUAL. */
int mod2dense_equal
( mod2dense *m1,
mod2dense *m2
)
{
int k, j, w;
mod2word m;
if (mod2dense_rows(m1)!=mod2dense_rows(m2)
|| mod2dense_cols(m1)!=mod2dense_cols(m2))
{ fprintf(stderr,"mod2dense_equal: Matrices have different dimensions\n");
exit(1);
}
w = m1->n_words;
/* Form a mask that has 1s in the lower bit positions corresponding to
bits that contain information in the last word of a matrix column. */
m = (1 << (mod2_wordsize - (w*mod2_wordsize-m1->n_rows))) - 1;
for (j = 0; j<mod2dense_cols(m1); j++)
{
for (k = 0; k<w-1; k++)
{ if (m1->col[j][k] != m2->col[j][k]) return 0;
}
if ((m1->col[j][k]&m) != (m2->col[j][k]&m)) return 0;
}
return 1;
}
/* INVERT A DENSE MOD2 MATRIX. */
int mod2dense_invert
( mod2dense *m, /* The matrix to find the inverse of (destroyed) */
mod2dense *r /* Place to store the inverse */
)
{
mod2word *s, *t;
int i, j, k, n, w, k0, b0;
if (mod2dense_rows(m)!=mod2dense_cols(m))
{ fprintf(stderr,"mod2dense_invert: Matrix to invert is not square\n");
exit(1);
}
if (r==m)
{ fprintf(stderr,
"mod2dense_invert: Result matrix is the same as the operand\n");
exit(1);
}
n = mod2dense_rows(m);
w = m->n_words;
if (mod2dense_rows(r)!=n || mod2dense_cols(r)!=n)
{ fprintf(stderr,
"mod2dense_invert: Matrix to receive inverse has wrong dimensions\n");
exit(1);
}
mod2dense_clear(r);
for (i = 0; i<n; i++)
{ mod2dense_set(r,i,i,1);
}
for (i = 0; i<n; i++)
{
k0 = i >> mod2_wordsize_shift;
b0 = i & mod2_wordsize_mask;
for (j = i; j<n; j++)
{ if (mod2_getbit(m->col[j][k0],b0)) break;
}
if (j==n) return 0;
if (j!=i)
{
t = m->col[i];
m->col[i] = m->col[j];
m->col[j] = t;
t = r->col[i];
r->col[i] = r->col[j];
r->col[j] = t;
}
for (j = 0; j<n; j++)
{ if (j!=i && mod2_getbit(m->col[j][k0],b0))
{ s = m->col[j];
t = m->col[i];
for (k = k0; k<w; k++) s[k] ^= t[k];
s = r->col[j];
t = r->col[i];
for (k = 0; k<w; k++) s[k] ^= t[k];
}
}
}
return 1;
}
/* INVERT A DENSE MOD2 MATRIX WITH ROWS & COLUMNS SELECTED FROM BIGGER MATRIX.*/
int mod2dense_invert_selected
( mod2dense *m, /* Matrix from which to pick a submatrix to invert */
mod2dense *r, /* Place to store the inverse */
int *rows, /* Set to indexes of rows used and not used */
int *cols /* Set to indexes of columns used and not used */
)
{
mod2word *s, *t;
int i, j, k, n, n2, w, k0, b0, c, R;
if (r==m)
{ fprintf(stderr,
"mod2dense_invert_selected2: Result matrix is the same as the operand\n");
exit(1);
}
n = mod2dense_rows(m);
w = m->n_words;
n2 = mod2dense_cols(m);
if (mod2dense_rows(r)!=n || mod2dense_cols(r)!=n2)
{ fprintf(stderr,
"mod2dense_invert_selected2: Matrix to receive inverse has wrong dimensions\n");
exit(1);
}
mod2dense_clear(r);
for (i = 0; i<n; i++)
{ rows[i] = i;
}
for (j = 0; j<n2; j++)
{ cols[j] = j;
}
R = 0;
i = 0;
for (;;)
{
while (i<n-R)
{
k0 = rows[i] >> mod2_wordsize_shift;
b0 = rows[i] & mod2_wordsize_mask;
for (j = i; j<n2; j++)
{ if (mod2_getbit(m->col[cols[j]][k0],b0)) break;
}
if (j<n2) break;
R += 1;
c = rows[i];
rows[i] = rows[n-R];
rows[n-R] = c;
}
if (i==n-R) break;
c = cols[j];
cols[j] = cols[i];
cols[i] = c;
mod2dense_set(r,rows[i],c,1);
for (j = 0; j<n2; j++)
{ if (j!=c && mod2_getbit(m->col[j][k0],b0))
{ s = m->col[j];
t = m->col[c];
for (k = 0; k<w; k++) s[k] ^= t[k];
s = r->col[j];
t = r->col[c];
for (k = 0; k<w; k++) s[k] ^= t[k];
}
}
i += 1;
}
for (j = n-R; j<n; j++)
{ s = r->col[cols[j]];
for (k = 0; k<w; k++) s[k] = 0;
}
return R;
}
/* FORCIBLY INVERT A DENSE MOD2 MATRIX. */
int mod2dense_forcibly_invert
( mod2dense *m, /* The matrix to find the 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 */
)
{
mod2word *s, *t;
int i, j, k, n, w, k0, b0;
int u, c;
if (mod2dense_rows(m)!=mod2dense_cols(m))
{ fprintf(stderr,
"mod2dense_forcibly_invert: Matrix to invert is not square\n");
exit(1);
}
if (r==m)
{ fprintf(stderr,
"mod2dense_forcibly_invert: Result matrix is the same as the operand\n");
exit(1);
}
n = mod2dense_rows(m);
w = m->n_words;
if (mod2dense_rows(r)!=n || mod2dense_cols(r)!=n)
{ fprintf(stderr,
"mod2dense_forcibly_invert: Matrix to receive inverse has wrong dimensions\n");
exit(1);
}
mod2dense_clear(r);
for (i = 0; i<n; i++)
{ mod2dense_set(r,i,i,1);
}
for (i = 0; i<n; i++)
{ a_row[i] = -1;
a_col[i] = i;
}
for (i = 0; i<n; i++)
{
k0 = i >> mod2_wordsize_shift;
b0 = i & mod2_wordsize_mask;
for (j = i; j<n; j++)
{ if (mod2_getbit(m->col[j][k0],b0)) break;
}
if (j==n)
{ j = i;
mod2dense_set(m,i,j,1);
a_row[i] = i;
}
if (j!=i)
{
t = m->col[i];
m->col[i] = m->col[j];
m->col[j] = t;
t = r->col[i];
r->col[i] = r->col[j];
r->col[j] = t;
u = a_col[i];
a_col[i] = a_col[j];
a_col[j] = u;
}
for (j = 0; j<n; j++)
{ if (j!=i && mod2_getbit(m->col[j][k0],b0))
{ s = m->col[j];
t = m->col[i];
for (k = k0; k<w; k++) s[k] ^= t[k];
s = r->col[j];
t = r->col[i];
for (k = 0; k<w; k++) s[k] ^= t[k];
}
}
}
c = 0;
for (i = 0; i<n; i++)
{ if (a_row[i]!=-1)
{ a_row[c] = a_row[i];
a_col[c] = a_col[i];
c += 1;
}
}
return c;
}

113
lib/ldpc/mod2dense.h Executable file
View File

@ -0,0 +1,113 @@
/* MOD2DENSE.H - Interface to module for handling dense mod2 matrices. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* This module implements operations on matrices of mod2 elements (bits,
with addition and multiplication being done modulo 2). The matrices
are stored with consecutive bits of a column packed into words, and
the procedures are implemented where possible using bit operations
on these words. This is an appropriate representation when the matrices
are dense (ie, 0s and 1s are about equally frequent).
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.
*/
#include <stdint.h> /* Has the definition of uint32_t used below */
/* PACKING OF BITS INTO WORDS. Bits are packed into 32-bit words, with
the low-order bit coming first. */
typedef uint32_t mod2word; /* Data type that holds packed bits. If uint32_t
doesn't exist, change it to unsigned long */
#define mod2_wordsize 32 /* Number of bits that fit in a mod2word. Can't
be increased without changing intio module */
#define mod2_wordsize_shift 5 /* Amount to shift by to divide by wordsize */
#define mod2_wordsize_mask 0x1f /* What to AND with to produce mod wordsize */
/* Extract the i'th bit of a mod2word. */
#define mod2_getbit(w,i) (((w)>>(i))&1)
/* Make a word like w, but with the i'th bit set to 1 (if it wasn't already). */
#define mod2_setbit1(w,i) ((w)|(1<<(i)))
/* Make a word like w, but with the i'th bit set to 0 (if it wasn't already). */
#define mod2_setbit0(w,i) ((w)&(~(1<<(i))))
/* STRUCTURE REPRESENTING A DENSE MATRIX. These structures are dynamically
allocated using mod2dense_allocate (or by other procedures that call
mod2dense_allocate). They should be freed with mod2dense_free when no
longer required.
Direct access to this structure should be avoided except in low-level
routines. Use the macros and procedures defined below instead. */
typedef struct
{
int n_rows; /* Number of rows in the matrix */
int n_cols; /* Number of columns in the matrix */
int n_words; /* Number of words used to store a column of bits */
mod2word **col; /* Pointer to array of pointers to columns */
mod2word *bits; /* Pointer to storage block for bits in this matrix
(pieces of this block are pointed to from col) */
} mod2dense;
/* MACROS. */
#define mod2dense_rows(m) ((m)->n_rows) /* Get the number of rows or columns */
#define mod2dense_cols(m) ((m)->n_cols) /* in a matrix */
/* PROCEDURES. */
mod2dense *mod2dense_allocate (int, int);
void mod2dense_free (mod2dense *);
void mod2dense_clear (mod2dense *);
void mod2dense_copy (mod2dense *, mod2dense *);
void mod2dense_copyrows (mod2dense*, mod2dense *, int *);
void mod2dense_copycols (mod2dense*, mod2dense *, int *);
void mod2dense_print (FILE *, mod2dense *);
int mod2dense_write (FILE *, mod2dense *);
mod2dense *mod2dense_read (FILE *);
int mod2dense_get (mod2dense *, int, int);
void mod2dense_set (mod2dense *, int, int, int);
int mod2dense_flip(mod2dense *, int, int);
void mod2dense_transpose (mod2dense *, mod2dense *);
void mod2dense_add (mod2dense *, mod2dense *, mod2dense *);
void mod2dense_multiply (mod2dense *, mod2dense *, mod2dense *);
int mod2dense_equal (mod2dense *, mod2dense *);
int mod2dense_invert (mod2dense *, mod2dense *);
int mod2dense_forcibly_invert (mod2dense *, mod2dense *, int *, int *);
int mod2dense_invert_selected (mod2dense *, mod2dense *, int *, int *);

487
lib/ldpc/mod2dense.html Executable file
View File

@ -0,0 +1,487 @@
<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>

431
lib/ldpc/mod2sparse-test-out Executable file
View File

@ -0,0 +1,431 @@
PART 1:
Matrix m1:
0: 0
1: 1
2: 2 3
3: 3
4: 4
5: 5
6: 6
7: 7
8: 8
9: 9
10: 10 38
11: 11
12: 12
13: 13
14: 14
15: 15
16: 16
17: 17
18: 18
19: 19
20: 20
21: 21
22: 22
23: 23
24: 24
25: 25
26: 26
27: 27
28: 28
29: 29
30: 30
31: 31
32: 32
33: 33
34: 4 34
Matrix m2, as read from file. Should be same as m1 above.
0: 0
1: 1
2: 2 3
3: 3
4: 4
5: 5
6: 6
7: 7
8: 8
9: 9
10: 10 38
11: 11
12: 12
13: 13
14: 14
15: 15
16: 16
17: 17
18: 18
19: 19
20: 20
21: 21
22: 22
23: 23
24: 24
25: 25
26: 26
27: 27
28: 28
29: 29
30: 30
31: 31
32: 32
33: 33
34: 4 34
Test of equality of m1 & m2 (should be 1): 1
Matrix m3, copied from m1 above.
0: 0
1: 1
2: 2 3
3: 3
4: 4
5: 5
6: 6
7: 7
8: 8
9: 9
10: 10 38
11: 11
12: 12
13: 13
14: 14
15: 15
16: 16
17: 17
18: 18
19: 19
20: 20
21: 21
22: 22
23: 23
24: 24
25: 25
26: 26
27: 27
28: 28
29: 29
30: 30
31: 31
32: 32
33: 33
34: 4 34
Test of equality of m1 & m3 (should be 1): 1
Matrix m3 again, should now be all zeros.
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
Test of equality of m1 & m3 (should be 0): 0
PART 2:
Transpose of m1.
0: 0
1: 1
2: 2
3: 2 3
4: 4 34
5: 5
6: 6
7: 7
8: 8
9: 9
10: 10
11: 11
12: 12
13: 13
14: 14
15: 15
16: 16
17: 17
18: 18
19: 19
20: 20
21: 21
22: 22
23: 23
24: 24
25: 25
26: 26
27: 27
28: 28
29: 29
30: 30
31: 31
32: 32
33: 33
34: 34
35:
36:
37:
38: 10
39:
Matrix m1 after adding rows 2 and 12 and 3 to 10.
0: 0
1: 1
2: 2 3
3: 3
4: 4
5: 5
6: 6
7: 7
8: 8
9: 9
10: 2 10 12 38
11: 11
12: 12
13: 13
14: 14
15: 15
16: 16
17: 17
18: 18
19: 19
20: 20
21: 21
22: 22
23: 23
24: 24
25: 25
26: 26
27: 27
28: 28
29: 29
30: 30
31: 31
32: 32
33: 33
34: 4 34
Matrix m1 after further adding column 34 to 0.
0: 0
1: 1
2: 2 3
3: 3
4: 4
5: 5
6: 6
7: 7
8: 8
9: 9
10: 2 10 12 38
11: 11
12: 12
13: 13
14: 14
15: 15
16: 16
17: 17
18: 18
19: 19
20: 20
21: 21
22: 22
23: 23
24: 24
25: 25
26: 26
27: 27
28: 28
29: 29
30: 30
31: 31
32: 32
33: 33
34: 0 4 34
PART 3:
Matrix s0.
0:
1: 3 4
2: 0
3: 1
4:
Matrix s1.
0:
1: 3 5
2:
3: 0 1 6
4:
Matrix s2.
0: 0
1: 1
2:
3:
4:
5: 1 2 3
6:
Maxtrix s1 times unpacked vector ( 1 0 0 1 0 1 0 ).
( 0 0 0 1 0 )
Sum of s0 and s1.
0:
1: 4 5
2: 0
3: 0 6
4:
Product of s1 and s2.
0:
1: 1 2 3
2:
3: 0 1
4:
Tried to find (1,2), actually found: (1,2)
Above matrix with (1,2) cleared.
0:
1: 1 3
2:
3: 0 1
4:
Tried to find (1,1), actually found: (1,1)
Matrix with (1,1) cleared as well.
0:
1: 3
2:
3: 0 1
4:
PART 4:
Matrix s1.
0: 3 5
1: 1 6
2: 0
3: 1 2
4: 0 2
5: 6
LU decomposition (returned value was 0).
L=
0: 3
1: 1
2: 0
3: 1 2
4: 0 2 4
5:
U=
0: 0
1: 1 6
2: 2 6
3: 3
4: 6
cols: 0 1 2 3 6 5 4
rows: 2 1 3 0 4 5
Product of L and U.
0: 3
1: 1 6
2: 0
3: 1 2
4: 0 2
5:
Solution of Ly=x with x from ( 0 1 1 0 1 0 ) according to rows selected.
1 1 1 0 1
Returned value from forward_sub was 1
Solution of Uz=y.
1 0 0 0 0 0 1
Returned value from backward_sub was 1
PART 5:
Matrix m1:
0: 3
1: 1
2: 2
3: 0
Matrix m2, copyrows of m1 in order 3,1,2,0 (should be identity)
0: 0
1: 1
2: 2
3: 3
Matrix m3, copycols of m1 in order 3,1,2,0 (should be identity)
0: 0
1: 1
2: 2
3: 3
DONE WITH TESTS.

378
lib/ldpc/mod2sparse-test.c Executable file
View File

@ -0,0 +1,378 @@
/* MOD2SPARSE-TEST. C - Program to test mod2sparse module. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* Correct output for this program is saved in the file mod2sparse-test-out */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mod2sparse.h"
main(void)
{
mod2sparse *m1, *m2, *m3, *m4;
mod2sparse *s0, *s1, *s2, *s3, *s4;
mod2sparse *L, *U;
mod2entry *e;
int rows[5], cols[7];
int i, j;
FILE *f;
printf("\nPART 1:\n\n");
/* Set up m1 with bits on a diagonal plus a few more set to 1. */
m1 = mod2sparse_allocate(35,40);
mod2sparse_clear(m1);
for (i = 0; i<35; i++) mod2sparse_insert(m1,i,i);
mod2sparse_insert(m1,2,3);
mod2sparse_insert(m1,34,4);
mod2sparse_insert(m1,10,38);
/* Print m1. */
printf("Matrix m1:\n\n");
mod2sparse_print(stdout,m1);
printf("\n"); fflush(stdout);
/* Store m1 in a file. */
f = fopen("test-file","wb");
if (f==0)
{ fprintf(stderr,"Can't create test-file\n");
exit(1);
}
if (!mod2sparse_write(f,m1))
{ printf("Error from mod2sparse_write\n");
}
fclose(f);
/* Read matrix written above back into m2. */
f = fopen("test-file","rb");
if (f==0)
{ fprintf(stderr,"Can't open test-file\n");
exit(1);
}
m2 = mod2sparse_read(f);
if (m2==0)
{ printf("Error from mod2sparse_read\n");
exit(1);
}
/* Print m2, along with result of equality test. */
printf("Matrix m2, as read from file. Should be same as m1 above.\n\n");
mod2sparse_print(stdout,m2);
printf("\n"); fflush(stdout);
printf("Test of equality of m1 & m2 (should be 1): %d\n\n",
mod2sparse_equal(m1,m2));
/* Copy m1 to m3. */
m3 = mod2sparse_allocate(mod2sparse_rows(m1),mod2sparse_cols(m1));
mod2sparse_copy(m1,m3);
/* Print m3, along with result of equality test. */
printf("Matrix m3, copied from m1 above.\n\n");
mod2sparse_print(stdout,m3);
printf("\n"); fflush(stdout);
printf("Test of equality of m1 & m3 (should be 1): %d\n\n",
mod2sparse_equal(m1,m3));
/* Clear m3. */
mod2sparse_clear(m3);
/* Print m3 again. */
printf("Matrix m3 again, should now be all zeros.\n\n");
mod2sparse_print(stdout,m3);
printf("\n"); fflush(stdout);
printf("Test of equality of m1 & m3 (should be 0): %d\n\n",
mod2sparse_equal(m1,m3));
printf("\nPART 2:\n\n");
/* Compute transpose of m1. */
m4 = mod2sparse_allocate(mod2sparse_cols(m1),mod2sparse_rows(m1));
mod2sparse_transpose(m1,m4);
/* Print transpose. */
printf("Transpose of m1.\n\n");
mod2sparse_print(stdout,m4);
printf("\n"); fflush(stdout);
/* Add rows and columns in m1. */
mod2sparse_add_row(m1,10,m1,2);
mod2sparse_add_row(m1,10,m1,12);
mod2sparse_add_row(m1,10,m1,3);
printf("Matrix m1 after adding rows 2 and 12 and 3 to 10.\n\n");
mod2sparse_print(stdout,m1);
printf("\n"); fflush(stdout);
printf("Matrix m1 after further adding column 34 to 0.\n\n");
mod2sparse_add_col(m1,0,m1,34);
mod2sparse_print(stdout,m1);
printf("\n"); fflush(stdout);
/* Free space for m1, m2, and m3. */
mod2sparse_free(m1);
mod2sparse_free(m2);
mod2sparse_free(m3);
printf("\nPART 3:\n\n");
/* Allocate some small matrices. */
s0 = mod2sparse_allocate(5,7);
s1 = mod2sparse_allocate(5,7);
s2 = mod2sparse_allocate(7,4);
s3 = mod2sparse_allocate(5,4);
s4 = mod2sparse_allocate(5,7);
/* Set up the contents of s0, s1, and s2. */
mod2sparse_clear(s0);
mod2sparse_clear(s1);
mod2sparse_clear(s2);
mod2sparse_insert(s0,1,3);
mod2sparse_insert(s0,1,4);
mod2sparse_insert(s0,2,0);
mod2sparse_insert(s0,3,1);
mod2sparse_insert(s1,1,3);
mod2sparse_insert(s1,1,5);
mod2sparse_insert(s1,3,0);
mod2sparse_insert(s1,3,1);
mod2sparse_insert(s1,3,6);
mod2sparse_insert(s2,5,1);
mod2sparse_insert(s2,5,2);
mod2sparse_insert(s2,5,3);
mod2sparse_insert(s2,0,0);
mod2sparse_insert(s2,1,1);
/* Print s0, s1, and s2. */
printf("Matrix s0.\n\n");
mod2sparse_print(stdout,s0);
printf("\nMatrix s1.\n\n");
mod2sparse_print(stdout,s1);
printf("\nMatrix s2.\n\n");
mod2sparse_print(stdout,s2);
printf("\n"); fflush(stdout);
/* Multiply s1 by vector (1 1 0 1 0 1 0). */
{ char u[7] = { 1, 0, 0, 1, 0, 1, 0 };
char v[5];
int i;
printf("Maxtrix s1 times unpacked vector ( 1 0 0 1 0 1 0 ).\n\n(");
mod2sparse_mulvec(s1,u,v);
for (i = 0; i<5; i++) printf(" %d",v[i]);
printf(" )\n\n");
}
/* Add s0 and s1, storing the result in s4, then print s4. */
mod2sparse_add(s0,s1,s4);
printf("Sum of s0 and s1.\n\n");
mod2sparse_print(stdout,s4);
printf("\n"); fflush(stdout);
/* Multiply s1 and s2, storing the product in s3, and then print s3. */
mod2sparse_multiply(s1,s2,s3);
printf("Product of s1 and s2.\n\n");
mod2sparse_print(stdout,s3);
printf("\n"); fflush(stdout);
/* Try clearing a bit in s3, then printing the result. */
e = mod2sparse_find(s3,1,2);
printf("Tried to find (1,2), actually found: (%d,%d)\n\n",
mod2sparse_row(e), mod2sparse_col(e));
mod2sparse_delete(s3,e);
printf("Above matrix with (1,2) cleared.\n\n");
mod2sparse_print(stdout,s3);
printf("\n"); fflush(stdout);
/* Try clearing another bit in s3, then printing the result. */
e = mod2sparse_find(s3,1,1);
printf("Tried to find (1,1), actually found: (%d,%d)\n\n",
mod2sparse_row(e), mod2sparse_col(e));
mod2sparse_delete(s3,e);
printf("Matrix with (1,1) cleared as well.\n\n");
mod2sparse_print(stdout,s3);
printf("\n"); fflush(stdout);
/* Free space for s0, s1, s2, s3, and s4. */
mod2sparse_free(s0);
mod2sparse_free(s1);
mod2sparse_free(s2);
mod2sparse_free(s3);
mod2sparse_free(s4);
printf("\nPART 4:\n\n");
/* Set up a small rectangular matrix, s1. */
s1 = mod2sparse_allocate(6,7);
mod2sparse_clear(s1);
mod2sparse_insert(s1,0,3);
mod2sparse_insert(s1,0,5);
mod2sparse_insert(s1,1,6);
mod2sparse_insert(s1,1,1);
mod2sparse_insert(s1,2,0);
mod2sparse_insert(s1,3,1);
mod2sparse_insert(s1,3,2);
mod2sparse_insert(s1,4,2);
mod2sparse_insert(s1,4,0);
mod2sparse_insert(s1,5,6);
/* Print s1. */
printf("Matrix s1.\n\n");
mod2sparse_print(stdout,s1);
printf("\n"); fflush(stdout);
/* Compute and print LU decomposition. */
L = mod2sparse_allocate(6,5);
U = mod2sparse_allocate(5,7);
i = mod2sparse_decomp(s1,5,L,U,rows,cols,Mod2sparse_first,0,0);
printf("LU decomposition (returned value was %d).\n\n",i);
printf("L=\n");
mod2sparse_print(stdout,L);
printf("\nU=\n");
mod2sparse_print(stdout,U);
printf("\n");
printf("cols:");
for (j = 0; j<7; j++) printf(" %d",cols[j]);
printf("\n");
printf("rows:");
for (i = 0; i<6; i++) printf(" %d",rows[i]);
printf("\n\n");
fflush(stdout);
/* Compute and print product of L and U. Should match s1 for the
sub-matrix found. */
s2 = mod2sparse_allocate(6,7);
mod2sparse_multiply(L,U,s2);
printf("Product of L and U.\n\n");
mod2sparse_print(stdout,s2);
printf("\n");
fflush(stdout);
/* Solve system by forward and backward substitution. */
{ char x[6] = { 0, 1, 1, 0, 1, 0 };
static char y[5], z[7];
int i, r;
r = mod2sparse_forward_sub (L, rows, x, y);
printf(
"Solution of Ly=x with x from ( 0 1 1 0 1 0 ) according to rows selected.\n\n");
for (i = 0; i<5; i++) printf(" %d",y[i]);
printf("\n\nReturned value from forward_sub was %d\n\n",r);
fflush(stdout);
r = mod2sparse_backward_sub (U, cols, y, z);
printf("Solution of Uz=y.\n\n");
for (i = 0; i<7; i++) printf(" %d",z[i]);
printf("\n\nReturned value from backward_sub was %d\n\n",r);
fflush(stdout);
}
printf("\nPART 5:\n\n");
m1 = mod2sparse_allocate(4,4);
m2 = mod2sparse_allocate(4,4);
m3 = mod2sparse_allocate(4,4);
mod2sparse_insert(m1,0,3);
mod2sparse_insert(m1,1,1);
mod2sparse_insert(m1,2,2);
mod2sparse_insert(m1,3,0);
printf("Matrix m1:\n\n");
mod2sparse_print(stdout,m1);
printf("\n"); fflush(stdout);
printf("Matrix m2, copyrows of m1 in order 3,1,2,0 (should be identity)\n\n");
{ int rows[] = { 3, 1, 2, 0 };
mod2sparse_copyrows(m1,m2,rows);
}
mod2sparse_print(stdout,m2);
printf("\n"); fflush(stdout);
printf("Matrix m3, copycols of m1 in order 3,1,2,0 (should be identity)\n\n");
{ int cols[] = { 3, 1, 2, 0 };
mod2sparse_copycols(m1,m3,cols);
}
mod2sparse_print(stdout,m3);
printf("\n"); fflush(stdout);
printf("\nDONE WITH TESTS.\n");
exit(0);
}

1361
lib/ldpc/mod2sparse.c Executable file

File diff suppressed because it is too large Load Diff

147
lib/ldpc/mod2sparse.h Executable file
View File

@ -0,0 +1,147 @@
/* MOD2SPARSE.H - Interface to module for handling sparse mod2 matrices. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* This module implements operations on sparse matrices of mod2 elements
(bits, with addition and multiplication being done modulo 2).
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.
*/
/* DATA STRUCTURES USED TO STORE A SPARSE MATRIX. Non-zero entries (ie, 1s)
are represented by nodes that are doubly-linked both by row and by column,
with the headers for these lists being kept in arrays. Nodes are allocated
in blocks to reduce time and space overhead. Freed nodes are kept for
reuse in the same matrix, rather than being freed for other uses, except
that they are all freed when the matrix is cleared to all zeros by the
mod2sparse_clear procedure, or copied into by mod2sparse_copy.
Direct access to these structures should be avoided except in low-level
routines. Use the macros and procedures defined below instead. */
typedef struct mod2entry /* Structure representing a non-zero entry, or
the header for a row or column */
{
int row, col; /* Row and column indexes of this entry, starting
at 0, and with -1 for a row or column header */
struct mod2entry *left, *right, /* Pointers to entries adjacent in row */
*up, *down; /* and column, or to headers. Free */
/* entries are linked by 'left'. */
double pr, lr; /* Probability and likelihood ratios - not used */
/* by the mod2sparse module itself */
} mod2entry;
#define Mod2sparse_block 10 /* Number of entries to block together for
memory allocation */
typedef struct mod2block /* Block of entries allocated all at once */
{
struct mod2block *next; /* Next block that has been allocated */
mod2entry entry[Mod2sparse_block]; /* Entries in this block */
} mod2block;
typedef struct /* Representation of a sparse matrix */
{
int n_rows; /* Number of rows in the matrix */
int n_cols; /* Number of columns in the matrix */
mod2entry *rows; /* Pointer to array of row headers */
mod2entry *cols; /* Pointer to array of column headers */
mod2block *blocks; /* Blocks that have been allocated */
mod2entry *next_free; /* Next free entry */
} mod2sparse;
/* MACROS TO GET AT ELEMENTS OF A SPARSE MATRIX. The 'first', 'last', 'next',
and 'prev' macros traverse the elements in a row or column. Moving past
the first/last element gets one to a header element, which can be identified
using the 'at_end' macro. Macros also exist for finding out the row
and column of an entry, and for finding out the dimensions of a matrix. */
#define mod2sparse_first_in_row(m,i) ((m)->rows[i].right) /* Find the first */
#define mod2sparse_first_in_col(m,j) ((m)->cols[j].down) /* or last entry in */
#define mod2sparse_last_in_row(m,i) ((m)->rows[i].left) /* a row or column */
#define mod2sparse_last_in_col(m,j) ((m)->cols[j].up)
#define mod2sparse_next_in_row(e) ((e)->right) /* Move from one entry to */
#define mod2sparse_next_in_col(e) ((e)->down) /* another in any of the four */
#define mod2sparse_prev_in_row(e) ((e)->left) /* possible directions */
#define mod2sparse_prev_in_col(e) ((e)->up)
#define mod2sparse_at_end(e) ((e)->row<0) /* See if we've reached the end */
#define mod2sparse_row(e) ((e)->row) /* Find out the row or column index */
#define mod2sparse_col(e) ((e)->col) /* of an entry (indexes start at 0) */
#define mod2sparse_rows(m) ((m)->n_rows) /* Get the number of rows or columns*/
#define mod2sparse_cols(m) ((m)->n_cols) /* in a matrix */
/* POSSIBLE LU DECOMPOSITION STRATEGIES. For use with mod2sparse_decomp. */
typedef enum
{ Mod2sparse_first,
Mod2sparse_mincol,
Mod2sparse_minprod
} mod2sparse_strategy;
/* PROCEDURES TO MANIPULATE SPARSE MATRICES. */
mod2sparse *mod2sparse_allocate (int, int);
void mod2sparse_free (mod2sparse *);
void mod2sparse_clear (mod2sparse *);
void mod2sparse_copy (mod2sparse *, mod2sparse *);
void mod2sparse_copyrows (mod2sparse *, mod2sparse *, int *);
void mod2sparse_copycols (mod2sparse *, mod2sparse *, int *);
void mod2sparse_print (FILE *, mod2sparse *);
int mod2sparse_write (FILE *, mod2sparse *);
mod2sparse *mod2sparse_read (FILE *);
mod2entry *mod2sparse_find (mod2sparse *, int, int);
mod2entry *mod2sparse_insert (mod2sparse *, int, int);
void mod2sparse_delete (mod2sparse *, mod2entry *);
void mod2sparse_transpose (mod2sparse *, mod2sparse *);
void mod2sparse_add (mod2sparse *, mod2sparse *, mod2sparse *);
void mod2sparse_multiply (mod2sparse *, mod2sparse *, mod2sparse *);
void mod2sparse_mulvec (mod2sparse *, char *, char *);
int mod2sparse_equal (mod2sparse *, mod2sparse *);
int mod2sparse_count_row (mod2sparse *, int);
int mod2sparse_count_col (mod2sparse *, int);
void mod2sparse_add_row (mod2sparse *, int, mod2sparse *, int);
void mod2sparse_add_col (mod2sparse *, int, mod2sparse *, int);
int mod2sparse_decomp (mod2sparse *, int, mod2sparse *, mod2sparse *,
int *, int *, mod2sparse_strategy, int, int);
int mod2sparse_forward_sub (mod2sparse *, int *, char *, char *);
int mod2sparse_backward_sub (mod2sparse *, int *, char *, char *);

719
lib/ldpc/mod2sparse.html Executable file
View File

@ -0,0 +1,719 @@
<HTML><HEAD>
<TITLE> Sparse Modulo-2 Matrix Routines </TITLE>
</HEAD><BODY>
<H1> Sparse 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 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.
<P>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 <A
HREF="mod2dense.html">dense 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.
<A NAME="rep"><H2>Representation of sparse matrices</H2></A>
<P>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
<TT>mod2entry</TT>, 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 <B>pr</B> and <B>lr</B>, which are
of no significance to this module, but which are used by the routines
for <A HREF="decoding.html#prprp">decoding LDPC codes by probability
propagation</A>.
<P>The <TT>mod2sparse</TT> type represents a matrix. It records the
number of rows and columns in the matrix, and contains arrays of
pointers to the <TT>mod2entry</TT> structures for the first non-zero
element in each row and the first non-zero element in each column.
<P>Matrices must be created by the <A
HREF="#allocate"><TT>mod2sparse_allocate</TT></A> procedure, which
returns a pointer to a <TT>mod2sparse</TT> structure. When a matrix
is no longer needed, the space it occupies can be freed with <A
HREF="#free"><TT>mod2sparse_free</TT></A>. Elements within a matrix,
represented by <TT>mod2entry</TT> 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 <A
HREF="#free"><TT>mod2sparse_free</TT></A>, or cleared to all zeros,
with <A HREF="#clear"><TT>mod2sparse_clear</TT></A>, or used as
the result matrix for copying or arithmetic operations.
<P><B>Header files required</B>:
<TT>mod2sparse.h</TT>
<A NAME="dimension-sec">
<P><HR>
<CENTER><BIG>Dimension Macros</BIG></CENTER>
</A>
<HR>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 <A HREF="#allocate">mod2sparse_allocate</A>:
<BLOCKQUOTE><PRE>
mod2sparse_rows(m) /* Returns the number of rows in m */
mod2sparse_cols(m) /* Returns the number of columns in m */
</PRE></BLOCKQUOTE>
<A NAME="traversal-sec">
<P><HR>
<CENTER><BIG>Traversal Macros</BIG></CENTER>
</A>
<HR>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
<TT>mod2sparse_at_end</TT> macro. If one is already at this special
entry, moving further wraps one around to the first or last entry.
<P>The macros for finding the first or last entry in a row or column
take as their arguments a pointer to the matrix (<TT>mod2sparse
*</TT>) and a row or column index, starting at zero. The other macros
take as their arguments a pointer to an entry (<TT>mod2entry *</TT>)
within some matrix.
<BLOCKQUOTE><PRE>
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 */
</PRE></BLOCKQUOTE>
<A NAME="alloc-sec">
<P><HR>
<CENTER><BIG>Allocating and Freeing Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="allocate"><HR><B>mod2sparse_allocate</B>:
Allocate space for a sparse module-2 matrix.</A>
<BLOCKQUOTE><PRE>
mod2sparse *mod2sparse_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. The matrix will initially
be all zero.
<P>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>mod2sparse_free</TT></A> once it is no
longer in use.
<P><A NAME="free"><HR><B>mod2sparse_free</B>:
Free the space occupied by a sparse module-2 matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_free
( mod2sparse *m /* Pointer to matrix to free */
)
</PRE></BLOCKQUOTE>
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 when <A
HREF="#clear"><TT>mod2sparse_clear</TT></A> is called, or the matrix
is used as the destination for other operations.
<A NAME="copy-clear-sec">
<P><HR>
<CENTER><BIG>Copying and Clearing Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="clear"><HR><B>mod2sparse_clear</B>:
Set all elements of a matrix to zero.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_clear
( mod2sparse *m /* Pointer to matrix to clear */
)
</PRE></BLOCKQUOTE>
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,
use <A HREF="#free"><TT>mod2sparse_free</TT></A>.
<P><A NAME="copy"><HR><B>mod2sparse_copy</B>:
Copy the contents of one matrix to another.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_copy
( mod2sparse *m /* Pointer to matrix to copy from */
mod2sparse *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>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use (which may include being reused immediately for
the copies of the entries in <B>m</B>).
<P><A NAME="copyrows"><HR><B>mod2sparse_copyrows</B>:
Copy selected rows from one matrix to another.</A>
<BLOCKQUOTE><PRE>
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 */
)
</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>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use (which may include being reused immediately for
the copies of the entries in <B>m</B>).
<P><A NAME="copycols"><HR><B>mod2sparse_copycols</B>:
Copy selected columns from one matrix to another.</A>
<BLOCKQUOTE><PRE>
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 */
)
</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.
<P>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use (which may include being reused immediately for
the copies of the entries in <B>m</B>).
<A NAME="input-output-sec">
<P><HR>
<CENTER><BIG>Input and Output of Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="print"><HR><B>mod2sparse_print</B>:
Print a sparse modulo-2 matrix in human-readable form.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_print
( FILE *f, /* File to print to */
mod2sparse *m /* Pointer to matrix to print */
)
</PRE></BLOCKQUOTE>
The matrix is printed on standard output with one line of output per row,
of the form
<BLOCKQUOTE><PRE>
<I>row</I>: <I>col col col ...</I>
</PRE></BLOCKQUOTE>
where <I>row</I> is the index of the row, and the <I>col</I> entries are
the indexes of columns that are non-zero in that row. Row and column
indexes start at zero. Rows with no entries are printed with no column
indexes after the colon. The number of columns is not indicated in the output.
<P><A NAME="write"><HR><B>mod2sparse_write</B>:
Write a sparse modulo-2 matrix to a file in machine-readable format.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_write
( FILE *f, /* File to write data to */
mod2sparse *m /* Pointer to matrix write out */
)
</PRE></BLOCKQUOTE>
Writes a machine-readable representation the sparse 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 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 <A
HREF="#read"><TT>mod2sparse_read</TT></A> even on a machine with a
different byte-ordering.
<P>The value returned by <TT>mod2sparse_write</TT> is one if the
operation was successful, zero if an error of some sort occurred.
<P><A NAME="read"><HR><B>mod2sparse_read</B>:
Read a sparse modulo-2 matrix from a file.</A>
<BLOCKQUOTE><PRE>
mod2sparse *mod2sparse_read
( FILE *f, /* File to read data from */
)
</PRE></BLOCKQUOTE>
Reads a sparse 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>mod2sparse_read</TT> is called should have been written by <A
HREF="#write"><TT>mod2sparse_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>mod2sparse_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 Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="find"><HR><B>mod2sparse_find</B>:
Look for an entry at a given row and column.</A>
<BLOCKQUOTE><PRE>
mod2entry *mod2sparse_find
( mod2sparse *m, /* Matrix in which to look for entry */
int row, /* Row index (from 0) */
int col /* Column index (from 0) */
)
</PRE></BLOCKQUOTE>
Looks for an entry at the given row and column in the matrix <B>m</B>,
representing a non-zero element (ie, one with value 1). Returns a
pointer to this entry if it exists, or zero (a null pointer) if it
does not exist (ie, if that element of the matrix has value 0).
<P>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.
<P><A NAME="insert"><HR><B>mod2sparse_insert</B>:
Insert an entry at a given row and column.</A>
<BLOCKQUOTE><PRE>
mod2entry *mod2sparse_insert
( mod2sparse *m, /* Matrix in which to insert an entry */
int row, /* Row index (from 0) */
int col /* Column index (from 0) */
)
</PRE></BLOCKQUOTE>
Adds a new entry (representing an element with value 1) at the given
row and column position in the matrix <B>m</B>. If such an entry
already exists, nothing is done (this is not considered to be an
error). The new (or existing) entry is returned as the value of
this procedure.
<P>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.
<P>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.
<P><A NAME="delete"><HR><B>mod2sparse_delete</B>:
Delete an entry from a sparse modulo-2 matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_delete
( mod2sparse *m, /* Matrix in which to delete an entry */
mod2entry *e /* Entry to delete - MUST be in m */
)
</PRE></BLOCKQUOTE>
Deletes the entry <B>e</B> from the sparse matrix <B>m</B>, which
effectively sets to zero the element of the matrix that this entry
corresponded to. The entry is freed for future use in the same
matrix, but not (immediately, at least) for use in other matrices, or
generally. The pointer to this entry should not be used again once
it is deleted.
<P>The time required for this operation does not depend on how many
entries are currently in the matrix.
<P><B>Warning:</B> It is an error if <B>e</B> is not an entry of
<B>m</B>. This error is not currently diagnosed, but doing this may
cause serious problems, as it may lead later to entries for <B>m</B>
being erroneously freed when the matrix to which <B>e</B> properly
belongs is freed.
<A NAME="arith-sec">
<P><HR>
<CENTER><BIG>Sparse Modulo-2 Matrix Arithmetic and Comparison</BIG></CENTER>
</A>
<A NAME="transpose"><HR><B>mod2sparse_transpose</B>:
Compute the transpose of a sparse modulo-2 matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_transpose
( mod2sparse *m, /* Matrix to compute transpose of */
mod2sparse *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>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use.
<P><A NAME="add"><HR><B>mod2sparse_add</B>:
Add two sparse modulo-2 matrices.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_add
( mod2sparse *m1, /* Left operand of add */
mod2sparse *m2, /* Right operand of add */
mod2sparse *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>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use.
<P><A NAME="multiply"><HR><B>mod2sparse_multiply</B>:
Multiply two sparse modulo-2 matrices.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_multiply
( mod2sparse *m1, /* Left operand of multiply */
mod2sparse *m2, /* Right operand of multiply */
mod2sparse *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 space occupied by the previous non-zero entries of <B>r</B> is
freed for general use.
<P><A NAME="mulvec"><HR><B>mod2sparse_mulvec</B>:
Multiply a vector by a sparse modulo-2 matrix.</A>
<BLOCKQUOTE><PRE>
void 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 */
)
</PRE></BLOCKQUOTE>
Multiplies the vector <B>u</B> on the left by the sparse modulo-2
matrix <B>m</B>, storing the result in <B>v</B>. Both <B>u</B> and
<B>v</B> are modulo-2 vectors, but are stored unpacked, with one bit
per char. Any non-zero value in <B>u</B> is equivalent to '1'.
The vectors <B>u</B> and <B>v</B> must not overlap.
<P><A NAME="equal"><HR><B>mod2sparse_equal</B>:
Check whether two sparse modulo-2 matrices are equal.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_equal
( mod2sparse *m1, /* Pointers to the two matrices */
mod2sparse *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="row-col-ops-sec">
<P><HR>
<CENTER><BIG>Row/Column Operations on Sparse Modulo-2 Matrices</BIG>
</CENTER></A>
<A NAME="count_row"><HR><B>mod2sparse_count_row</B>:
Count the number of 1s in a row of a sparse matrix.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_count_row
( mod2sparse *m, /* Pointer to matrix */
int row /* Index of row to count (from 0) */
)
</PRE></BLOCKQUOTE>
Returns the number of 1s in the given row of the matrix, by counting
the number of entries in that row.
<P><A NAME="count_col"><HR><B>mod2sparse_count_col</B>:
Count the number of 1s in a column of a sparse matrix.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_count_col
( mod2sparse *m, /* Pointer to matrix */
int col /* Index of column to count (from 0) */
)
</PRE></BLOCKQUOTE>
Returns the number of 1s in the given column of the matrix, by counting
the number of entries in that column.
<P><A NAME="add_row"><HR><B>mod2sparse_add_row</B>:
Add a row to a row of a sparse matrix.</A>
<BLOCKQUOTE><PRE>
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 */
)
</PRE></BLOCKQUOTE>
Modifies the row with index <B>row1</B> in the matrix <B>m1</B> by
adding to that row the row with index <B>row2</B> in the matrix
<B>m2</B>. The matrix <B>m1</B> must have at least as many columns as
<B>m2</B>. This operation is performed by inserting entries into the
row of <B>m1</B> at positions where they exist in the row of <B>m2</B>
but not in the row of <B>m1</B>, and deleting entries in the row of
<B>m1</B> that exist in the same position in the row of <B>m2</B>.
The matrix <B>m2</B> is not modified.
<P><A NAME="add_col"><HR><B>mod2sparse_add_col</B>:
Add a column to a column of a sparse matrix.</A>
<BLOCKQUOTE><PRE>
void 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 */
)
</PRE></BLOCKQUOTE>
Modifies the column with index <B>col1</B> in the matrix <B>m1</B> by
adding to that column the column with index <B>col2</B> in the matrix
<B>m2</B>. The matrix <B>m1</B> must have at least as many rows as
<B>m2</B>. This operation is performed by inserting entries into the
column of <B>m1</B> at positions where they exist in the column of
<B>m2</B> but not in the column of <B>m1</B>, and deleting entries in
the column of <B>m1</B> that exist in the same position in the column
of <B>m2</B>. The matrix <B>m2</B> is not modified.
<A NAME="lu-decomp-sec">
<P><HR>
<CENTER><BIG>LU Decomposition of Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="decomp"><HR><B>mod2sparse_decomp</B>:
Find an LU decomposition of a sparse modulo-2 (sub-)matrix.</A>
<BLOCKQUOTE><PRE>
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 */
)
</PRE></BLOCKQUOTE>
<P>Takes as input a matrix, <B>A</B>, having <I>M</I> rows and
<I>N</I> columns, and an integer <I>K</I>. Finds an LU decomposition
of a <I>K</I> by <I>K</I> sub-matrix of <B>A</B>. The decomposition
is stored in the matrix <B>L</B>, with <I>M</I> rows and <I>K</I>
columns, and the matrix <B>U</B>, with <I>K</I> rows and <I>N</I>
columns. The product of <B>L</B> and <B>U</B> will be equal to the
<I>K</I> by <I>K</I> submatrix of <B>A</B> obtained by taking only
rows and columns that are given in the first <I>K</I> elements of the
<B>rows</B> and <B>cols</B> arrays, which are set by this procedure,
with this sub-matrix distributed over the original <I>M</I> rows and
<I>N</I> columns. Furthermore, the ordering of the row and column
indexes in these arrays will be set so that if the rows of <B>L</B>
and the columns of <B>U</B> were rearranged in this order, <B>L</B>
would be lower triangular, with zeros in rows past row <I>K</I>, and
<B>U</B> would be upper triangular, with zeros in columns past column
<I>K</I>. The <B>rows</B> array is <I>M</I> long, and the <B>cols</B>
array is <I>N</I> long. The elements in both arrays after the first
<I>K</I> contain the indexes of the rows and columns not selected to
be part of the sub-matrix of <B>A</B>, in arbitrary order.
<P>The rows and columns of <B>A</B> are selected in order to try to
make the LU decomposition as sparse as possible, using the strategy
identified by the <B>strategy</B>, <B>abandon_number</B>, and
<B>abandon_when</B> parameters. The possible strategies are
<TT>Mod2sparse_first</TT>, <TT>Mod2sparse_mincol</TT>, and
<TT>Mod2sparse_minprod</TT>. If <B>abandon_number</B> is greater than
zero, it is possible that the matrix will appear to have linearly
dependent rows when it actually does not. See the <A
HREF="sparse-LU.html">discussion of sparse LU decomposition
methods</A> for details about these strategies.
<P>If <B>A</B> is not of rank <I>K</I> or more, <B>L</B> will contain
some number less than <I>K</I> of non-zero columns, and <B>U</B> will
contain an equal number of non-zero rows. The entries in the
<B>rows</B> and <B>cols</B> 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 <I>K</I> by <I>K</I> sub-matrix of full rank was
found).
<P>The matrix <B>A</B> is not altered. The previous contents of
<B>L</B> and <B>U</B> are cleared.
<P><A NAME="forward_sub"><HR><B>mod2sparse_forward_sub</B>:
Solve a lower-triangular system by forward substitution.</A>
<BLOCKQUOTE><PRE>
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 */
)
</PRE></BLOCKQUOTE>
<P>Solves the system of equations <B>Ly</B>=<B>x</B> for <B>y</B> by
forward substitution, based on <B>L</B> being lower triangular after
its rows are reordered according to the given index array. The
vectors <B>x</B> and <B>y</B> are stored unpacked, one bit per
character. If <B>L</B> is <I>M</I> by <I>K</I>, then <B>x</B> should
be <I>M</I> long, but only the <I>K</I> bits indexed by <B>rows</B>
are looked at. The solution vector, <B>y</B>, must be <I>K</I> long.
Only <I>K</I> rows of <B>L</B> are used, as also determined by the
<I>K</I> indexes in the <B>rows</B> argument. If <B>rows</B> is null,
the first <I>K</I> rows of <B>L</B> and the first <I>K</I> elements of
<B>x</B> are used.
<P>If the matrix <B>L</B> does not have 1s on its diagonal (after row
rearrangement), there may be no solution, depending on what <B>x</B>
is. If no solution exists, this procedure returns zero, otherwise it
returns one. Any arbitrary bits in the solution are set to zero.
<P><A NAME="backward_sub"><HR><B>mod2sparse_backward_sub</B>:
Solve an upper-triangular system by backward substitution.</A>
<BLOCKQUOTE><PRE>
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 */
)
</PRE></BLOCKQUOTE>
<P>Solves <B>Uz</B>=<B>y</B> for <B>z</B> by backward substitution,
based on <B>U</B> being upper triangular after its columns are
reordered according to the given index array. The vectors <B>y</B>
and <B>z</B> are stored unpacked, one bit per character. If <B>U</B>
is <I>K</I> by <I>N</I>, then the solution vector, <I>z</I>, should be
<I>N</I> long, but only the <I>K</I> bits indexed by <B>cols</B> are
set. The vector <B>y</B> must be <I>K</I> long. Only <I>K</I> columns
of <B>U</B> are used, as also determined by the <I>K</I> indexes in
the <B>cols</B> argument. The other columns of <B>U</B> must be zero
(this is not checked, but is necessary for the method used to work).
If <B>cols</B> is null, the first <I>K</I> columns of <B>U</B> and the
first <I>K</I> elements of <B>z</B> are used.
<P>If the matrix <B>U</B> 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.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

125
lib/ldpc/modify.html Executable file
View File

@ -0,0 +1,125 @@
<HTML><HEAD>
<TITLE> Notes on Modifying the LDPC Programs </TITLE>
</HEAD><BODY>
<H1> Notes on Modifying the LDPC Programs </H1>
<P>Here are a few notes on how to modify the programs to add new types of
channel, new decoding procedures, etc. You should also look at the <A
HREF="modules.html">module documentation</A>.
<H2> Adding a new type of channel </H2>
<P>Channels are involved in two programs:
<A HREF="channel.html#transmit"><B>transmit</B></A> and
<A HREF="decoding.html#decode"><B>decode</B></A>.
Adding another type of memoryless channel should be straightforward.
Adding a channel with memory may involve more work. Here are the
steps needed if no major reorganizations are required:
<OL>
<LI> Decide on a syntax for specifying the new channel type and its
parameters, and on an internal name for the channel type. Add
the internal name as a possibility in the enumerated <TT>channel_type</TT>
declared in <A HREF="channel.h"><TT>channel.h</TT></A>. You
may also need to declare new global variables to store parameters of
the channel in <A HREF="channel.h"><TT>channel.h</TT></A> and
<A HREF="channel.c"><TT>channel.c</TT></A>.
<LI> Modify the <TT>channel_parse</TT> and
<TT>channel_usage</TT> procedures in
<A HREF="channel.c"><TT>channel.c</TT></A> to
parse the specification of the new channel and display an appropriate
usage message.
<LI> Decide on how the new channel's output is represented in a file
(eg, for an erasure channel, what the symbol for an erasure is), and
update <A HREF="transmit.c"><TT>transmit.c</TT></A> to write the
new channel's output for each transmitted bit, after randomly generating
any noise (see
the <A HREF="rand.html">documentation on random number generation</A>).
<LI> Modify <A HREF="decode.c"><TT>decode.c</TT></A> in three places to
accommodate the new channel. The three sections of code to modify
allocate space for data from the channel, read data from the channel,
and set likelihood ratios based on the data read. The setting of
likelihood ratios is based on the assumption that the channel is
memoryless (ie, data received for different bits is independent).
Adding a channel with memory would require changing this assumption,
which would involve modifications to the decoding procedures too.
<LI> Document the new channel type in <A HREF="channel.html">channel.html</A>
and <A HREF="decoding.html">decoding.html</A>.
</OL>
<H2> Adding a new decoding procedure </H2>
A new decoding method can be implemented as follows:
<OL>
<LI> Decide on a syntax for specifying the method and its parameters,
using the trailing arguments to the
<A HREF="decoding.html#decode"><TT>decode</TT></A> program. Pick an
internal name for the method, and add it as a possibility in the
enumerated <TT>decoding_method</TT> type in
<A HREF="dec.h"><TT>dec.h</TT></A>. You may also need to declare
new variables for the method's parameters in
<A HREF="dec.h"><TT>dec.h</TT></A> and <A HREF="dec.c"><TT>dec.c</TT></A>.
<LI> Modify the argument parsing code in
<A HREF="decode.c"><TT>decode.c</TT></A>
to handle specifications of the new method, and change the <TT>usage</TT>
procedure to display the syntax for specifying the new method.
<LI> Write a setup procedure for your decoding method, putting it in
<A HREF="dec.c"><TT>dec.c</TT></A>, with a declaration in
<A HREF="dec.h"><TT>dec.h</TT></A>. At a minimum, this procedure
should print headers for the table of detailed decoding information
when the <B>-T</B> option was specified.
<LI> Write a decode procedure implementing your method, putting it in
<A HREF="dec.c"><TT>dec.c</TT></A>, with a declaration in
<A HREF="dec.h"><TT>dec.h</TT></A>. This procedure should output
detailed trace information when the <B>-T</B> option was specified.
<LI> Modify <A HREF="decode.c"><TT>decode.c</TT></A> in the appropriate
places to call the setup procedure and the decode procedure you wrote.
<LI> Document the new decoding method in
<A HREF="decoding.html">decoding.html</A> and
<A HREF="decode-detail.html">decode-detail.html</A>.
</OL>
<H2> Adding a new method of making a low-density parity-check matrix </H2>
<P>The <A HREF="pchk.html#make-ldpc"><B>make-ldpc</B></A> program can be
changed to add a new method for generating a LDPC code by modifying
<A HREF="make-ldpc.c"><TT>make-ldpc.c</TT></A>. A radically different
method might better be implemented by writing a new program of similar
structure.
<H2> Adding a new encoding method </H2>
<P>A new heuristic for finding a sparse LU decomposition can be
implemented by changing <A HREF="make-gen.c">make-gen.c</A> to allow
the new heuristic to be specified on the command line, changing the <A
HREF="mod2sparse.html#decomp"><B>mod2sparse_decomp</B></A> procedure
in <A HREF="mod2sparse.c"><TT>mod2sparse.c</TT></A> to implement the
heuristic, and documenting the new heuristic in <A
HREF="encoding.html">encoding.html</A>, <A
HREF="sparse-LU.html">sparse-LU.html</A>, and <A
HREF="mod2sparse.html">mod2sparse.html</A>.
<P>To implement a completely new encoding method, you will first need
to define a new file format for a generator matrix, modify <A
HREF="make-gen.c">make-gen.c</A> appropriately to write out this new
format, and modify the <TT>read_gen</TT> procedure in <A
HREF="rcode.c"><TT>rcode.c</TT></A> to read this format. You will
need to implement the new method in a procedure in <A
HREF="enc.c">enc.c</A>, and modify <A HREF="encode.c">encode.c</A> so
that it will call this new procedure when the new method is used. The
<TT>enum_decode</TT> procedure in <A HREF="dec.c">dec.c</A> will also
need to be modified so it can call the new encoding method. Finally,
you should document the new method in <A
HREF="encoding.html">encoding.html</A>
<P>
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

89
lib/ldpc/modules.html Executable file
View File

@ -0,0 +1,89 @@
<HTML><HEAD>
<TITLE> Modules Used in LDPC Programs </TITLE>
</HEAD><BODY>
<H1> Modules Used in LDPC Programs </H1>
You may need to familiarize yourself with the modules documented here
in order to <A HREF="modify.html">modify the LDPC programs</A>.
These modules may also be useful for other purposes.
<P>Click on the title of a module below for general information, or on
specific routines for detailed documentation.
<P><A HREF="mod2dense.html">Dense modulo-2 matrix routines</A>:
<BLOCKQUOTE><PRE>
<A HREF="mod2dense.html#dimension-sec"><I>Dimension macros:</I> mod2dense_rows mod2dense_cols</A>
<I><A HREF="mod2dense.html#alloc-sec">Allocation:</A> <A HREF="mod2dense.html#copy-clear-sec">Copy/Clear:</A> <A HREF="mod2dense.html#input-output-sec">Input/Output:</A> <A HREF="mod2dense.html#elementary-sec">Elementary ops:</A></I>
<A HREF="mod2dense.html#allocate">mod2dense_allocate</A> <A HREF="mod2dense.html#clear">mod2dense_clear</A> <A HREF="mod2dense.html#print">mod2dense_print</A> <A HREF="mod2dense.html#get">mod2dense_get</A>
<A HREF="mod2dense.html#free">mod2dense_free</A> <A HREF="mod2dense.html#copy">mod2dense_copy</A> <A HREF="mod2dense.html#write">mod2dense_write</A> <A HREF="mod2dense.html#set">mod2dense_set</A>
<A HREF="mod2dense.html#copyrows">mod2dense_copyrows</A> <A HREF="mod2dense.html#read">mod2dense_read</A> <A HREF="mod2dense.html#flip">mod2dense_flip</A>
<A HREF="mod2dense.html#copycols">mod2dense_copycols</A>
<I><A HREF="mod2dense.html#arith-sec">Matrix arithmetic:</A> <A HREF="mod2dense.html#invert-sec">Matrix inversion:</A></I>
<A HREF="mod2dense.html#transpose">mod2dense_transpose</A> <A HREF="mod2dense.html#invert">mod2dense_invert</A>
<A HREF="mod2dense.html#add">mod2dense_add</A> <A HREF="mod2dense.html#forcibly_invert">mod2dense_forcibly_invert</A>
<A HREF="mod2dense.html#multiply">mod2dense_multiply</A> <A HREF="mod2dense.html#invert_selected">mod2dense_invert_selected</A>
<A HREF="mod2dense.html#equal">mod2dense_equal</A>
</PRE></BLOCKQUOTE>
<P><A HREF="mod2sparse.html">Sparse modulo-2 matrix routines</A>:
<BLOCKQUOTE><PRE>
<A HREF="mod2sparse.html#dimension-sec"><I>Dimension macros:</I> mod2sparse_rows mod2sparse_cols</A>
<A HREF="mod2sparse.html#traversal-sec"><I>Traversal macros:</I> mod2sparse_first_in_row mod2sparse_next_in_row ...</A>
<I><A HREF="mod2sparse.html#alloc-sec">Allocation:</A> <A HREF="mod2sparse.html#copy-clear-sec">Copy/Clear:</A> <A HREF="mod2sparse.html#input-output-sec">Input/Output:</A> <A HREF="mod2sparse.html#elementary-sec">Elementary ops:</A></I>
<A HREF="mod2sparse.html#allocate">mod2sparse_allocate</A> <A HREF="mod2sparse.html#clear">mod2sparse_clear</A> <A HREF="mod2sparse.html#print">mod2sparse_print</A> <A HREF="mod2sparse.html#find">mod2sparse_find</A>
<A HREF="mod2sparse.html#free">mod2sparse_free</A> <A HREF="mod2sparse.html#copy">mod2sparse_copy</A> <A HREF="mod2sparse.html#write">mod2sparse_write</A> <A HREF="mod2sparse.html#insert">mod2sparse_insert</A>
<A HREF="mod2sparse.html#copyrows">mod2sparse_copyrows</A> <A HREF="mod2sparse.html#read">mod2sparse_read</A> <A HREF="mod2sparse.html#delete">mod2sparse_delete</A>
<A HREF="mod2sparse.html#copycols">mod2sparse_copycols</A>
<I><A HREF="mod2sparse.html#arith-sec">Matrix arithmetic:</A> <A HREF="mod2sparse.html#row-col-ops-sec">Row/Column ops:</A> <A HREF="mod2sparse.html#lu-decomp-sec">LU decomposition:</A></I>
<A HREF="mod2sparse.html#transpose">mod2sparse_transpose</A> <A HREF="mod2sparse.html#count_row">mod2sparse_count_row</A> <A HREF="mod2sparse.html#decomp">mod2sparse_decomp</A>
<A HREF="mod2sparse.html#add">mod2sparse_add</A> <A HREF="mod2sparse.html#count_col">mod2sparse_count_col</A> <A HREF="mod2sparse.html#forward_sub">mod2sparse_forward_sub</A>
<A HREF="mod2sparse.html#multiply">mod2sparse_multiply</A> <A HREF="mod2sparse.html#add_row">mod2sparse_add_row</A> <A HREF="mod2sparse.html#backward_sub">mod2sparse_backward_sub</A>
<A HREF="mod2sparse.html#mulvec">mod2sparse_mulvec</A> <A HREF="mod2sparse.html#add_col">mod2sparse_add_col</A>
<A HREF="mod2sparse.html#equal">mod2sparse_equal</A>
</PRE>
<A HREF="sparse-LU.html">Discussion of sparse LU decomposition methods.</A>
</BLOCKQUOTE>
<P><A HREF="mod2convert.html">Modulo-2 matrix sparse/dense conversion</A>:
<BLOCKQUOTE><PRE>
<A HREF="mod2convert.html#sparse_to_dense">mod2sparse_to_dense</A>
<A HREF="mod2convert.html#dense_to_sparse">mod2dense_to_sparse</A>
</PRE></BLOCKQUOTE>
<P><A HREF="rand.html">Random variate generation routines</A>:
<BLOCKQUOTE><PRE>
<I><A HREF="rand.html#get-set-sec">Set/Get state:<A> <A HREF="rand.html#uniform-sec">Uniform:</A> <A HREF="rand.html#discrete-sec">Discrete:</A> <A HREF="rand.html#continuous-sec">Continuous:</A></I>
<A HREF="rand.html#seed">rand_seed</A> <A HREF="rand.html#uniform">rand_uniform</A> <A HREF="rand.html#int">rand_int</A> <A HREF="rand.html#gaussian">rand_gaussian</A>
<A HREF="rand.html#get_state">rand_get_state</A> <A HREF="rand.html#uniopen">rand_uniopen</A> <A HREF="rand.html#pickd">rand_pickd</A> <A HREF="rand.html#logistic">rand_logistic</A>
<A HREF="rand.html#use_state">rand_use_state</A> <A HREF="rand.html#pickf">rand_pickf</A> <A HREF="rand.html#cauchy">rand_cauchy</A>
<A HREF="rand.html#poisson">rand_poisson</A> <A HREF="rand.html#gamma">rand_gamma</A>
<A HREF="rand.html#permutation">rand_permutation</A> <A HREF="rand.html#exp">rand_exp</A>
<A HREF="rand.html#beta">rand_beta</A>
</PRE></BLOCKQUOTE>
<P>Each of the modules above has a test program, called
<TT><I>module</I>-test</TT>. These programs are compiled by the command
<BLOCKQUOTE><PRE>
make tests
</PRE></BLOCKQUOTE>
See the source files for these test programs for further information.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

50
lib/ldpc/open.c Executable file
View File

@ -0,0 +1,50 @@
/* OPEN.C - Routine for opening file that might be stdin/stdout. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "open.h"
/* OPEN A FILE THAT MIGHT BE STANDARD INPUT OR OUTPUT. If the file name
given is "-", this procedure just returns stdin or stdout, depending on
whether the mode is for reading or writing. Otherwise, fopen is called.
*/
FILE *open_file_std
( char *fname, /* Name of file to open, or "-" for stdin/stdout */
char *mode /* Mode for opening: eg, "r" or "w" */
)
{
if (strcmp(fname,"-")==0)
{ switch (mode[0])
{ case 'r':
{ return stdin;
}
case 'w':
{ return stdout;
}
default:
{ fprintf(stderr,"Bad mode passed to open_file_std: %s\n",mode);
exit(1);
}
}
}
else
{ return fopen(fname,mode);
}
}

16
lib/ldpc/open.h Executable file
View File

@ -0,0 +1,16 @@
/* OPEN.H - Interface to routine for opening file that might be stdin/stdout. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
FILE *open_file_std (char *, char *);

166
lib/ldpc/pchk-to-alist.c Executable file
View File

@ -0,0 +1,166 @@
/* ALIST-TO-PCHK.C - Convert a parity check matrix to alist format. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "alloc.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
void usage(void);
/* MAIN PROGRAM. */
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;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: pchk-to-alist [ -t ] [ -z ] pchk-file alist-file\n");
exit(1);
}

371
lib/ldpc/pchk.html Executable file
View File

@ -0,0 +1,371 @@
<HTML><HEAD>
<TITLE> Creating a Parity Check Matrix </TITLE>
</HEAD><BODY>
<H1> Creating a Parity Check Matrix </H1>
<P>This software deals only with linear block codes for binary (ie,
modulo-2, GF(2)) vectors. The set of valid codewords for a linear
code can be specified by giving a <I>parity check matrix</I>,
<B>H</B>, with <I>M</I> rows and <I>N</I> columns. The valid
codewords are the vectors, <B>x</B>, of length <I>N</I>, for which
<B>Hx</B>=<B>0</B>, where all arithmetic is done modulo-2. Each row
of <B>H</B> represents a parity check on a subset of the bits in
<B>x</B>; all these parity checks must be satisfied for <B>x</B> to be
a codeword. Note that the parity check matrix for a given code (ie,
for a given set of valid codewords) is not unique, even after
eliminating rows of <B>H</B> that are redundant because they are
linear combinations of other rows.
<P>This software stores parity check matrices in files in a sparse
format. These parity-check files are <I>not</I> human-readable
(except by using the <A HREF="#print-pchk"><TT>print-pchk</TT></A>
program). However, they <I>are</I> readable on a machine with a
different architecture than they were written on.
<P>Some LDPC software by David MacKay and others uses the
<A HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
format</A> for parity check matrices. Two programs for converting
between this format and the format for sparse parity check matrices
used by this software are provided.
<A NAME="ldpc"><H2>Methods for constructing LDPC codes</H2></A>
<P>This software is primarily intended for experimentation with Low
Density Parity Check (LDPC) codes. These codes can be constructed by
various methods, which generally involve some random selection of
where to put 1s in a parity check matrix. Any such method for
constructing LDPC codes will have the property that it produces parity
check matrices in which the number of 1s in a column is approximately
the same (perhaps on average) for any size parity check matrix. For a
given code rate, these matrices therefore become increasingly sparse
as the length of a codeword, and hence the number of parity checks,
increases.
<P>Many methods for constructing LDPC matrices are described in the
<A HREF="refs.html">references</A>. Two simple methods are currently
implemented by this software, both of which operate according to the
following scheme:
<OL>
<LI> Create a preliminary parity check matrix by one of the methods.
<LI> Add 1s to the parity check matrix in order to avoid rows that have no
1s in them, and hence are redundant, or which have only one 1 in them,
in which case the corresponding codeword bits will always be zero.
The places within such a row to add these 1s are selected randomly.
<LI> If the preliminary parity check matrix constructed in step (1) had
an even number of 1s in each column, add further 1s to avoid the problem
that this will cause the rows to add to zero, and hence at least
one check will be redundant. Up to two 1s are added (since it is also
undesirable for the sum of the rows to have only one 1 in it), at
positions selected randomly from the entire matrix. However, the
number of 1s to add in this step is reduced by the number already added
in step (2). (Note that although redundant checks are not disastrous,
they are better avoided; see the discussion of <A HREF="dep-H.html">linear
dependence in parity check matrices</A>.)
<LI> If requested, try to eliminate
situations where a pair of columns both have 1s in a particular pair of
rows, which correspond to cycles of length four in the factor graph of
the parity check matrix. When such a situation is detected, one of the
1s involved is moved randomly within its column. This continues until
no such situations remain, or until 10 passes over all columns have
failed to eliminate all such situations.
</OL>
<P>The <I>evencol</I> method is the simplest way of performing step
(1) of the above procedure. For each column of the parity check
matrix, independently, it places a specified number of 1s in positions
selected uniformly at random, with the only constraint being that
these 1s be in distinct rows. Note that despite the name, the columns
do not have to have the same number of 1s - a distribution over
several values for the number of 1s in a column can be specified
instead. Such codes with different-weight columns are sometimes
better than codes in which every column has the same weight.
<P>The <I>evenboth</I> method also puts a specified number of 1s in
each column, but it tries as well to keep the numbers of 1s in the
rows approximately the same. Initially, it creates indicators for all
the 1s that will be required, and assigns these 1s to rows as evenly
as it can, favouring earlier rows if an exactly even split is not
possible. It then assigns 1s to successive columns by selecting
randomly, without replacement, from this initial supply of 1s, subject
only to the constraint that the 1s assigned to a column must be in
distinct rows. If at some point it is impossible to put the required
number of 1s in a column by picking from the 1s remaining, a 1 is set
in that column without reference to other columns, creating a possible
unevenness.
<P>Note that regardless of how evenly 1s are distributed in the
preliminary parity check matrix created in step (1), steps (2) and (3)
can make the numbers of 1s in the both rows and columns be uneven, and
step (4), if done, can make the numbers of 1s in rows be uneven.
<P><A NAME="make-pchk"><HR><B>make-pchk</B>: Make a parity check
matrix by explicit specification.
<BLOCKQUOTE><PRE>
make-pchk <I>pchk-file n-checks n-bits row</I>:<I>col ...</I>
</PRE></BLOCKQUOTE>
<P>Creates a file named <TT><I>pchk-file</I></TT> in
which it stores a parity check matrix with <TT><I>n-checks</I></TT>
rows and <TT><I>n-bits</I></TT> columns. This parity check matrix
consists of all 0s except for 1s at the <I>row</I>:<I>col</I>
positions listed. Rows and columns are numbered starting at zero.
This program is intended primarily for testing and demonstration
purposes.
<P><B>Example:</B> The well-known Hamming code with codewords of
length <I>N</I>=7 and with <I>M</I>=3 parity checks can be can be
created as follows:
<UL><PRE>
<LI>make-pchk ham7.pchk 3 7 0:0 0:3 0:4 0:5 1:1 1:3 1:4 1:6 2:2 2:4 2:5 2:6
</PRE></UL>
<P><A NAME="alist-to-pchk"><HR><B>alist-to-pchk</B>: Convert a parity
check matrix from alist format to the sparse matrix format used by
this software.
<BLOCKQUOTE><PRE>
alist-to-pchk [ -t ] <I>alist-file pchk-file</I>
</PRE></BLOCKQUOTE>
<P>Converts a parity check matrix in
<A HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
format</A> stored in the file named <TT><I>alist-file</I></TT> to
the sparse matrix format used by this software, storing it in the
file named <TT><I>pchk-file</I></TT>.
<P>If the <B>-t</B> option is given, the transpose of the parity check
matrix in <TT><I>alist-file</I></TT> is stored in the
<TT><I>pchk-file</I></TT>.
<P>Any zeros indexes in the alist file are ignored, so that alist files
with zero padding (as required in the specification) are accepted,
but files without this zero padding are also accepted. Newlines
are ignored by <TT>alist-to-pchk</TT>, so no error is reported if
the set of indexes in a row or column description are not those
on a single line.
<P><A NAME="pchk-to-alist"><HR><B>pchk-to-alist</B>: Convert a parity
check matrix to alist format.
<BLOCKQUOTE><PRE>
pchk-to-alist [ -t ] [ -z ] <I>pchk-file alist-file</I>
</PRE></BLOCKQUOTE>
<P>Converts a parity check matrix stored in the sparse matrix format
used by this software, in the file named <TT><I>pchk-file</I></TT>, to
the <A
HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
format</A>, storing it in the file named <TT><I>alist-file</I></TT>.
<P>If the <B>-t</B> option is given, the transpose of the parity check
matrix is converted to alist format.
<P>If the number of 1s is not
the same for each row or each column, the alist format specification
says that the list of indexes of 1s for each row or column should
be padded with zeros to the maximum number of indexes. By default,
<TT>pchk-to-alist</TT> does this, but output of these 0s can be
suppressed by specifying the <B>-z</B> option. (The <TT>alist-to-pchk</TT>
program will accept alist files produced with or without the <B>-z</B>
option.)
<P><A NAME="print-pchk"><HR><B>print-pchk</B>: Print a parity check matrix.
<BLOCKQUOTE><PRE>
print-pchk [ -d ] [ -t ] <I>pchk-file</I>
</PRE></BLOCKQUOTE>
<P>Prints a human-readable representation of the parity check matrix stored
in <TT><I>pchk-file</I></TT>.
The <B>-d</B> option causes the matrix to be printed in a dense
format, even though parity check matrices are always stored in the
file in a sparse format. If the <B>-t</B> option is present, what is
printed is the transpose of the parity check matrix.
<P>The sparse display format consists of one line for every row of the
matrix, consisting of the row number, a colon, and the column numbers
at which 1s are located (possibly none). Row and columns numbers
start at zero. No attempt is made to wrap long lines.
<P>The dense display is the obvious array of 0s and 1s. Long lines
are not wrapped.
<P><B>Example</B>: The parity check matrix for the Hamming code created
by the example for <A HREF="#make-pchk"><TT>make-pchk</TT></A> would print
as follows:
<UL><PRE>
<LI>print-pchk ham7.pchk
Parity check matrix in ham7.pchk (sparse format):
0: 0 3 4 5
1: 1 3 4 6
2: 2 4 5 6
<LI>print-pchk -d ham7.pchk
Parity check matrix in ham7.pchk (dense format):
1 0 0 1 1 1 0
0 1 0 1 1 0 1
0 0 1 0 1 1 1
</PRE></UL>
<P><A NAME="make-ldpc"><HR><B>make-ldpc</B>: Make a low density parity
check matrix, by random generation.
<BLOCKQUOTE><PRE>
make-ldpc <I>pchk-file n-checks n-bits seed method</I>
</PRE>
<BLOCKQUOTE>
where <TT><I>method</I></TT> is one of the following:
<BLOCKQUOTE><PRE>
evencol <I>checks-per-col</I> [ no4cycle ]
evencol <I>checks-distribution</I> [ no4cycle ]
evenboth <I>checks-per-col</I> [ no4cycle ]
evenboth <I>checks-distribution</I> [ no4cycle ]
</PRE></BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P>Creates a Low Density Parity Check matrix with
<TT><I>n-checks</I></TT> rows and <TT><I>n-bits</I></TT> columns. The
parity check matrix will be generated pseudo-randomly by the indicated
method, using a pseudo-random number stream determined by <TT><I>seed</I></TT>.
The actual random number seed used is 10 times <TT><I>seed</I></TT> plus 1,
so as to avoid using the same stream as any of the other programs.
<P>Two methods are currently available for creating the LDPC matrix,
specified by <TT>evencol</TT> or <TT>evenboth</TT>. Both methods
produce a matrix in which the number of 1s in each column is
approximately <TT><I>checks-per-col</I></TT>, or varies from column
to column according the the <TT><I>checks-distribution</I></TT>.
The <TT>evenboth</TT> method also tries to make the number of checks per row be
approximately uniform; if this is not achieved, a message saying that
how many bits were placed unevenly is displayed on standard error.
<P>For both methods, the <TT>no4cycle</TT> option will cause cycles of
length four in the factor graph representation of the code to be
eliminated (if possible). A message is displayed on standard error if
this is not achieved.
<P>A <TT><I>checks-distribution</I></TT> has the form
<BLOCKQUOTE><PRE>
<I>prop</I>x<I>count</I>/<I>prop</I>x<I>count</I>/...
</PRE></BLOCKQUOTE>
Here, <TT><I>prop</I></TT> is a proportion of columns that have the
associated <TT><I>count</I></TT>. The proportions need not sum to one,
since they will be automatically normalized. For example, <TT>0.3x4/0.2x5</TT>
specifies that 60% of the columns will contain four 1s and 40% will
contain five 1s.
<P>See the <A HREF="#ldpc">discussion above</A> for more details
on how these methods construct LDPC matrices.
<P><B>Example 1:</B> The <TT>make-ldpc</TT> command below creates
a 20 by 40 low density parity check matrix with three 1s per
column and six 1s per row, using random seed 1. The matrix
is then printed in sparse format
using <A HREF="#print-pchk">print-pchk</A>.
<UL><PRE>
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 3
<LI>print-pchk ldpc.pchk
Parity check matrix in ldpc.pchk (sparse format):
0: 10 14 18 27 38 39
1: 2 3 5 11 27 30
2: 15 19 20 21 24 26
3: 2 4 25 28 32 38
4: 7 9 12 22 33 34
5: 5 6 21 22 26 32
6: 1 4 13 24 25 28
7: 1 14 28 29 30 36
8: 11 13 22 23 32 37
9: 6 8 13 20 31 33
10: 0 3 24 29 31 38
11: 7 12 15 16 17 23
12: 3 16 29 34 35 39
13: 0 8 10 18 36 37
14: 6 11 18 20 35 39
15: 0 7 14 16 25 37
16: 2 4 9 19 30 31
17: 5 9 10 17 19 23
18: 8 15 17 21 26 27
19: 1 12 33 34 35 36
</PRE></UL>
<P><B>Example 2:</B> The two <TT>make-ldpc</TT> commands
below both create a 20 by 40 low density parity check matrix with 30%
of columns with two 1s, 60% of columns with three 1s, and 10% of
columns with seven 1s. The transpose of the parity check matrix
is then printed in sparse format.
<UL><PRE>
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 0.3x2/0.6x3/0.1x7
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 3x2/6x3/1x7
<LI>print-pchk -t ldpc.pchk
Transpose of parity check matrix in ldpc.pchk (sparse format):
0: 13 16
1: 9 18
2: 1 10
3: 3 15
4: 4 14
5: 14 17
6: 4 5
7: 1 8
8: 0 4
9: 9 14
10: 5 8
11: 6 16
12: 2 12 19
13: 3 17 18
14: 2 16 17
15: 2 11 18
16: 12 13 19
17: 7 13 18
18: 2 5 11
19: 10 12 14
20: 1 8 16
21: 10 18 19
22: 3 6 17
23: 7 11 12
24: 1 2 19
25: 0 6 7
26: 5 8 15
27: 1 4 7
28: 6 13 19
29: 3 4 11
30: 3 8 17
31: 4 5 9
32: 0 10 15
33: 7 11 13
34: 8 12 19
35: 0 2 10
36: 0 5 9 11 15 17 18
37: 0 1 2 6 7 14 16
38: 0 1 3 9 12 13 15
39: 3 6 9 10 14 15 16
</PRE></UL>
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

139
lib/ldpc/print-gen.c Executable file
View File

@ -0,0 +1,139 @@
/* PRINT-CODE.C - Print a Low Density Parity Check code's matrices. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "rand.h"
#include "alloc.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *gen_file;
int dprint;
int i, j;
dprint = 0;
if (argc>1 && strcmp(argv[1],"-d")==0)
{ dprint = 1;
argc -= 1;
argv += 1;
}
if (!(gen_file = argv[1]) || argv[2])
{ usage();
}
read_gen(gen_file,0,1);
switch (type)
{
case 's':
{
printf("\nGenerator matrix in %s (sparse representation):\n\n",gen_file);
printf("Column order (message bits at end):\n");
for (j = 0; j<N; j++)
{ if (j%20==0) printf("\n");
printf(" %3d",cols[j]);
}
printf("\n\n");
printf("Row order:\n");
for (i = 0; i<M; i++)
{ if (i%20==0) printf("\n");
printf(" %3d",rows[i]);
}
printf("\n\n");
if (dprint)
{ mod2dense *Ld, *Ud;
Ld = mod2dense_allocate(M,M);
Ud = mod2dense_allocate(M,N);
mod2sparse_to_dense(L,Ld);
mod2sparse_to_dense(U,Ud);
printf("L:\n\n");
mod2dense_print(stdout,Ld);
printf("\n");
printf("U:\n\n");
mod2dense_print(stdout,Ud);
printf("\n");
}
else
{ printf("L:\n\n");
mod2sparse_print(stdout,L);
printf("\n");
printf("U:\n\n");
mod2sparse_print(stdout,U);
printf("\n");
}
break;
}
case 'd': case 'm':
{
if (type=='d')
{ printf("\nGenerator matrix in %s (dense representation):\n\n",gen_file);
}
if (type=='m')
{ printf("\nGenerator matrix in %s (mixed representation):\n\n",gen_file);
}
printf("Column order (message bits at end):\n");
for (j = 0; j<N; j++)
{ if (j%20==0) printf("\n");
printf(" %3d",cols[j]);
}
printf("\n\n");
printf (type=='d' ? "Inv(A) X B:\n\n" : "Inv(A):\n\n");
mod2dense_print(stdout,G);
printf("\n");
break;
}
default:
{ fprintf(stderr,"Unknown type of generator matrix file\n");
exit(1);
}
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: print-gen [ -d ] gen-file\n");
exit(1);
}

114
lib/ldpc/print-pchk.c Executable file
View File

@ -0,0 +1,114 @@
/* PRINT-PCHK.C - Print the parity check matrix for a code. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "rand.h"
#include "alloc.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
mod2dense *D;
mod2sparse *T;
char *pchk_file;
int dprint, trans;
dprint = 0;
trans = 0;
for (;;)
{
if (argc>1 && strcmp(argv[1],"-d")==0)
{ dprint = 1;
argc -= 1;
argv += 1;
}
else if (argc>1 && strcmp(argv[1],"-t")==0)
{ trans = 1;
argc -= 1;
argv += 1;
}
else
{ break;
}
}
if (!(pchk_file = argv[1]) || argv[2])
{ usage();
}
read_pchk(pchk_file);
if (trans)
{ T = mod2sparse_allocate(N,M);
mod2sparse_transpose(H,T);
}
if (dprint)
{ if (trans)
{ D = mod2dense_allocate(N,M);
mod2sparse_to_dense(T,D);
printf("\nTranspose of parity check matrix in %s (dense format):\n\n",
pchk_file);
mod2dense_print(stdout,D);
}
else
{ D = mod2dense_allocate(M,N);
mod2sparse_to_dense(H,D);
printf("\nParity check matrix in %s (dense format):\n\n",pchk_file);
mod2dense_print(stdout,D);
}
}
else /* sparse */
{ if (trans)
{ printf("\nTranspose of parity check matrix in %s (sparse format):\n\n",
pchk_file);
mod2sparse_print(stdout,T);
}
else
{ printf("\nParity check matrix in %s (sparse format):\n\n",pchk_file);
mod2sparse_print(stdout,H);
}
}
printf("\n");
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: print-pchk [ -d ] [ -t ] pchk-file\n");
exit(1);
}

80
lib/ldpc/progs.html Executable file
View File

@ -0,0 +1,80 @@
<HTML><HEAD>
<TITLE> Programs for Low Density Parity Check Codes </TITLE>
</HEAD><BODY>
<H1> Programs for Low Density Parity Check Codes </H1>
Programs are available for creating LDPC codes, encoding messages,
simulating transmission through a channel, and decoding the received
message. There are links here to the general documentation on each of
these operations, and to the detailed documentation on the relevant
programs.
<P>The programs names below are followed by the form of arguments they
take; a similar usage message is displayed when a program is run with
no arguments. In these descriptions, things to be entered literally
are in roman font, descriptions of something to be supplied are in
italic. Arguments in square brackets are optional. A vertical bar
separates alternatives. Dots represent indefinite repetition.
<P>Many of the arguments are file names, which can be a dash ("-") in
order to specify that standard input or standard output is to be used.
(However, you can't use standard input or output for more than one thing.)
<P>Click on a main title below for general information on that aspect
of the software, or on the name of a program for detailed information.
<P><A HREF="pchk.html">Creating a parity check matrix for a code</A>:
<BLOCKQUOTE><PRE>
<A HREF="pchk.html#make-pchk">make-pchk</A> <I>pchk-file n-checks n-bits row</I>:<I>col ...</I>
<A HREF="pchk.html#alist-to-pchk">alist-to-pchk</A> [ -t ] <I>alist-file pchk-file</I>
<A HREF="pchk.html#pchk-to-alist">pchk-to-alist</A> [ -t ] [ -z ] <I>pchk-file alist-file</I>
<A HREF="pchk.html#print-pchk">print-pchk</A> [ -d ] [ -t ] <I>pchk-file</I>
<A HREF="pchk.html#make-ldpc">make-ldpc</A> <I>pchk-file n-checks n-bits seed method</I>
</PRE></BLOCKQUOTE>
<P><A HREF="encoding.html">Encoding message blocks as codewords</A>:
<BLOCKQUOTE><PRE>
<A HREF="encoding.html#make-gen">make-gen</A> <I>pchk-file gen-file method</I>
<A HREF="encoding.html#print-gen">print-gen</A> [ -d ] <I>gen-file</I>
<A HREF="encoding.html#encode">encode</A> [ -f ] <I>pchk-file gen-file source-file encoded-file</I>
</PRE></BLOCKQUOTE>
<P><A HREF="channel.html">Transmitting bits through a simulated channel:</A>
<BLOCKQUOTE><PRE>
<A HREF="channel.html#transmit">transmit</A> <I>encoded-file</I>|<I>n-zeros received-file seed channel</I>
</PRE></BLOCKQUOTE>
<P><A HREF="decoding.html">Decoding received blocks:</A>
<BLOCKQUOTE><PRE>
<A HREF="decoding.html#decode">decode</A> [ -f ] [ -t | -T ] <I>pchk-file received-file decoded-file</I> [ <I>bp-file</I> ] <I>channel method</I>
<A HREF="decoding.html#extract">extract</A> <I>gen-file decoded-file extracted-file</I>
</PRE></BLOCKQUOTE>
<P><A HREF="support.html">Support programs:</A>
<BLOCKQUOTE><PRE>
<A HREF="support.html#rand-src">rand-src</A> <I>source-file seed n-bits</I>
<A HREF="support.html#verify">verify</A> [ -t ] <I>pchk-file decoded-file</I> [ <I>gen-file</I> [ <I>source-file</I> ] ]
</PRE></BLOCKQUOTE>
See also the discussions of <A HREF="dep-H.html">linear dependence in
parity check matrices</A> and of <A HREF="sparse-LU.html">sparse LU
decomposition methods</A>, and the <A HREF="examples.html">examples
of program usage</A>.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

86
lib/ldpc/rand-src.c Executable file
View File

@ -0,0 +1,86 @@
/* RAND-SRC.C - Generate random message bits. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "open.h"
#include "rand.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
int seed, bs, nb;
char *file, *n_bits;
char junk;
int i, j;
FILE *f;
if (!(file = argv[1])
|| !argv[2] || sscanf(argv[2],"%d%c",&seed,&junk)!=1
|| !(n_bits = argv[3])
|| argv[4])
{ usage();
}
if (sscanf(n_bits,"%d%c",&nb,&junk)==1)
{ if (nb<=0) usage();
bs = 1;
}
else if (sscanf(n_bits,"%dx%d%c",&bs,&nb,&junk)==2)
{ if (nb<=0 || bs<=0) usage();
}
else
{ usage();
}
f = open_file_std(file,"w");
if (f==NULL)
{ fprintf(stderr,"Can't create source file: %s\n",file);
exit(1);
}
rand_seed(10*seed+2);
for (i = 0; i<nb; i++)
{ for (j = 0; j<bs; j++)
{ fprintf(f,"%d",rand_int(2));
}
fprintf(f,"\n");
}
if (ferror(f) || fclose(f)!=0)
{ fprintf(stderr,"Error writing random source blocks to %s\n",file);
exit(1);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: rand-src source-file seed n-bits\n");
exit(1);
}

266
lib/ldpc/rand-test.c Executable file
View File

@ -0,0 +1,266 @@
/* RAND-TEST.C - Program to test random number generators. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* Usage:
rand-test seed generator { parameters } / sample-size [ low high bins ]
Using the seed given, tests the random number generator identified by
the second argument, for the parameter values specified. The possible
generators and required parameters are as follows:
uniform Uniform from [0,1)
uniopen Uniform from (0,1)
int n Uniform from the set { 0, 1, ..., (n-1) }
gaussian From Gaussian with mean zero and unit variance
exp From exponential with mean one
cauchy From Cauchy centred at zero with unit width
gamma alpha From Gamma with shape parameter (and mean) alpha
beta a b From Beta with parameters a and b
The size of the sample to use is also specified. The program reports
the mean and variance of the sample. A histogram is also printed if a
low and high range and number of bins are for it are specified.
These tests are not really adequate to detect subtle forms of bias due
to use of pseudo-random numbers, but are hopefully good enough to find
most programming errors.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "rand.h"
#define Max_bins 1000 /* Maximum number of histogram bins */
static void usage (void);
/* MAIN PROGRAM. */
main
( int argc,
char **argv
)
{
int seed, sample_size, bins, np;
double low, high;
char *generator;
double p1, p2;
double mean, variance;
double tmean, tvariance;
int undef_mean, undef_variance;
int count[Max_bins];
int under, over;
char **ap;
double x;
int i, n;
bins = 0;
if (argc<5) usage();
if ((seed = atoi(argv[1]))==0 && strcmp(argv[1],"0")!=0) usage();
generator = argv[2];
if (strcmp(generator,"uniform")==0) np = 0;
else if (strcmp(generator,"uniopen")==0) np = 0;
else if (strcmp(generator,"int")==0) np = 1;
else if (strcmp(generator,"poisson")==0) np = 1;
else if (strcmp(generator,"gaussian")==0) np = 0;
else if (strcmp(generator,"exp")==0) np = 0;
else if (strcmp(generator,"cauchy")==0) np = 0;
else if (strcmp(generator,"gamma")==0) np = 1;
else if (strcmp(generator,"beta")==0) np = 2;
else
{ fprintf(stderr,"Unknown generator: %s\n",generator);
exit(1);
}
ap = argv+3;
if (np>0)
{ if (*ap==0 || (p1 = atof(*ap++))<=0) usage();
}
if (np>1)
{ if (*ap==0 || (p2 = atof(*ap++))<=0) usage();
}
if (*ap==0 || strcmp(*ap++,"/")!=0) usage();
if (*ap==0 || (sample_size = atoi(*ap++))<=0) usage();
if (*ap!=0)
{ low = atof(*ap++);
if (*ap==0) usage();
high = atof(*ap++);
if (high<=low) usage();
if (*ap==0 || (bins = atoi(*ap++))<=0) usage();
if (bins>Max_bins)
{ fprintf(stderr,"Too many histogram bins\n");
exit(1);
}
}
if (*ap!=0) usage();
printf("\nTest of %s(",generator);
if (np>0) printf("%.4f",p1);
if (np>1) printf(",%.4f",p2);
printf(") generator using sample of size %d with seed %d\n\n",
sample_size, seed);
undef_mean = undef_variance = 0;
if (strcmp(generator,"uniform")==0)
{ tmean = 0.5;
tvariance = 1.0/12.0;
}
else if (strcmp(generator,"uniopen")==0)
{ tmean = 0.5;
tvariance = 1.0/12.0;
}
else if (strcmp(generator,"int")==0)
{ tmean = (p1-1)/2;
tvariance = p1*p1/3.0 - p1/2.0 + 1/6.0 - tmean*tmean;
}
else if (strcmp(generator,"poisson")==0)
{ tmean = p1;
tvariance = p1;
}
else if (strcmp(generator,"gaussian")==0)
{ tmean = 0;
tvariance = 1;
}
else if (strcmp(generator,"exp")==0)
{ tmean = 1;
tvariance = 1;
}
else if (strcmp(generator,"cauchy")==0)
{ undef_mean = 1;
undef_variance = 1;
}
else if (strcmp(generator,"gamma")==0)
{ tmean = p1;
tvariance = p1;
}
else if (strcmp(generator,"beta")==0)
{ tmean = p1 / (p1+p2);
tvariance = (p1*p2) / ((p1+p2)*(p1+p2)*(p1+p2+1));
}
else
{ abort();
}
mean = 0;
variance = 0;
if (bins>0)
{ for (i = 0; i<bins; i++) count[i] = 0;
under = over = 0;
}
rand_seed(seed);
for (n = 0; n<sample_size; n++)
{
if (strcmp(generator,"uniform")==0) x = rand_uniform();
else if (strcmp(generator,"uniopen")==0) x = rand_uniopen();
else if (strcmp(generator,"int")==0) x = rand_int((int)p1);
else if (strcmp(generator,"poisson")==0) x = rand_poisson(p1);
else if (strcmp(generator,"gaussian")==0) x = rand_gaussian();
else if (strcmp(generator,"exp")==0) x = rand_exp();
else if (strcmp(generator,"cauchy")==0) x = rand_cauchy();
else if (strcmp(generator,"gamma")==0) x = rand_gamma(p1);
else if (strcmp(generator,"beta")==0) x = rand_beta(p1,p2);
else abort();
mean += x;
variance += x*x;
if (bins>0)
{ if (x<low)
{ under += 1;
}
else
{ i = (int) ((x-low)/((high-low)/bins));
if (i>=bins)
{ over += 1;
}
else
{ count[i] += 1;
}
}
}
}
mean /= sample_size;
variance /= sample_size;
variance -= mean*mean;
printf("Sample mean: %.4f",mean);
if (undef_mean)
{ printf(" (true value: undefined)\n");
}
else
{ printf(" (true value: %.4f)\n",tmean);
}
printf("Sample variance: %.4f",variance);
if (undef_variance)
{ printf(" (true value: undefined)\n");
}
else
{ printf(" (true value: %.4f)\n",tvariance);
}
printf("\n");
if (bins!=0)
{ printf("Histogram:\n");
printf(" under : %8d %.5f\n\n",
under, (double)under / sample_size);
for (i = 0; i<bins; i++)
{ printf(" %10.4f - %10.4f : %8d %.5f\n",
i*(high-low)/bins + low, (i+1)*(high-low)/bins + low,
count[i], (double)count[i] / sample_size);
}
printf("\n over : %8d %.5f\n",
over, (double)over / sample_size);
printf("\n");
}
exit(0);
}
/* PRINT USAGE MESSAGE AND EXIT. */
static void usage (void)
{
fprintf(stderr,
"Usage: rand-test seed generator { parameters } / sample-size [ low high bins ]\n");
exit(1);
}

567
lib/ldpc/rand.c Executable file
View File

@ -0,0 +1,567 @@
/* RAND.C - Random number generation module. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* Random generation routines at the end of this file are taken from the
GNU C library, see the copyright notice there. */
/* NOTE: See rand.html for documentation on these procedures. */
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "rand.h"
static long int this_nrand48 (unsigned short int [3]);
/* Local version of nrand48 */
/* This module uses the 'this_nrand48' pseudo-random number generator from the
GNU C library, included below, but renamed to 'this_nrand48'. The
output of this generator is combined with a file of real random numbers.
Many of the methods used in this module may be found in the following
reference:
Devroye, L. (1986) Non-Uniform Random Variate Generation,
New York: Springer-Verlag.
The methods used here are not necessarily the fastest available. They're
selected to be reasonably fast while also being easy to write.
*/
/* CONSTANT PI. Defined here if not in <math.h>. */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* TABLES OF REAL RANDOM NUMBERS. A file of 100000 real random numbers
(NOT pseudo-random) is used in conjunction with pseudo-random numbers
for extra insurance. These are employed in the form of five tables
of 5000 32-bit integers.
The file must be located at the path given by RAND_FILE, which should
be defined on the "cc" command line. */
#define Table_size 5000 /* Number of words in each table */
static int rn[N_tables][Table_size]; /* Random number tables */
/* STATE OF RANDOM NUMBER GENERATOR. */
static int initialized = 0; /* Has module been initialized? */
static rand_state state0; /* Default state structure */
static rand_state *state; /* Pointer to current state */
/* INITIALIZE MODULE. Sets things up using the default state structure,
set as if rand_seed had been called with a seed of one. */
static void initialize (void)
{
int i, j, k, w;
char b;
FILE *f;
if (!initialized)
{
f = fopen(RAND_FILE,"rb");
if (f==NULL)
{ fprintf(stderr,"Can't open file of random numbers (%s)\n",RAND_FILE);
exit(1);
}
for (i = 0; i<N_tables; i++)
{ for (j = 0; j<Table_size; j++)
{ w = 0;
for (k = 0; k<4; k++)
{ if (fread(&b,1,1,f)!=1)
{ fprintf(stderr,"Error reading file of random numbers (%s)\n",
RAND_FILE);
exit(1);
}
w = (w<<8) | (b&0xff);
}
rn[i][j] = w;
}
}
state = &state0;
initialized = 1;
rand_seed(1);
}
}
/* SET CURRENT STATE ACCORDING TO SEED. */
void rand_seed
( int seed
)
{
int j;
if (!initialized) initialize();
state->seed = seed;
state->state48[0] = seed>>16;
state->state48[1] = seed&0xffff;
state->state48[2] = rn[0][(seed&0x7fffffff)%Table_size];
for (j = 0; j<N_tables; j++)
{ state->ptr[j] = seed%Table_size;
seed /= Table_size;
}
}
/* SET STATE STRUCTURE TO USE. */
void rand_use_state
( rand_state *st
)
{
if (!initialized) initialize();
state = st;
}
/* RETURN POINTER TO CURRENT STATE. */
rand_state *rand_get_state (void)
{
if (!initialized) initialize();
return state;
}
/* GENERATE RANDOM 31-BIT INTEGER. Not really meant for use outside this
module. */
int rand_word(void)
{
int v;
int j;
if (!initialized) initialize();
v = this_nrand48(state->state48);
for (j = 0; j<N_tables; j++)
{ v ^= rn[j][state->ptr[j]];
}
for (j = 0; j<N_tables && state->ptr[j]==Table_size-1; j++)
{ state->ptr[j] = 0;
}
if (j<N_tables)
{ state->ptr[j] += 1;
}
return v & 0x7fffffff;
}
/* GENERATE UNIFORMLY FROM [0,1). */
double rand_uniform (void)
{
return (double)rand_word() / (1.0+(double)0x7fffffff);
}
/* GENERATE UNIFORMLY FORM (0,1). */
double rand_uniopen (void)
{
return (0.5+(double)rand_word()) / (1.0+(double)0x7fffffff);
}
/* GENERATE RANDOM INTEGER FROM 0, 1, ..., (n-1). */
int rand_int
( int n
)
{
return (int) (n * rand_uniform());
}
/* GENERATE INTEGER FROM 0, 1, ..., (n-1), WITH GIVEN DISTRIBUTION. */
int rand_pickd
( double *p,
int n
)
{
double t, r;
int i;
t = 0;
for (i = 0; i<n; i++)
{ if (p[i]<0) abort();
t += p[i];
}
if (t<=0) abort();
r = t * rand_uniform();
for (i = 0; i<n; i++)
{ r -= p[i];
if (r<0) return i;
}
/* Return value with non-zero probability if we get here due to roundoff. */
for (i = 0; i<n; i++)
{ if (p[i]>0) return i;
}
abort();
}
/* SAME PROCEDURE AS ABOVE, BUT WITH FLOAT ARGUMENT. */
int rand_pickf
( float *p,
int n
)
{
double t, r;
int i;
t = 0;
for (i = 0; i<n; i++)
{ if (p[i]<=0) abort();
t += p[i];
}
if (t<=0) abort();
r = t * rand_uniform();
for (i = 0; i<n; i++)
{ r -= p[i];
if (r<0) return i;
}
/* Return value with non-zero probability if we get here due to roundoff. */
for (i = 0; i<n; i++)
{ if (p[i]>0) return i;
}
abort();
}
/* GENERATE RANDOM PERMUTATION OF INTEGERS FROM 1 TO N. */
void rand_permutation
( int *perm, /* Place to store permutation */
int n /* Number of integers to permute */
)
{
int i, j, t;
for (i = 0; i<n; i++)
{ perm[i] = i+1;
}
for (i = 0; i<n; i++)
{ t = perm[i];
j = i + rand_int(n-i);
perm[i] = perm[j];
perm[j] = t;
}
}
/* POISSON GENERATOR. The method used is simple, but not very fast. See
Devroye, p. 503. Very large means are done using Gaussian approximation. */
int rand_poisson
( double lambda
)
{ int v;
if (lambda>10000)
{ v = (int) (lambda + rand_gaussian()*sqrt(lambda) + 0.5);
}
else
{ v = 0;
for (;;)
{ lambda -= rand_exp();
if (lambda<=0) break;
v += 1;
}
}
return v;
}
/* GAUSSIAN GENERATOR. Done by using the Box-Muller method, but only one
of the variates is retained (using both would require saving more state).
See Devroye, p. 235.
As written, should never deliver exactly zero, which may sometimes be
helpful. */
double rand_gaussian (void)
{
double a, b;
a = rand_uniform();
b = rand_uniopen();
return cos(2.0*M_PI*a) * sqrt(-2.0*log(b));
}
/* EXPONENTIAL GENERATOR. See Devroye, p. 29. Written so as to never
return exactly zero. */
double rand_exp (void)
{
return -log(rand_uniopen());
}
/* LOGISTIC GENERATOR. Just inverts the CDF. */
double rand_logistic (void)
{ double u;
u = rand_uniopen();
return log(u/(1-u));
}
/* CAUCHY GENERATOR. See Devroye, p. 29. */
double rand_cauchy (void)
{
return tan (M_PI * (rand_uniopen()-0.5));
}
/* GAMMA GENERATOR. Generates a positive real number, r, with density
proportional to r^(a-1) * exp(-r). See Devroye, p. 410 and p. 420.
Things are fiddled to avoid ever returning a value that is very near
zero. */
double rand_gamma
( double a
)
{
double b, c, X, Y, Z, U, V, W;
if (a<0.00001)
{ X = a;
}
else if (a<=1)
{
U = rand_uniopen();
X = rand_gamma(1+a) * pow(U,1/a);
}
else if (a<1.00001)
{ X = rand_exp();
}
else
{
b = a-1;
c = 3*a - 0.75;
for (;;)
{
U = rand_uniopen();
V = rand_uniopen();
W = U*(1-U);
Y = sqrt(c/W) * (U-0.5);
X = b+Y;
if (X>=0)
{
Z = 64*W*W*W*V*V;
if (Z <= 1 - 2*Y*Y/X || log(Z) <= 2 * (b*log(X/b) - Y)) break;
}
}
}
return X<1e-30 && X<a ? (a<1e-30 ? a : 1e-30) : X;
}
/* BETA GENERATOR. Generates a real number, r, in (0,1), with density
proportional to r^(a-1) * (1-r)^(b-1). Things are fiddled to avoid
the end-points, and to make the procedure symmetric between a and b. */
double rand_beta
( double a,
double b
)
{
double x, y, r;
do
{ x = rand_gamma(a);
y = rand_gamma(b);
r = 1.0 + x/(x+y);
r = r - 1.0;
} while (r<=0.0 || r>=1.0);
return r;
}
/* ROUTINES FROM THE GNU C LIBRARY. These were modified to extract
only the routines used here, and to allow them to be included in
this module without any possible name conflict with other modules.
Inclusion here ensures that these routines are always available, and
operate in exactly the same way on all systems. The routines as copied
below are still easily useable by other programs by simply inserting
this source code into an appropriate source file.
The following is the copyright notice for these routines:
Copyright (C) 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
The GNU Lesser General Public License is included with these source
files in the file LGPL. */
#include <errno.h>
#include <limits.h>
#include <sys/types.h>
struct this_drand48_data
{
unsigned short int x[3]; /* Current state. */
unsigned short int old_x[3]; /* Old state. */
unsigned short int c; /* Additive const. in congruential formula. */
unsigned short int init; /* Flag for initializing. */
unsigned long long int a; /* Factor in congruential formula. */
};
/* Global state for non-reentrant functions. */
struct this_drand48_data libc_this_drand48_data;
static int this_nrand48_r (unsigned short int xsubi[3],
struct this_drand48_data *buffer,
long int *result);
/* Internal function to compute next state of the generator. */
static int this_drand48_iterate (unsigned short int xsubi[3],
struct this_drand48_data *buffer);
static long int this_nrand48 (xsubi)
unsigned short int xsubi[3];
{
long int result;
(void) this_nrand48_r (xsubi, &libc_this_drand48_data, &result);
return result;
}
static int this_nrand48_r (xsubi, buffer, result)
unsigned short int xsubi[3];
struct this_drand48_data *buffer;
long int *result;
{
/* Compute next state. */
if (this_drand48_iterate (xsubi, buffer) < 0)
return -1;
/* Store the result. */
if (sizeof (unsigned short int) == 2)
*result = xsubi[2] << 15 | xsubi[1] >> 1;
else
*result = xsubi[2] >> 1;
return 0;
}
static int this_drand48_iterate (xsubi, buffer)
unsigned short int xsubi[3];
struct this_drand48_data *buffer;
{
uint64_t X;
uint64_t result;
/* Initialize buffer, if not yet done. */
if (!buffer->init)
{
buffer->a = 0x5deece66dull;
buffer->c = 0xb;
buffer->init = 1;
}
/* Do the real work. We choose a data type which contains at least
48 bits. Because we compute the modulus it does not care how
many bits really are computed. */
X = (uint64_t) xsubi[2] << 32 | (uint32_t) xsubi[1] << 16 | xsubi[0];
result = X * buffer->a + buffer->c;
xsubi[0] = result & 0xffff;
xsubi[1] = (result >> 16) & 0xffff;
xsubi[2] = (result >> 32) & 0xffff;
return 0;
}

54
lib/ldpc/rand.h Executable file
View File

@ -0,0 +1,54 @@
/* RAND.H - Interface to random number generation procedures. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* STATE OF RANDOM NUMBER GENERATOR. */
#define N_tables 5 /* Number of tables of real random numbers */
typedef struct
{ int seed; /* Seed state derives from */
int ptr[N_tables]; /* Pointers for tables of real random numbers */
unsigned short state48[3]; /* State of 'rand48' pseudo-random generator */
} rand_state;
/* BASIC PSEUDO-RANDOM GENERATION PROCEDURES. */
void rand_seed (int); /* Initialize current state structure by seed */
void rand_use_state (rand_state *); /* Start using given state structure */
rand_state *rand_get_state (void); /* Return pointer to current state */
int rand_word (void); /* Generate random 31-bit positive integer */
/* GENERATORS FOR VARIOUS DISTRIBUTIONS. */
double rand_uniform (void); /* Uniform from [0,1) */
double rand_uniopen (void); /* Uniform from (0,1) */
int rand_int (int); /* Uniform from 0, 1, ... (n-1) */
int rand_pickd (double *, int); /* From 0 ... (n-1), with given distribution */
int rand_pickf (float *, int); /* Same as above, but with floats */
void rand_permutation (int *, int); /* Random permutation */
int rand_poisson (double); /* Poisson with given mean */
double rand_gaussian (void); /* Gaussian with mean zero and unit variance */
double rand_logistic (void); /* Logistic centred at zero with unit width */
double rand_cauchy (void); /* Cauchy centred at zero with unit width */
double rand_gamma (double); /* Gamma with given shape parameter */
double rand_exp (void); /* Exponential with mean one */
double rand_beta (double, double); /* Beta with given parameters */

306
lib/ldpc/rand.html Executable file
View File

@ -0,0 +1,306 @@
<HTML><HEAD>
<TITLE> Random Variate Generation Routines </TITLE>
</HEAD><BODY>
<H1> Random Variate Generation Routines </H1>
<P>This module provides facilities for basic pseudo-random number generation,
and for generation of random variates from various common distributions.
<P>All the random generation procedures use the same underlying
"stream" of random numbers. This stream is generated using the
<TT>nrand48</TT> pseudo-random generation procedure found on most Unix
systems, with the output being combined with a limited supply of real
random numbers from the file "randfile" in the source
directory for this software, in order to reduce the chances that the
pseudo-random numbers aren't random enough.
<P>A pseudo-random number stream is determined by an integer
<I>seed</I>, which is typically set by the user for each experimental
run (eg, to 1, 2, 3, etc. for successive runs). The state of the
random number stream can be saved in a structure of type
<TT>rand_state</TT>, and later restored. For example, the state could
be saved in a file at the end of a run, and restored if it is later
decided that the run should be continued for longer.
<P>The methods for generating random variates from various distributions
are mostly taken from the following reference:
<BLOCKQUOTE>
Devroye, L. (1986) <I>Non-Uniform Random Variate Generation</I>,
New York: Springer-Verlag.
</BLOCKQUOTE>
The methods used here are not necessarily the fastest available. They were
selected to be reasonably fast while also being easy to write.
<P><B>Header file required</B>: <TT>rand.h</TT>
<A NAME="get-set-sec">
<P><HR>
<CENTER><BIG>Setting and saving the state</BIG></CENTER>
</A>
<A NAME="seed"><HR><B>rand_seed</B>:
Set the state from an integer seed.</A>
<BLOCKQUOTE><PRE>
void rand_seed
( int seed; /* Seed to set state based on */
)
</PRE></BLOCKQUOTE>
<P>Sets the random number generator to a state that is determined from
the integer <TT>seed</TT>. Setting the seed the same on two occasions,
and then calling exactly the same sequence of random generation
procedures, should produce exactly the same sequence of random
variates. (Note: this may not be true, however, if computers with
different architectures are used on the two occasions.)
<P>Sequential seeds should produce streams that are pretty much
independent (unlike the situation for some pseudo-random number
generators). Setting the seed randomly according to the time or day,
or some such, without recording what it was, is <B>not</B>
recommended, since the results are then not reproducible.
<P><A NAME="get_state"><HR><B>rand_get_state</B>:
Get a pointer to the current state.</A>
<BLOCKQUOTE><PRE>
rand_state *rand_get_state (void)
</PRE></BLOCKQUOTE>
Returns a pointer to the current state of the random number generator,
which is a structure of type <TT>rand_state</TT>. The only use for this
pointer is to use it to save a copy of the current state someplace.
<P><A NAME="use_state"><HR><B>rand_use_state</B>:
Set the state to use from now on.</A>
<BLOCKQUOTE><PRE>
void rand_use_state
( rand_state *state /* Pointer to a previously saved state */
)
</PRE></BLOCKQUOTE>
Sets the random number generator to the state pointed to by the argument.
This state must be valid. The only way to get a valid state is by using
<TT>rand_get_state</TT>.
<A NAME="uniform-sec">
<P><HR>
<CENTER><BIG>Generating uniform random variates</BIG></CENTER>
</A>
<A NAME="uniform"><HR><B>rand_uniform</B>:
Generate uniformly from [0,1).</A>
<BLOCKQUOTE><PRE>
double rand_uniform (void)
</PRE></BLOCKQUOTE>
Returns a random number that is uniformly distributed between 0 and 1,
with a value of exactly 0 being possible, but with a value of exactly 1
not being possible.
<P><A NAME="uniopen"><HR><B>rand_uniopen</B>:
Generate uniformly from (0,1).</A>
<BLOCKQUOTE><PRE>
double rand_uniopen (void)
</PRE></BLOCKQUOTE>
Returns a random number that is uniformly distributed between 0 and 1,
with neither a value of exactly 0 nor a value of exactly 1
being possible.
<A NAME="discrete-sec">
<P><HR>
<CENTER><BIG>Generating discrete random variates</BIG></CENTER>
</A>
<A NAME="int"><HR><B>rand_int</B>:
Pick an integer uniformly from <I>0</I> to <I>n-1</I>.</A>
<BLOCKQUOTE><PRE>
int rand_int
( int n /* Number of integers (from 0) to pick from */
)
</PRE></BLOCKQUOTE>
<P>Randomly picks an integer from the set { <TT>0, 1, ..., n-1</TT> },
with each integer being equally probable. The probabilities may
become somewhat unequal, however, if <TT>n</TT> is very large,
approaching 2<SUP><SMALL>31</SMALL></SUP>.
<P><A NAME="pickd"><HR><B>rand_pickd</B>: Pick an integer from <I>0</I>
to <I>n-1</I> with given probabilities (as doubles).</A>
<BLOCKQUOTE><PRE>
int rand_pickd
( double *p, /* Array of probabilities, of length n */
int n /* Number of integers (from 0) to pick from */
)
</PRE></BLOCKQUOTE>
<P>Randomly picks an integer from the set { <TT>0, 1, ..., n-1</TT> },
with probabilities given by the array of double-precision numbers
passed as the first argument. These numbers need not sum to one, but they
must be non-negative, and must not all be zero. The actual
probabilities used are obtained by dividing each number in this array
by the sum of all the numbers.
<P>If one of the probabilities is exactly zero, it is guaranteed that
the corresponding integer will not be picked.
<P><A NAME="pickf"><HR><B>rand_pickf</B>: Pick an integer from <I>0</I>
to <I>n-1</I> with given probabilities (as floats).</A>
<BLOCKQUOTE><PRE>
int rand_pickf
( float *p, /* Array of probabilities, of length n */
int n /* Number of integers (from 0) to pick from */
)
</PRE></BLOCKQUOTE>
<P>This procedure is the same as <A HREF="#pickd"><TT>rand_pickd</TT></A>
except that the array giving the probabilities is an array of single-precision
floating point numbers, rather than double-precision.
<A NAME="poisson"><HR><B>rand_poisson</B>:
Generate a non-negative integer from a Poisson distribution.</A>
<BLOCKQUOTE><PRE>
int rand_poisson
( double lambda /* Mean of the Poisson distribution */
)
</PRE></BLOCKQUOTE>
<P>Generates a non-negative integer from the Poisson distribution with mean
<tt>lambda</tt>.
<P><A NAME="permutation"><HR><B>rand_permutation</B>: Generate a random
permutation of integers from <i>1</i> to <i>n</i>.</A>
<BLOCKQUOTE><PRE>
int rand_permutation
( int *perm, /* Place to store the permutation */
int n /* Number of integers to permute */
)
</PRE></BLOCKQUOTE>
<P>Stores a random permutation of the integers from <i>1</i> to <i>n</i> in the
array perm, which must be at least <i>n</i> long. All permutations are
equally likely.
<A NAME="continuous-sec">
<P><HR>
<CENTER><BIG>Generating continuous random variates</BIG></CENTER>
</A>
<A NAME="gaussian"><HR><B>rand_gaussian</B>:
Generate a standard Gaussian (normal) random variate.</A>
<BLOCKQUOTE><PRE>
double rand_gaussian (void)
</PRE></BLOCKQUOTE>
<P>Generates a random value drawn from the Gaussian (normal) distribution
with mean zero and standard deviation one, whose density function is
proportional to exp(-<I>x<SUP><SMALL>2</SMALL></SUP></I>/2), with <I>x</I>
being any real value.
<A NAME="logistic"><HR><B>rand_logistic</B>:
Generate a logistic random variate.</A>
<BLOCKQUOTE><PRE>
double rand_logistic (void)
</PRE></BLOCKQUOTE>
<P>Generates a random value drawn from the logistic distribution with
location parameter zero and width parameter one, whose density
function is proportional to
exp(-<I>x</I>) / [1 + exp(-<I>x</I>)]<SUP><SMALL>2</SMALL></SUP>,
with <I>x</I> being any real value.
<P><A NAME="cauchy"><HR><B>rand_cauchy</B>:
Generate a Cauchy random variate.</A>
<BLOCKQUOTE><PRE>
double rand_cauchy (void)
</PRE></BLOCKQUOTE>
<P>Generates a random value drawn from the Cauchy distribution with centre
at zero and width one, whose density function is proportional to
1 / (1+<I>x<SUP><SMALL>2</SMALL></SUP></I>), with <I>x</I> being any real value.
<P><A NAME="gamma"><HR><B>rand_gamma</B>:
Generate a gamma-distributed random variate.</A>
<BLOCKQUOTE><PRE>
double rand_gamma
( double A /* Shape parameter */
)
</PRE></BLOCKQUOTE>
<P>Generates a random value drawn from the gamma distribution with
positive shape parameter <I>A</I>, whose density function is proportional
to <I>x<SUP><SMALL>A-1</SMALL></SUP></I> exp(-<I>x</I>), with <I>x</I>
being any positive real. This procedure will never return a value that is
exactly zero.
<P><A NAME="exp"><HR><B>rand_exp</B>:
Generate an exponentially-distributed random variate.</A>
<BLOCKQUOTE><PRE>
double rand_exponential (void)
</PRE></BLOCKQUOTE>
<P>Generates a random value drawn from the exponential distribution with
mean one, whose density function is exp(-<I>x</I>), with <I>x</I> being
any positive real. This procedure will never return a value that is
exactly zero.
<P>Note: This is a common special case of the gamma distribution.
<P><A NAME="beta"><HR><B>rand_beta</B>:
Generate a beta-distributed random variate.</A>
<BLOCKQUOTE><PRE>
double rand_beta
( double A, /* Parameters of distribution */
double B
)
</PRE></BLOCKQUOTE>
<P>Generates a random value drawn from the beta distribution with positive
parameters <I>A</I> and <I>B</I>, whose density function is proportional
to <I>x<SUP><SMALL>A-1</SMALL></SUP>(1-x)<SUP><SMALL>B-1</SMALL></SUP></I>,
with <I>x</I> being any real in the interval (0,1). This procedure
will never return a value that is exactly zero or exactly one.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

BIN
lib/ldpc/randfile Executable file

Binary file not shown.

200
lib/ldpc/rcode.c Executable file
View File

@ -0,0 +1,200 @@
/* RCODE.C - Procedures to read parity check and generator matrices. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "alloc.h"
#include "intio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
/* VARIABLES DECLARED IN RCODE.H. These global variables are set to
representations of the parity check and generator matrices by read_pchk
and read_gen. */
mod2sparse *H; /* Parity check matrix */
int M; /* Number of rows in parity check matrix */
int N; /* Number of columns in parity check matrix */
char type; /* Type of generator matrix representation (s/d/m) */
int *cols; /* Ordering of columns in generator matrix */
mod2sparse *L, *U; /* Sparse LU decomposition, if type=='s' */
int *rows; /* Ordering of rows in generator matrix (type 's') */
mod2dense *G; /* Dense or mixed representation of generator matrix,
if type=='d' or type=='m' */
/* READ PARITY CHECK MATRIX. Sets the H, M, and N global variables. If an
error is encountered, a message is displayed on standard error, and the
program is terminated. */
void read_pchk
( char *pchk_file
)
{
FILE *f;
f = open_file_std(pchk_file,"rb");
if (f==NULL)
{ fprintf(stderr,"Can't open parity check file: %s\n",pchk_file);
exit(1);
}
if (intio_read(f)!=('P'<<8)+0x80)
{ fprintf(stderr,"File %s doesn't contain a parity check matrix\n",pchk_file);
exit(1);
}
H = mod2sparse_read(f);
if (H==0)
{ fprintf(stderr,"Error reading parity check matrix from %s\n",pchk_file);
exit(1);
}
M = mod2sparse_rows(H);
N = mod2sparse_cols(H);
fclose(f);
}
/* READ GENERATOR MATRIX. The parity check matrix must have already been
read, unless the last argument is set to 1. The generator matrix must be
compatible with the parity check matrix, if it has been read. If the
second argument is 1, only the column ordering (the last N-M of which are
the indexes of the message bits) is read, into the 'cols' global variable.
Otherwise, everything is read, into the global variables appropriate
to the representation. The 'type' global variable is set to a letter
indicating which represention is used.
If an error is encountered, a message is displayed on standard error,
and the program is terminated. */
void read_gen
( char *gen_file, /* Name of generator matrix file */
int cols_only, /* Read only column ordering? */
int no_pchk_file /* No parity check file used? */
)
{
int M2, N2;
FILE *f;
int i;
f = open_file_std(gen_file,"rb");
if (f==NULL)
{ fprintf(stderr,"Can't open generator matrix file: %s\n",gen_file);
exit(1);
}
if (intio_read(f)!=('G'<<8)+0x80)
{ fprintf(stderr,"File %s doesn't contain a generator matrix\n",gen_file);
exit(1);
}
if (fread (&type, 1, 1, f) != 1) goto error;
M2 = intio_read(f);
N2 = intio_read(f);
if (feof(f) || ferror(f)) goto error;
if (no_pchk_file)
{ M = M2;
N = N2;
}
else
{ if (M2!=M || N2!=N)
{ fprintf(stderr,
"Generator matrix and parity-check matrix are incompatible\n");
exit(1);
}
}
cols = chk_alloc (N, sizeof *cols);
rows = chk_alloc (M, sizeof *rows);
for (i = 0; i<N; i++)
{ cols[i] = intio_read(f);
if (feof(f) || ferror(f)) goto error;
}
if (!cols_only)
{
switch (type)
{
case 's':
{
for (i = 0; i<M; i++)
{ rows[i] = intio_read(f);
if (feof(f) || ferror(f)) goto error;
}
if ((L = mod2sparse_read(f)) == 0) goto error;
if ((U = mod2sparse_read(f)) == 0) goto error;
if (mod2sparse_rows(L)!=M || mod2sparse_cols(L)!=M) goto garbled;
if (mod2sparse_rows(U)!=M || mod2sparse_cols(U)<M) goto garbled;
break;
}
case 'd':
{
if ((G = mod2dense_read(f)) == 0) goto error;
if (mod2dense_rows(G)!=M || mod2dense_cols(G)!=N-M) goto garbled;
break;
}
case 'm':
{
if ((G = mod2dense_read(f)) == 0) goto error;
if (mod2dense_rows(G)!=M || mod2dense_cols(G)!=M) goto garbled;
break;
}
default:
{ fprintf(stderr,
"Unknown type of generator matrix in file %s\n",gen_file);
exit(1);
}
}
}
fclose(f);
return;
error:
fprintf(stderr,"Error reading generator matrix from file %s\n",gen_file);
exit(1);
garbled:
fprintf(stderr,"Garbled generator matrix in file %s\n",gen_file);
exit(1);
}

37
lib/ldpc/rcode.h Executable file
View File

@ -0,0 +1,37 @@
/* RCODE.H - Parity chk and gen matrix storage, and procedures to read them.*/
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* VARIABLES HOLDING DATA READ. These are declared for real in rcode.c. */
extern mod2sparse *H; /* Parity check matrix */
extern int M; /* Number of rows in parity check matrix */
extern int N; /* Number of columns in parity check matrix */
extern char type; /* Type of generator matrix representation */
extern int *cols; /* Ordering of columns in generator matrix */
extern mod2sparse *L, *U; /* Sparse LU decomposition, if type=='s' */
extern int *rows; /* Ordering of rows in generator matrix (type 's') */
extern mod2dense *G; /* Dense or mixed representation of generator matrix,
if type=='d' or type=='m' */
/* PROCEDURES FOR READING DATA. */
void read_pchk (char *);
void read_gen (char *, int, int);

58
lib/ldpc/refs.html Executable file
View File

@ -0,0 +1,58 @@
<HTML><HEAD>
<TITLE> References on Low Density Parity Check Codes </TITLE>
</HEAD><BODY>
<H1> References on Low Density Parity Check Codes </H1>
Robert Gallager's original work on low density parity check codes was published
as the following book, based his doctoral dissertation, and a related paper:
<BLOCKQUOTE>
<P>Gallager, R. G. (1963) <I>Low Density Parity Check Codes</I>,
Cambridge, MA: MIT Press.
<P>Gallager, R. G. (1962) ``Low-density parity-check codes'', <I>IRE
Transactions on Information Theory</I>, vol. IT-8, pp. 21-28.
</BLOCKQUOTE>
More recent work on these codes by David MacKay and myself was published
as follows:
<BLOCKQUOTE>
<P>MacKay, D. J. C. and Neal, R. M. (1996) ``Near Shannon limit performance
of low density parity check codes'', <I>Electronics Letters</I>,
vol. 32, pp. 1645-1646. Reprinted with printing errors corrected
in vol. 33, pp. 457-458.
<P>MacKay, D. J. C. (1999) ``Good error-correcting codes based on very
sparse matrices'', <I>IEEE Transactions on Information Theory</I>,
vol. 45, pp. 399-431.
</BLOCKQUOTE>
The decoding algorithms described in the above references can visualized
in terms of a ``factor graph'' representation of the code, as described
in the following paper:
<BLOCKQUOTE>
<P>Kschischang, F. R., Frey, B. J., and Loeliger, H.-A. (1998) ``Factor graphs
and the sum-product algorithm'', <I>IEEE Transactions on Information
Theory</I>, vol. 47, pp. 498-519.
</BLOCKQUOTE>
I presented the application of sparse matrix techniques to encoding of
LDPC codes at the IMA workshop on Codes, Systems and Graphical Models,
Minneapolis, 1999. You can view the slides of this talk <A
HREF="sparse-encode.pdf">here</A>. <B>Note</B>: Due to a bug in the
program I used then, the results shown for the minimal product heuristic in
these slides are somewhat worse than the actual performance. For instance,
the number of bit operations per check bit for for <I>M</I>=3200 with
3 checks per bit is actually around 12.7, not the value around 17 shown
on one of the slides.
<P>Text and references to many more recent and classical papers can be
obtained via the <A HREF="http://www.ima.umn.edu/csg/">IMA workshop's
web page</A>.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

244
lib/ldpc/release.html Executable file
View File

@ -0,0 +1,244 @@
<HTML><HEAD>
<TITLE>Release Notes for LDPC-codes Software</TITLE>
</HEAD><BODY>
<H1>Release Notes for LDPC-codes Software</H1>
These notes describe all the stable public releases of this software. Old
and future releases can be obtained via
<BLOCKQUOTE>
<A HREF="http://www.cs.toronto.edu/~radford/ldpc.software.html">
<TT>http://www.cs.toronto.edu/~radford/ldpc.software.html</TT></A>
</BLOCKQUOTE>
The current development version is now maintained at
<BLOCKQUOTE>
<A HREF="http://github.com/radfordneal/LDPC-codes">
<TT>http://github.com/radfordneal/LDPC-code</TT></A>
</BLOCKQUOTE>
<H2>Version of 2012-02-11.</H2>
This version has a few bug fixes and some minor new features. The major
change is that a source repository for the software is now hosted
at github.com, making it easier for people to create and release
their own versions of this software.
<OL>
<LI> Changed the copyright notice (in the file COPYRIGHT, and elsewhere)
to remove the requirement that my web site be referenced. (Nowadays,
I think users should have no problem finding the sources using a
search engine.)
<LI> Included a copy of the nrand48 routine from the GNU C library
in the rand.c module, to ensure that it is always available
and always the same. (This isn't so on some versions of cygwin.)
<LI> Added a -f option to encode and decode that forces flushing
after writing each block. Useful for allowing encode or
decode to be used as a server, reading and writing blocks
from named pipes.
<LI> Added a -z option for pchk-to-alist to suppress output of 0
row and column indexes that pad up to the maximum number used.
<LI> Documented the previously undocumented -t options for pchk-to-alist
and alist-to-pchk.
<LI> Changed alist-to-pchk so that it no longer requires zero indexes
that pad out to the maximum needed for a row or column (thanks
to Monica Kolb for suggesting this).
<LI> Changed mod2word type in mod2dense.c to uint32_t, to avoid
wasted space when long is 64 bits (thanks to Mathieu Cunche
and Vincent Roca for suggesting this).
<LI> Fixed bug in distrib.c affecting distributions with a single
number (thanks to Mike Vicuna for pointing it out).
<LI> Fixed bug in -t option for pchk-to-alist (thanks to Andrea Fontana
for reporting this).
<LI> Fixed references in the documentation to mod2sparse_multvec
that should be to mod2sparse_mulvec (thanks to Andrea Fontana
for reporting this).
</OL>
<H2>Version of 2006-02-08.</H2>
The copyright notice has been changed in this release to no longer
restrict use to purposes of research or education. The new copyright
notice can be read <A HREF="index.html#copyright">here</A>. It is now
possible to create LDPC codes with varying numbers of checks per bit
(an extension based on work by Peter Junteng Liu). New programs for
converting to and from the <A
HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
format</A> for parity check matrices, used by David MacKay and others,
have also been added.
<P>The following new features have been added:
<OL>
<LI> The <A HREF="pchk.html#make-ldpc"><TT>make-ldpc</TT></A> program can
new create LDPC codes with varying numbers of checks per bit. The
<A HREF="examples.html">examples</A> now include a code of this sort.
<LI> New programs <A HREF="pchk.html#pchk-to-alist"><TT>pchk-to-alist</TT></A>
and <A HREF="pchk.html#alist-to-pchk"><TT>alist-to-pchk</TT></A> have
been added, which convert to and from <A
HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
format</A>.
<LI> A <A HREF="run-examples"><TT>run-examples</TT></A> script has been
added, which runs all the <A HREF="examples.html">examples</A> and
compares with the saved output that I obtained.
</OL>
<H2>Version of 2001-11-18.</H2>
This is a minor release, whose main purpose is fixing bug (1) below.
Also, this release has been tested and found to work with the <A
HREF="http://www.cygwin.com">cygwin</A> Unix environment that runs
under Microsoft Windows.
<P>The following new feature has been added:
<OL>
<LI> A new <B>-t</B> option has been added to
<A HREF="pchk.html#print-pchk"><TT>print-pchk</TT></A>, which
causes it to print the transpose of the parity check matrix.
</OL>
The following program module change was made:
<OL>
<LI> The behaviour of <A
HREF="mod2dense.html#invert_selected">mod2dense_invert_selected</A>
has been changed when the matrix has dependent rows. The result returned
contains the inverse of a sub-matrix in its initial columns. The contents
of the remaining columns up to the number of rows was previously undefined,
but these columns are now set to contain zeros. This was done to fix
bug (1) below.
</OL>
The following bugs were fixed:
<OL>
<LI> A bug has been fixed in
<A HREF="encoding.html#make-gen"><TT>make-gen</TT></A>
which sometimes
produced invalid `dense' or `mixed' generator matrices when the parity
check matrix had redundant rows.
The `sparse' generator matrices were not affected. The output of the
<A HREF="ex-dep"><TT>ex-dep</TT></A> example has changed slightly as a
result.
<LI> The open mode for reading the file of random numbers has been changed from
"r" to "rb", for compatibility with non-Unix systems.
<LI> <A HREF="mod2sparse.html#copy"><TT>mod2sparse_copy</TT></A> has
been fixed so that it copies the <B>lr</B> and <B>pr</B> fields
of entries.
<LI> The "set -v -e" in the command files for the examples has
been replaced by two commands, "set -e" and "set -v", since some
shells can't set two options at once.
</OL>
A few minor fixes to the documentation have also been made.
<H2>Version of 2001-05-04.</H2>
Changes and new features regarding programs and associated
documentation and examples:
<OL>
<LI> Warnings have been added to the documentation about the dangers of
using zero codewords for testing (due to the possibility of the decoder
accidently being non-symmetric). The examples have been changed to
not use zero codewords, except for
<A HREF="ex-ham7a"><TT>ex-ham7a</TT></A>, which still
demonstrates this facility.
<LI> Decoding by probability propagation has been changed so that if
a probability ratio gets set to NaN ("not a number", the result of
infinite but conflicting evidence from different sources), the probability
ratio is changed to 1, in hopes that something sensible may result.
<LI> The decoding procedures have been changed to decode a bit to a 1 if
there is a tie, so that any resulting asymmetry in decoding will
make zero decoding less, rather than more, likely. See point (1) above.
<LI> All programs now allow a file name argument to be "-", which specifies
standard input or standard output, as appropriate. The
<A HREF="ex-ldpc36-5000a"><TT>ex-ldpc36-5000a</TT></A> example has been
changed to use this facility in order to avoid creating lots of files.
<LI> Channels with noise from a logistic distribution (AWLN) have been
implemented. For details,
see the <A HREF="channel.html">channel documentation</A>.
<LI> The <B>make-gen</B> program for "dense" or "mixed" options was modified
so that when some parity checks are redundant, others are not declared
redundant when they aren't. This makes the result compatible with
what is obtained with the "sparse" option. The example in the
<A HREF="dep-H.html">discussion of linear dependence in parity check
matrices</A> has changed slightly as a result.
<LI> The messages displayed by the <A HREF="decoding.html#decode">decode</A>
program have changed slightly: The block size is no longer displayed,
and the percentage of bits changed is now shown. The data output
when the <B>-t</B> option is specified now includes the number of
bits changed in each block.
<LI> A new <B>-T</B> option to <A HREF="decoding.html#decode">decode</A>
for displaying
<A HREF="decode-detail.html">detailed information on decoding</A>
has been added.
<LI> Doing a <B>make clean</B> will now remove the files created
by running the <A HREF="examples.html">examples</A>.
<LI> The files created by the <A HREF="examples.html">examples</A> now
start with "<TT>ex-</TT>" and contain a ".", to make them easier to
identify for cleanup, and the saved output file now ends in
"<TT>-out</TT>" rather than "<TT>.out</TT>".
<LI> The scripts for the examples now use the <B>-v</B> option of <B>set</B>
rather than <B>-x</B>, so that the command lines are echoed
faithfully as they are read.
<LI> Two new <A HREF="examples.html">examples</A> have been added:
<TT>ex-dep</TT> demonstrates what happens when parity check matrices
have redundant row, and <TT>ex-wrong-model</TT> investigates what
happens when the wrong model is used to decode.
</OL>
Changes and new features regarding program modules and other internals:
<OL>
<LI> Instructions have been added on
<A HREF="modify.html">how to modify the programs</A>, and some
code has been reorganized to facilitate modifications.
<LI> The makefile has been made trivial, simply recompiling everything
from scratch every time. This is simpler and less error prone
than putting in dependencies.
Compiling all the programs takes only about five seconds on a
modern PC.
<LI> The
<A HREF="mod2dense.html#invert_selected"><TT>mod2dense_invert_selected</TT></A>
procedure has been changed
to take an additional argument in which a permutation of rows is
returned. This extension is needed in order for the result when
the matrix is not of full rank to include as many rows as possible,
as needed for the above modification of <B>make-gen</B>.
<LI> New routines
<A HREF="mod2dense.html#copyrows"><TT>mod2dense_copyrows</TT></A> and
<A HREF="mod2sparse.html#copyrows"><TT>mod2sparse_copyrows</TT></A> have
been added, analogous to the previous routines for copying columns.
<LI> The decoding procedures have been changed to always return the bit
probabilities (previously, one could pass a null pointer to suppress
this). This makes things simpler, and facilitates the production of
detailed trace output when the <B>-T</B> option is used.
</OL>
The following bugs were fixed:
<OL>
<LI> A problem with <B>print-gen</B> prevented the <B>-d</B> option from working
in most cases. The documentation was also fixed to note what
the <B>L</B> and <B>U</B> matrices printed will look like.
<LI> The documentation for
<A HREF="mod2sparse.html#copycols"><TT>mod2sparse_copycols</TT></A> and
<A HREF="mod2dense.html#copycols"><TT>mod2dense_copycols</TT></A>
was ambiguous. It has been clarified. The dense and sparse
implementations were inconsistent. The sparse version has been changed
to match the dense version, which was and is the only version actually
used in the LDPC software.
<LI> In <TT>decode.c</TT>, a variable declared to be <TT>float</TT> was printed
using "<TT>%f</TT>", which strangely didn't work with one compiler.
It's now declared as <TT>double</TT>.
</OL>
There were also numerous minor cleanups of program code and documentation.
<H2>Version of 2000-03-19.</H2>
This was the first public release.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

12
lib/ldpc/run-examples Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# Run all the examples, and check the output against the corresponding -out
# file. Note that slight differences are possible when the examples are
# run on different machines, due to slightly different round-off errors.
for e in `ls ex-* | grep -v "\\." | grep -v .-out`
do
echo Running $e:
$e 2>&1 | diff ${e}-out -
echo " "
done

90
lib/ldpc/sparse-LU.html Executable file
View File

@ -0,0 +1,90 @@
<HTML><HEAD>
<TITLE> Sparse LU Decomposition Methods </TITLE>
</HEAD><BODY>
<H1> Sparse LU Decomposition Methods </H1>
<P>The sparse modulo-2 matrix LU decomposition routine <A
HREF="mod2sparse.html#decomp"><TT>mod2sparse_decomp</TT></A> (which
is used by the <A HREF="encoding.html#make-gen"><TT>make-gen</TT></A>
program when it is asked to create a sparse generator matrix) tries to
find an sub-matrix of a matrix (for <TT>make-gen</TT>, the parity
check matrix), and an ordering of rows and columns for this
sub-matrix, that leads to the lower-triangular matrix <B>L</B> and the
upper-triangular matrix <B>U</B> making up the LU decomposition being
as sparse as possible. Finding an optimal solution is too difficult,
so instead a heuristic strategy is used.
<P>The overall algorithm finds <B>L</B> and <B>U</B> a column at a
time, from left to right (as reordered, in the case of <B>U</B>). As
this is done, a copy, <B>B</B>, of the original matrix is modified.
To create column <I>i</I> of <B>L</B> and <B>U</B>, some element with
value 1 in <B>B</B> whose row and column indexes, after reordering,
are both greater than <I>i</I> is found. The row and column of this
element are considered to come next in the reordering, and the
contents of the column containing this element is copied to <B>L</B>
and <B>U</B> (upper elements going to <B>U</B>, lower to <B>L</B>).
The row containing this element is then added to some later rows so as
to clear the lower part of this column to zeros.
<P>At the first step of this process - selecting an element with value
1 from the later rows and columns - there will often be several
possibilities. Different choices can lead to the final result being
more or less sparse. The possible strategies for picking an element
are identified by the constants <TT>Mod2sparse_first</TT>,
<TT>Mod2sparse_mincol</TT>, and <TT>Mod2sparse_minprod</TT>. These
strategies operate as follows:
<P><TT>Mod2sparse_first</TT>
<BLOCKQUOTE>
Select the first element with value 1 that is encountered in a top
to bottom, left to right search.
</BLOCKQUOTE>
<P><TT>Mod2sparse_mincol</TT>
<BLOCKQUOTE>
Select the first element with value 1 that is contained in a column
of <B>B</B> that has the smallest number of 1s of any column.
</BLOCKQUOTE>
<P><TT>Mod2sparse_minprod</TT>
<BLOCKQUOTE>
Select an element with value 1 for which the product of the number of
1s in that row of <B>B</B> minus one times the number of 1s in that
column of <B>B</B> minus one is as small as possible.
</BLOCKQUOTE>
<P>The <B>abandon_number</B> and <B>abandon_when</B> parameters can
modify the basic strategy. If <B>abandon_number</B> is greater than
zero, then after <B>abandon_when</B> columns have been selected,
<B>abandon_number</B> of the remaining columns are abandoned as
candidates for possible future selection, the abandoned columns being
those with the greatest number of entries. Abandoning such columns
saves space and time, but may make the final result less sparse than
it would otherwise be, and can possibly result in the matrix appearing
to have lower rank than it actually has.
<P>The methods described here are fairly straightforward adaptations
of standard methods for sparse square matrices of reals, as described, for
example, in
<BLOCKQUOTE>
I. S. Duff, A. M. Erisman, J. K. Reid (1986) <I>Direct Methods for
Sparse Matrices</I>, Oxford: Clarendon Press.
</BLOCKQUOTE>
In the coding context, however, we are interested in matrices of
modulo-2 elements, and it is enough to find a sparse LU decomposition
of any square sub-matrix that can be obtained by selecting columns of
the rectangular parity check matrix. I talked about the application
of sparse matrix methods to encoding of LDPC codes at the 1999 IMA
workshop on Codes, Systems and Graphical Models (see the <A
HREF="refs.html">references</A>).
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

BIN
lib/ldpc/sparse-encode.pdf Executable file

Binary file not shown.

100
lib/ldpc/support.html Executable file
View File

@ -0,0 +1,100 @@
<HTML><HEAD>
<TITLE> Support Programs </TITLE>
</HEAD><BODY>
<H1> Support Programs </H1>
The following programs provide support for testing and performance
assessment.
<P><A NAME="rand-src"><HR><B>rand-src</B>: Generate random message bits.
<BLOCKQUOTE><PRE>
rand-src <I>source-file seed n-bits</I>
</PRE></BLOCKQUOTE>
<P>Creates a file of random messages bits called
<TT><I>source-file</I></TT>, which is suitable for testing the
correctness and performance of other programs. The bits in the file
are independent, and are equally likely to be 0 or 1. They are
generated pseudo-randomly based on <TT><I>seed</I></TT>. The actual
random number seed used will be <TT><I>seed</I></TT> times 10 plus 2,
so that the stream of pseudo-random numbers will not be the same as
any that might have been used by another program.
<P>The <TT><I>n-bits</I></TT> argument specifies the number of bits to
produce. It can be a single number, or it can consist of a block size
and a number of blocks, written with <TT>x</TT> separating these
numbers, with no spaces. Each block is written as a single line, with
the bits in the block represented by the characters '0' and '1', with
no intervening spaces. If the bit count is given by a single number,
the block size is assumed to be one.
<P><B>Example:</B> The following command produces a file containing
3 blocks, each consisting of 15 random bits, produced using the pseudo-random
number stream identified by the <TT><I>seed</I></TT> of 17:
<UL><PRE>
<LI>rand-src rsrc 17 15x3
</PRE></UL>
The contents of the file <TT>rsrc</TT> after this command might be something
like the following:
<BLOCKQUOTE><PRE>
111011000110000
010010110010111
100000000000111
</BLOCKQUOTE></PRE>
<P><A NAME="verify"><HR><B>verify</B>: Verify that decoded blocks are
codewords, and that they match the source.
<BLOCKQUOTE><PRE>
verify [ -t ] <I>pchk-file decoded-file</I> [ <I>gen-file</I> [ <I>source-file</I> ] ]
</PRE></BLOCKQUOTE>
<P>Checks whether or not the blocks in <TT><I>decoded-file</I></TT>
are codewords, according to the parity check matrix in
<TT><I>pchk-file</I></TT>. If <TT><I>gen-file</I></TT> is specified,
the message bits of the blocks are also checked against the
corresponding blocks of <TT><I>source-file</I></TT>, or against zero
if <TT><I>source-file</I></TT> is not given. (Normally, one would
leave out <TT><I>source-file</I></TT> only if the <A
HREF="channel.html#transmit"><TT>transmit</TT></A> command was used
with an argument specifying that zeros are to be transmitted, rather
than a file of encoded data.)
<P>A summary of the results is displayed on standard error, giving the
total numbers of blocks, the number with parity check errors, and, if
<TT><I>gen-file</I></TT> was specified, the number of blocks with
source errors and the number with errors of both kinds. If
<TT><I>gen-file</I></TT> was specified, a second
summary line displays the bit error rate from
comparing the decoded message bits with the true message bits (zeros
if no <TT><I>source file</I></TT> was given).
<P>If the <B>-t</B> option is given, block-by-block results are
printed on standard output in two or three columns, giving the block
number (from zero), the number of parity check errors for that block,
and the number of errors in source bits. The last column is omitted
if <TT><I>gen-file</I></TT> is not specified. The columns are
preceded by a line of headers, so the file is suitable for reading
into the S-Plus or R statistics packages, with a command such as
<BLOCKQUOTE><PRE>
data <- read.table(<I>file</I>,header=T)
</PRE></BLOCKQUOTE>
<P>Warning messages are displayed on standard error if the number of
bits in <TT><I>decoded-file</I></TT> is not a multiple of the block
length, or if <TT><I>source-file</I></TT> is too short. Newlines
in these files are ignored, even though they would normally occur
at the ends of blocks.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>

170
lib/ldpc/transmit.c Executable file
View File

@ -0,0 +1,170 @@
/* TRANSMIT.C - Simulate transmission of bits through a channel. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "channel.h"
#include "open.h"
#include "rand.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *tfile, *rfile;
FILE *tf, *rf;
int block_size, n_bits;
char junk;
int seed;
int cnt;
int n, b;
/* Look at arguments. The arguments specifying the channel are looked
at by channel_parse in channel.c */
if (!(tfile = argv[1])
|| !(rfile = argv[2])
|| !argv[3] || sscanf(argv[3],"%d%c",&seed,&junk)!=1)
{ usage();
}
n = channel_parse(argv+4,argc-4);
if (n<=0 || argc-4-n!=0)
{ usage();
}
/* See if the source is all zeros or a file. */
if (sscanf(tfile,"%d%c",&n_bits,&junk)==1 && n_bits>0)
{ block_size = 1;
tf = NULL;
}
else if (sscanf(tfile,"%dx%d%c",&block_size,&n_bits,&junk)==2
&& block_size>0 && n_bits>0)
{ n_bits *= block_size;
tf = NULL;
}
else
{ tf = open_file_std(tfile,"r");
if (tf==NULL)
{ fprintf(stderr,"Can't open encoded file to transmit: %s\n",tfile);
exit(1);
}
}
/* Open output file. */
rf = open_file_std(rfile,"w");
if (rf==NULL)
{ fprintf(stderr,"Can't create file for received data: %s\n",rfile);
exit(1);
}
/* Set random seed to avoid duplications with other programs. */
rand_seed(10*seed+3);
/* Transmit bits. */
for (cnt = 0; ; cnt++)
{
/* Get next bit to transmit. */
if (tf) /* Data comes from a file */
{
for (;;)
{ b = getc(tf);
if (b!=' ' && b!='\t' && b!='\n' && b!='\r')
{ break;
}
putc(b,rf);
}
if (b==EOF) break;
if (b!='0' && b!='1')
{ fprintf(stderr,"Bad character (code %d) file being transmitted\n",b);
exit(1);
}
}
else /* Data is all zeros */
{
if (cnt>0 && cnt%block_size==0)
{ putc('\n',rf);
}
if (cnt==n_bits) break;
b = '0';
}
b = b=='1';
/* Produce the channel output for this transmitted bit. */
switch (channel)
{ case BSC:
{ int bsc_noise;
bsc_noise = rand_uniform() < error_prob;
fprintf (rf, "%d", b^bsc_noise);
break;
}
case AWGN:
{ double awgn_noise;
awgn_noise = std_dev * rand_gaussian();
fprintf (rf, " %+5.2f", b ? 1+awgn_noise : -1+awgn_noise);
break;
}
case AWLN:
{ double awln_noise;
awln_noise = lwidth * rand_logistic();
fprintf (rf, " %+5.2f", b ? 1+awln_noise : -1+awln_noise);
break;
}
default:
{ abort();
}
}
}
fprintf(stderr,"Transmitted %d bits\n",cnt);
if (ferror(rf) || fclose(rf)!=0)
{ fprintf(stderr,"Error writing received bits to %s\n",rfile);
exit(1);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,
"Usage: transmit encoded-file|n-zeros received-file seed channel\n");
channel_usage();
exit(1);
}

254
lib/ldpc/verify.c Executable file
View File

@ -0,0 +1,254 @@
/* VERIFY.C - Verify encoded or decoded blocks. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "alloc.h"
#include "blockio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
#include "check.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *coded_file, *source_file;
char *pchk_file, *gen_file;
int table;
char *sblk, *cblk, *chks;
int seof, ceof;
int srcerr, chkerr, bit_errs;
int i, n;
FILE *srcf, *codef;
int tot_srcerrs, tot_chkerrs, tot_botherrs, tot_undeterrs, tot_good;
/* Look at arguments. */
table = 0;
if (argc>1 && strcmp(argv[1],"-t")==0)
{ table = 1;
argc -= 1;
argv += 1;
}
if (argc<3 || argc>5) usage();
if (!(pchk_file = argv[1])
|| !(coded_file = argv[2]))
{ usage();
}
gen_file = 0;
source_file = 0;
if (argv[3])
{ gen_file = argv[3];
if (argv[4])
{ source_file = argv[4];
if (argv[5])
{ usage();
}
}
}
if ((strcmp(pchk_file,"-")==0)
+ (strcmp(coded_file,"-")==0)
+ (source_file!=0 && strcmp(source_file,"-")==0)
+ (gen_file!=0 && strcmp(gen_file,"-")==0) > 1)
{ fprintf(stderr,"Can't read more than one stream from standard input\n");
exit(1);
}
/* Read parity check file. */
read_pchk(pchk_file);
if (N<=M)
{ fprintf(stderr,
"Number of bits (%d) should be greater than number of checks (%d)\n",N,M);
exit(1);
}
/* Read generator matrix file, if given, up to the point of finding
out which are the message bits. */
if (gen_file!=0)
{ read_gen(gen_file,1,0);
}
/* Open coded file to check. */
codef = open_file_std(coded_file,"r");
if (codef==NULL)
{ fprintf(stderr,"Can't open coded file: %s\n",coded_file);
exit(1);
}
/* Open source file to verify against, if given. */
if (source_file!=0)
{
srcf = open_file_std(source_file,"r");
if (srcf==NULL)
{ fprintf(stderr,"Can't open source file: %s\n",source_file);
exit(1);
}
}
sblk = chk_alloc (N-M, sizeof *sblk);
cblk = chk_alloc (N, sizeof *cblk);
chks = chk_alloc (M, sizeof *chks);
/* Print header for table. */
if (table)
{ if (gen_file!=0)
{ printf(" block chkerrs srcerrs\n");
}
else
{ printf(" block chkerrs\n");
}
}
/* Verify successive blocks. */
tot_srcerrs = 0;
tot_chkerrs = 0;
tot_botherrs = 0;
tot_undeterrs = 0;
tot_good = 0;
bit_errs = 0;
seof = 0;
ceof = 0;
for (n = 0; ; n++)
{
/* Read block from coded file. */
if (blockio_read(codef,cblk,N)==EOF)
{ ceof = 1;
}
/* Read block from source file, if given. */
if (source_file!=0 && !ceof && !seof)
{ if (blockio_read(srcf,sblk,N-M)==EOF)
{ fprintf(stderr,"Warning: Not enough source blocks (only %d)\n",n);
seof = 1;
}
}
/* Stop if end of received file. */
if (ceof) break;
/* Check that received block is a code word, and if not find the number of
parity check errors. */
chkerr = check(H,cblk,chks);
/* Check against source block, if provided, or against zeros, if
the generator matrix was provided but no source file. */
if (gen_file!=0)
{ srcerr = 0;
if (source_file!=0 && !seof)
{ for (i = M; i<N; i++)
{ if (cblk[cols[i]]!=sblk[i-M])
{ srcerr += 1;
}
}
}
if (source_file==0)
{ for (i = M; i<N; i++)
{ if (cblk[cols[i]]!=0)
{ srcerr += 1;
}
}
}
bit_errs += srcerr;
}
/* Print table entry. */
if (table)
{ if (gen_file!=0)
{ printf("%6d %7d %7d\n",n,chkerr,srcerr);
}
else
{ printf("%6d %7d\n",n,chkerr);
}
}
/* Increment totals. */
if (chkerr) tot_chkerrs += 1;
if (gen_file!=0 && (source_file==0 || !seof))
{ if (srcerr) tot_srcerrs += 1;
if (srcerr && chkerr) tot_botherrs += 1;
if (srcerr && (chkerr==0) ) tot_undeterrs += 1;
if ((srcerr==0) && (chkerr==0) ) tot_good += 1;
}
}
/* Write final statistics to standard error. Flush standard output
first to avoid mixing of output. */
fflush(stdout);
if (gen_file!=0)
{ fprintf(stderr,
"Block counts: tot %d, with chk errs %d, with src errs %d, both %d\n",
n, tot_chkerrs, tot_srcerrs, tot_botherrs, tot_undeterrs);
fprintf(stderr,
"Total good frames: %d Total undetected errors: %d\n",
tot_good, tot_undeterrs);
fprintf(stderr,
"Bit error rate (on message bits only): %.3e\n",
(double)bit_errs/(n*(N-M)));
}
else
{ fprintf (stderr,
"Block counts: tot %d, with chk errs %d\n", n, tot_chkerrs);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,
"Usage: verify [ -t ] pchk-file decoded-file [ gen-file [ source-file ] ]\n");
exit(1);
}