[MN-dev] [mndiff]: r123 - in trunk/noe: Makefile ldpc.c ldpc.h test_ldpc.c
michael
subversion at mplayerhq.hu
Mon Nov 24 23:08:33 CET 2008
Author: michael
Date: Mon Nov 24 23:08:33 2008
New Revision: 123
Log:
Low density parity check codes support.
Added:
trunk/noe/ldpc.c
trunk/noe/ldpc.h
trunk/noe/test_ldpc.c
Modified:
trunk/noe/Makefile
Modified: trunk/noe/Makefile
==============================================================================
--- trunk/noe/Makefile (original)
+++ trunk/noe/Makefile Mon Nov 24 23:08:33 2008
@@ -1,7 +1,7 @@
LIBOBJS = galois.o rs.o
OBJS = rw.o filerw.o noe.o
LIBS = libnoe_100.a libnoe_101.a libnoe_10001.a
-PUBLIC_HEADERS = rs.h galois.h
+PUBLIC_HEADERS = rs.h galois.h ldpc.h
LIBSRCS = $(LIBOBJS:.o=.c) $(ASM_LIBOBJS:.o=.s)
SRCS = $(OBJS:.o=.c)
INSTALL_BASE = /usr/local
@@ -20,9 +20,9 @@ CFLAGS = -g -Wall -O4 $(OPTFLAGS) -I. $
%_10001.o: %.c
$(CC) $(CFLAGS) -c -DSIZE=0x10001 -o $@ $<
-all: test_100 test_101 test_10001 mina
+all: test_100 test_101 test_10001 mina test_ldpc_100
-libnoe_100.a: $(LIBOBJS:.o=_100.o)
+libnoe_100.a: $(LIBOBJS:.o=_100.o) ldpc_100.o
libnoe_101.a: $(LIBOBJS:.o=_101.o) gfft_101.o
libnoe_10001.a: $(LIBOBJS:.o=_10001.o) gfft_10001.o
libnoe_100.a libnoe_101.a libnoe_10001.a:
@@ -37,6 +37,9 @@ test: all
test_%: test_%.o libnoe_%.a
$(CC) $(LDFLAGS) -o $@ $^
+test_ldpc_%: test_ldpc_%.o libnoe_%.a
+ $(CC) $(LDFLAGS) -o $@ $^
+
clean:
rm -f *.o *.a *~
Added: trunk/noe/ldpc.c
==============================================================================
--- (empty file)
+++ trunk/noe/ldpc.c Mon Nov 24 23:08:33 2008
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2008 Michael Niedermayer <michaelni at gmx.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "noe_internal.h"
+#include "galois_internal.h"
+#include "random_internal.h"
+#include "ldpc.h"
+
+#undef NDEBUG
+#include <assert.h>
+
+#define MAX_NZC 32
+
+typedef struct LDPCContext{
+ unsigned int (*parity_matrix)[2][MAX_NZC];
+ GFF4Element *inv_matrix;
+ int parity_len;
+ int data_len;
+ int nzc;
+}LDPCContext;
+
+typedef uint8_t ELEM;
+
+int inverse(ELEM *matrix, int width, int height, int solvew){
+ int i, j, k, m, p;
+
+ for(p=i=0; i<solvew; i++){
+ for(j=p; j<height; j++){
+ if(matrix[i + j*width]){
+ unsigned int logline[width];
+ unsigned int inve= EXT(log)[inv(matrix[i + j*width])];
+ for(m=i; m<width; m++){
+ ELEM t= matrix[m + j*width];
+ matrix[m + j*width]= matrix[m + p*width];
+ matrix[m + p*width]= EXT(exp)[EXT(log)[t] + inve];
+ logline[m]= EXT(log)[matrix[m + p*width]];
+ }
+ for(k=0; k<height; k++){
+ if(matrix[i + k*width] && k!=p){
+ unsigned int factor= EXT(log)[neg(matrix[i + k*width])];
+ for(m=i; m<width; m++)
+ matrix[m + k*width] = sum(matrix[m + k*width], EXT(exp)[logline[m] + factor]);
+ }
+ }
+ p++;
+ break;
+ }
+ }
+ fprintf(stderr, "%5d/%5d\r", i, width);
+ }
+ return p;
+}
+
+LDPCContext *EXT(initLDPC)(int data_len, int parity_len, uint32_t seed){
+ LDPCContext *c= malloc(sizeof(LDPCContext));
+ KISSState kiss;
+ int i, j, y;
+ int nzc= noe_log2(parity_len)+1;
+ int code_len= data_len + parity_len;
+
+ if(nzc > MAX_NZC)
+ goto fail;
+ assert(nzc <= parity_len);
+
+ init_random(&kiss, seed);
+
+ c->parity_matrix= malloc(code_len * sizeof(*c->parity_matrix));
+ c-> inv_matrix= malloc(parity_len*parity_len * sizeof(*c->inv_matrix));
+
+ for(i=0; i<code_len; i++){
+ uint8_t tab[parity_len];
+ memset(tab, 0, parity_len);
+ for(j=0; j<nzc; j++){
+ do{
+ y= get_random(&kiss)%parity_len;
+ }while(tab[y]);
+ tab[y]=1;
+ c->parity_matrix[i][0][j] = y;
+ c->parity_matrix[i][1][j] = EXT(log)[get_random(&kiss)%(SIZE-1)+1];
+ }
+ }
+#if 0
+ for(;;){
+ int maxrow=0;
+ int minrow=999999;
+ int maxrowx=0;
+ uint8_t tab[parity_len];
+ memset(tab, 0, parity_len);
+
+ for(j=0; j<parity_len; j++){
+ if(row[j] > maxrow){
+ maxrow= row[j];
+ maxrowx= j;
+ }
+ if(row[j] < minrow)
+ minrow= row[j];
+ }
+ do{
+ j= get_random(&kiss)%nzc;
+ i= get_random(&kiss)%code_len;
+ }while(c->parity_matrix[i][0][j] != maxrowx);
+ for(y=0; y<nzc; y++)
+ tab[ c->parity_matrix[i][0][y] ]=1;
+ do{
+ y= get_random(&kiss)%parity_len;
+ }while(tab[y]);
+ c->parity_matrix[i][0][j] = y;
+ row[y] ++;
+ row[maxrowx]--;
+// fprintf(stderr, "%d %d\n", maxrow, minrow);
+ if(maxrow - 3 <= minrow)
+ break;
+ }
+#endif
+
+ c-> data_len= data_len;
+ c->parity_len= parity_len;
+ c->nzc = nzc;
+
+ return c;
+fail:
+ free(c);
+ return NULL;
+}
+
+int EXT(init_matrixLDPC)(LDPCContext *c, int erasure_count, int erasure_pos[]){
+ int i, j, rank, x, y;
+ int nzc= c->nzc;
+ int parity_len= c->parity_len;
+ ELEM inv_matrix[2*parity_len*parity_len];
+
+ memset(inv_matrix, 0, sizeof(inv_matrix));
+ for(i=0; i<erasure_count; i++){
+ x= erasure_pos[i];
+ for(j=0; j<nzc; j++){
+ y= c->parity_matrix[x][0][j];
+ inv_matrix[i + y*2*parity_len]= EXT(exp)[c->parity_matrix[x][1][j]];
+ }
+ }
+ for(i=0; i<parity_len; i++){
+ inv_matrix[i + i*2*parity_len + parity_len]= 1;
+ }
+
+ rank= inverse(inv_matrix, 2*parity_len, parity_len, erasure_count);
+ for(j=0; j<erasure_count; j++)
+ for(i=0; i<parity_len; i++)
+ c->inv_matrix[i + j*parity_len]= EXT(log)[inv_matrix[i + j*2*parity_len + parity_len]];
+
+ return rank - erasure_count;
+}
+
+int EXT(decodeLDPC)(LDPCContext *c, uint8_t *code, int erasure_count, int erasure_pos[]){
+ int i,j;
+ int parity_len= c->parity_len;
+ int code_len= c->data_len + parity_len;
+ GFF4Element syndrom[c->parity_len];
+ memset(syndrom, 0, sizeof(syndrom));
+
+ for(i=0; i<erasure_count; i++)
+ code[ erasure_pos[i] ]= 0;
+
+ for(i=0; i<code_len; i++){
+ GFF4Element v= EXT(log)[ code[i] ];
+ for(j=0; j<c->nzc; j++){
+ int y= c->parity_matrix[i][0][j];
+ int p= c->parity_matrix[i][1][j];
+ syndrom[y]= sum(syndrom[y], EXT(exp)[p + v]);
+ }
+ }
+
+ for(i=0; i<parity_len; i++)
+ syndrom[i]= EXT(log)[ syndrom[i] ];
+
+ for(i=0; i<erasure_count; i++){
+ GFF4Element v=0;
+ for(j=0; j<parity_len; j++){
+ v= sum(v, EXT(exp)[syndrom[j] + c->inv_matrix[j + i*parity_len]]);
+ }
+ code[ erasure_pos[i] ]= v;
+ }
+
+ return 0;
+}
+
+void EXT(freeLDPC)(LDPCContext *c){
+ free(c->parity_matrix);
+ free(c->inv_matrix);
+ free(c);
+}
Added: trunk/noe/ldpc.h
==============================================================================
--- (empty file)
+++ trunk/noe/ldpc.h Mon Nov 24 23:08:33 2008
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 Michael Niedermayer <michaelni at gmx.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+struct LDPCContext;
+
+struct LDPCContext *EXT(initLDPC)(int data_len, int parity_len, uint32_t seed);
+
+/**
+ *
+ * @return 0 if sucessfull, <0 if not (will only partially decode)
+ * for encoding you should try another seed when this returns <0
+ */
+int EXT(init_matrixLDPC)(struct LDPCContext *c, int erasure_count, int erasure_pos[]);
+
+/**
+ *
+ * @param code the code word to encode/decode.
+ * @param erasure_count must match what has been passed to init_matrixLDPC
+ * @param erasure_pos must match what has been passed to init_matrixLDPC
+ */
+int EXT(decodeLDPC)(struct LDPCContext *c, uint8_t *code, int erasure_count, int erasure_pos[]);
+
+void EXT(freeLDPC)(struct LDPCContext *c);
Added: trunk/noe/test_ldpc.c
==============================================================================
--- (empty file)
+++ trunk/noe/test_ldpc.c Mon Nov 24 23:08:33 2008
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2008 Michael Niedermayer <michaelni at gmx.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "galois_internal.h"
+#include "random_internal.h"
+#include "ldpc.h"
+
+#undef NDEBUG
+#include <assert.h>
+
+int main(){
+ int data_len, parity_len, i, x;
+ KISSState kiss;
+
+ init_random(&kiss, 0);
+ EXT(init)();
+
+ for(data_len=100; data_len < 2000; data_len<<=1){
+ for(parity_len=10; parity_len < data_len; parity_len<<=1){
+ const int code_len= data_len + parity_len;
+ int seed, erasure_count, try;
+ struct LDPCContext *enc= NULL;
+ struct LDPCContext *dec= NULL;
+ int parity_pos[parity_len];
+
+ for(i=0; i<parity_len; i++)
+ parity_pos[i]= data_len + i;
+
+ for(seed=0; 1; seed++){
+ enc= EXT(initLDPC)(data_len, parity_len, seed);
+ if(EXT(init_matrixLDPC)(enc, parity_len, parity_pos) >= 0)
+ break;
+ EXT(freeLDPC)(enc);
+ }
+
+ dec= EXT(initLDPC)(data_len, parity_len, seed);
+
+ for(erasure_count= parity_len; erasure_count > parity_len-3; erasure_count--){
+ int fail=0;
+ for(try=0; try<10; try++){
+ uint8_t code[code_len], code_bak[code_len];
+ int erasure_pos[erasure_count];
+
+ for(i=0; i<data_len; i++)
+ code[i]= code_bak[i]= get_random(&kiss);
+ EXT(decodeLDPC)(enc, code, parity_len, parity_pos);
+ memcpy(code_bak+data_len, code+data_len, parity_len);
+ for(i=0; i<code_len; i++)
+ if(code[i] != code_bak[i])
+ fprintf(stderr, "FATALXX error %X!= %X at %d\n", code[i], code_bak[i], i);
+
+ for(i=0; i<erasure_count; i++){
+ do{
+ x= get_random(&kiss) % code_len;
+ }while(code[x] != code_bak[x]);
+ code[x]+= get_random(&kiss)%255+1;
+ erasure_pos[i]= x;
+ }
+
+ if(EXT(init_matrixLDPC)(dec, erasure_count, erasure_pos) < 0){
+ fail++;
+ continue;
+ }
+
+ EXT(decodeLDPC)(dec, code, erasure_count, erasure_pos);
+ for(i=0; i<code_len; i++){
+ if(code[i] != code_bak[i])
+ fprintf(stderr, "FATAL error %X!= %X at %d\n", code[i], code_bak[i], i);
+ }
+ }
+ printf("data:%5d parity:%5d extra:%d fail:%d seed:%d\n", data_len, parity_len, parity_len-erasure_count, fail, seed);
+ if(!fail)
+ break;
+ }
+ EXT(freeLDPC)(dec);
+ EXT(freeLDPC)(enc);
+ }
+ }
+ return 0;
+}
More information about the Mndiff-dev
mailing list