Algorithm-FEC
view release on metacpan or search on metacpan
* 980624
* (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
*
* Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
* Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
* modified by Marc Lehmann <fec@schmorp.de>, Sep 2003.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define MSDOS /* LEAVE THIS IN PLACE EVEN ON UNIX! */
/*
* compatibility stuff
*/
#ifdef MSDOS /* but also for others, e.g. sun... */
#define NEED_BCOPY
#define bcmp(a,b,n) memcmp(a,b,n)
#endif
#ifdef NEED_BCOPY
#define bcopy(s, d, siz) memcpy((d), (s), (siz))
#define bzero(d, siz) memset((d), '\0', (siz))
#endif
/*
* stuff used for testing purposes only
*/
#ifdef TEST
#define DEB(x)
#define DDB(x) x
#define DEBUG 0 /* minimal debugging */
#ifdef MSDOS
#include <time.h>
struct timeval {
unsigned long ticks;
};
#define gettimeofday(x, dummy) { (x)->ticks = clock() ; }
#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC )
typedef unsigned long u_long ;
typedef unsigned short u_short ;
#else /* typically, unix systems */
#include <sys/time.h>
#define DIFF_T(a,b) \
(1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) )
#endif
#define TICK(t) \
{struct timeval x ; \
gettimeofday(&x, NULL) ; \
t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \
}
#define TOCK(t) \
{ u_long t1 ; TICK(t1) ; \
if (t1 < t) t = 256000000 + t1 - t ; \
else t = t1 - t ; \
if (t == 0) t = 1 ;}
u_long ticks[10]; /* vars for timekeeping */
#else
#define DEB(x)
#define DDB(x)
#define TICK(x)
#define TOCK(x)
#endif /* TEST */
/*
* You should not need to change anything beyond this point.
* The first part of the file implements linear algebra in GF.
*
* gf is the type used to store an element of the Galois Field.
* Must constain at least GF_BITS bits.
*
* Note: unsigned char will work up to GF(256) but int seems to run
* faster on the Pentium. We use int whenever have to deal with an
* index, since they are generally faster.
*/
#if (GF_BITS < 2 && GF_BITS >16)
#error "GF_BITS must be 2 .. 16"
#endif
#if (GF_BITS <= 8)
typedef uint8_t gf;
#else
typedef uint16_t gf;
#endif
#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
/*
* Primitive polynomials - see Lin & Costello, Appendix A,
* and Lee & Messerschmitt, p. 453.
GF_ADDMULC( dst[4] , src[4] );
GF_ADDMULC( dst[5] , src[5] );
GF_ADDMULC( dst[6] , src[6] );
GF_ADDMULC( dst[7] , src[7] );
#endif
#if (UNROLL > 8)
GF_ADDMULC( dst[8] , src[8] );
GF_ADDMULC( dst[9] , src[9] );
GF_ADDMULC( dst[10] , src[10] );
GF_ADDMULC( dst[11] , src[11] );
GF_ADDMULC( dst[12] , src[12] );
GF_ADDMULC( dst[13] , src[13] );
GF_ADDMULC( dst[14] , src[14] );
GF_ADDMULC( dst[15] , src[15] );
#endif
}
#endif
lim += UNROLL - 1 ;
for (; dst < lim; dst++, src++ ) /* final components */
GF_ADDMULC( *dst , *src );
}
/*
* computes C = AB where A is n*k, B is k*m, C is n*m
*/
static void
matmul(gf *a, gf *b, gf *c, int n, int k, int m)
{
int row, col, i ;
for (row = 0; row < n ; row++) {
for (col = 0; col < m ; col++) {
gf *pa = &a[ row * k ];
gf *pb = &b[ col ];
gf acc = 0 ;
for (i = 0; i < k ; i++, pa++, pb += m )
acc ^= gf_mul( *pa, *pb ) ;
c[ row * m + col ] = acc ;
}
}
}
#ifdef DEBUG
/*
* returns 1 if the square matrix is identiy
* (only for test)
*/
static int
is_identity(gf *m, int k)
{
int row, col ;
for (row=0; row<k; row++)
for (col=0; col<k; col++)
if ( (row==col && *m != 1) ||
(row!=col && *m != 0) )
return 0 ;
else
m++ ;
return 1 ;
}
#endif /* debug */
/*
* invert_mat() takes a matrix and produces its inverse
* k is the size of the matrix.
* (Gauss-Jordan, adapted from Numerical Recipes in C)
* Return non-zero if singular.
*/
DEB( int pivloops=0; int pivswaps=0 ; /* diagnostic */)
static int
invert_mat(gf *src, int k)
{
gf c, *p ;
int irow, icol, row, col, i, ix ;
int error = 1 ;
int *indxc = my_malloc(k*sizeof(int), "indxc");
int *indxr = my_malloc(k*sizeof(int), "indxr");
int *ipiv = my_malloc(k*sizeof(int), "ipiv");
gf *id_row = NEW_GF_MATRIX(1, k);
gf *temp_row = NEW_GF_MATRIX(1, k);
bzero(id_row, k*sizeof(gf));
DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ )
/*
* ipiv marks elements already used as pivots.
*/
for (i = 0; i < k ; i++)
ipiv[i] = 0 ;
for (col = 0; col < k ; col++) {
gf *pivot_row ;
/*
* Zeroing column 'col', look for a non-zero element.
* First try on the diagonal, if it fails, look elsewhere.
*/
irow = icol = -1 ;
if (ipiv[col] != 1 && src[col*k + col] != 0) {
irow = col ;
icol = col ;
goto found_piv ;
}
for (row = 0 ; row < k ; row++) {
if (ipiv[row] != 1) {
for (ix = 0 ; ix < k ; ix++) {
DEB( pivloops++ ; )
if (ipiv[ix] == 0) {
if (src[row*k + ix] != 0) {
irow = row ;
icol = ix ;
goto found_piv ;
}
} else if (ipiv[ix] > 1) {
fprintf(stderr, "singular matrix\n");
goto fail ;
}
}
}
}
if (icol == -1) {
fprintf(stderr, "XXX pivot not found!\n");
( run in 0.349 second using v1.01-cache-2.11-cpan-119454b85a5 )