├── StdAfx.cpp ├── README.txt ├── Decoder.h ├── Encoder.h ├── Encoder.cpp ├── Symbol.h ├── Decoder.cpp ├── StdAfx.h ├── Makefile ├── Helper.h ├── Helper.cpp ├── Generators.h ├── Symbol.cpp ├── Main.cpp ├── LICENSE ├── Generators.cpp └── Tables.h /StdAfx.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foxsen/raptorQ/master/README.txt -------------------------------------------------------------------------------- /Decoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Generators.h" 3 | 4 | class Decoder { 5 | public: 6 | Decoder(); 7 | virtual ~Decoder(); 8 | 9 | private: 10 | Generators* gen; 11 | 12 | public: 13 | bool init(int K, int T); 14 | Symbol** decode(char **source, int _N, int *esi); 15 | Symbol* recover(int x); 16 | }; -------------------------------------------------------------------------------- /Encoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Generators.h" 3 | #include "Symbol.h" 4 | 5 | class Encoder { 6 | public: 7 | Encoder(); 8 | virtual ~Encoder(); 9 | 10 | private: 11 | Generators* gen; 12 | 13 | public: 14 | bool init(int K, int T); 15 | Symbol** encode(char **source, int overhead); 16 | 17 | }; -------------------------------------------------------------------------------- /Encoder.cpp: -------------------------------------------------------------------------------- 1 | #include "Helper.h" 2 | #include "Symbol.h" 3 | 4 | Encoder::Encoder(){ 5 | } 6 | 7 | Encoder::~Encoder() { 8 | delete gen; 9 | } 10 | 11 | bool Encoder::init(int K,int T) { 12 | gen = new Generators(); 13 | return gen->gen(K, K, T); 14 | } 15 | 16 | Symbol** Encoder::encode(char **source, int overhead) { 17 | Symbol **s; 18 | 19 | gen->prepare(source,gen->getK(),NULL); 20 | s = gen->generate_intermediates(); 21 | if (!s) return NULL; 22 | return gen->generate_repairs(overhead); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Symbol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Symbol { 4 | 5 | public: 6 | int *data; 7 | int nbytes; 8 | int sbn; /* source block number */ 9 | int esi; /* encoding symbol id */ 10 | 11 | Symbol(void); 12 | Symbol(unsigned int size); 13 | ~Symbol(void); 14 | 15 | void init(int size); 16 | void print(void); 17 | void fillData(char *src, int size); 18 | 19 | Symbol& operator=(const Symbol &s); 20 | Symbol& operator^(const Symbol &s); 21 | 22 | void xxor(Symbol *s); 23 | void mul(unsigned char u); 24 | void div(unsigned char u); 25 | void muladd(Symbol *s, unsigned char u); 26 | 27 | /* 28 | int getSBN(); 29 | int getESI(); 30 | 31 | void setSBN(int sbn); 32 | void setESI(int esi); 33 | */ 34 | }; 35 | -------------------------------------------------------------------------------- /Decoder.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Helper.h" 3 | #include "Symbol.h" 4 | 5 | Decoder::Decoder() { 6 | } 7 | 8 | Decoder::~Decoder() { 9 | delete gen; 10 | } 11 | 12 | /* initialize general parameters as much as possible 13 | this is meant to be called only once. 14 | By default, N is set to K. It will be fixup in prepare() 15 | */ 16 | bool Decoder::init(int K, int T) { 17 | gen = new Generators(); 18 | return gen->gen(K, K, T); 19 | } 20 | 21 | Symbol** Decoder::decode(char **source, int _N, int *esi) 22 | { 23 | Symbol **s; 24 | 25 | gen->prepare(source,_N,esi); 26 | s = gen->generate_intermediates(); 27 | if (!s) return NULL; 28 | return s; 29 | } 30 | 31 | Symbol* Decoder::recover(int x) 32 | { 33 | return gen->recover_symbol(x); 34 | } 35 | -------------------------------------------------------------------------------- /StdAfx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #if !defined(AFX_STDAFX_H__6DE6E4DF_EB80_48FE_B2FD_CC47CA5F99F8__INCLUDED_) 7 | #define AFX_STDAFX_H__6DE6E4DF_EB80_48FE_B2FD_CC47CA5F99F8__INCLUDED_ 8 | 9 | #if _MSC_VER > 1000 10 | #pragma once 11 | #endif // _MSC_VER > 1000 12 | 13 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 14 | 15 | #include 16 | 17 | // TODO: reference additional headers your program requires here 18 | //#include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | //{{AFX_INSERT_LOCATION}} 28 | // Microsoft Visual C++ will insert additional declarations immediately before the previous line. 29 | 30 | #endif // !defined(AFX_STDAFX_H__6DE6E4DF_EB80_48FE_B2FD_CC47CA5F99F8__INCLUDED_) 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ALL: main 2 | .PHONY: ALL clean libraptor 3 | 4 | CC = g++ 5 | LDFLAGS ?= 6 | CFLAGS += -fPIC -O2 7 | 8 | Decoder.o: Decoder.cpp Decoder.h 9 | $(CC) Decoder.cpp -o Decoder.o -c $(CFLAGS) 10 | Encoder.o: Encoder.cpp Encoder.h 11 | $(CC) Encoder.cpp -o Encoder.o -c $(CFLAGS) 12 | Generators.o: Generators.cpp Generators.h 13 | $(CC) Generators.cpp -o Generators.o -c $(CFLAGS) 14 | Helper.o: Helper.cpp Helper.h 15 | $(CC) Helper.cpp -o Helper.o -c $(CFLAGS) 16 | Main.o: Main.cpp 17 | $(CC) Main.cpp -o Main.o -c $(CFLAGS) 18 | StdAfx.o: StdAfx.cpp StdAfx.h 19 | $(CC) StdAfx.cpp -o StdAfx.o -c $(CFLAGS) 20 | Symbol.o: Symbol.cpp Symbol.h 21 | $(CC) Symbol.cpp -o Symbol.o -c $(CFLAGS) 22 | main: Decoder.o Encoder.o Generators.o Helper.o Main.o StdAfx.o Symbol.o 23 | $(CC) Decoder.o Encoder.o Generators.o Helper.o Main.o StdAfx.o Symbol.o -o main 24 | 25 | libraptorq: libraptorq.a 26 | libraptorq.a: Decoder.o Encoder.o Generators.o Helper.o Symbol.o 27 | ar rcs libraptorq.a $^ 28 | # $(CC) -shared -o $@ $^ $(LDFLAGS) 29 | 30 | clean: 31 | rm -f *.o main libraptorq.so libraptorq.a libraptor.dll 32 | -------------------------------------------------------------------------------- /Helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "string.h" 5 | #include 6 | #include "Encoder.h" 7 | #include "Decoder.h" 8 | #include "Generators.h" 9 | #include 10 | 11 | #define max(a,b) (((a) > (b)) ? (a) : (b)) 12 | #define min(a,b) (((a) < (b)) ? (a) : (b)) 13 | 14 | struct PartitionS { 15 | int IL; 16 | int IS; 17 | int JL; 18 | int JS; 19 | }; 20 | 21 | class Helper { 22 | public: 23 | Helper(); 24 | virtual ~Helper(); 25 | 26 | private: 27 | int Kmax; 28 | int P; 29 | int F; 30 | int W; 31 | int Al; 32 | int Kmin; 33 | int Gmax; 34 | int G; 35 | int T; 36 | int Kt; 37 | int Z; 38 | int N; 39 | PartitionS KtZ; 40 | PartitionS TAlN; 41 | 42 | public: 43 | const int getKmax(); 44 | const int getP(); 45 | const int getF(); 46 | const int getW(); 47 | const int getAl(); 48 | const int getKmin(); 49 | const int getGmax(); 50 | const int getG(); 51 | const int getT(); 52 | const int getKt(); 53 | const int getZ(); 54 | const int getN(); 55 | const PartitionS getKtZ(); 56 | const PartitionS getTAlN(); 57 | 58 | public: 59 | bool init(int Al, int Kmin , int Gmax, int P, int F, int W); 60 | 61 | public: 62 | const PartitionS partition(int I, int J); 63 | 64 | public: 65 | void toString(); 66 | 67 | }; 68 | 69 | const static long Combin(int m, int n) { 70 | if (n==1||n==0) 71 | return m; 72 | if (n > m-n) { 73 | return Combin(m, m-n); 74 | } 75 | return (long)((double)Combin(m-1,n-1)*m/n); 76 | } -------------------------------------------------------------------------------- /Helper.cpp: -------------------------------------------------------------------------------- 1 | #include "Helper.h" 2 | 3 | Helper::Helper() { 4 | } 5 | 6 | Helper::~Helper() { 7 | } 8 | 9 | bool Helper::init(int Al, int Kmin, int Gmax, int P, int F, int W) { 10 | this->Al = Al; 11 | this->P = P; 12 | if (P % Al != 0) { 13 | return false; 14 | } 15 | this->Kmin = Kmin; 16 | this->Kmax = 8192; 17 | this->Gmax = Gmax; 18 | this->F = F; 19 | this->W = W; 20 | 21 | this->G = min((min((int)ceil((double)P * Kmin /F), (int)P/Al)), Gmax); 22 | this->T = (int)floor((double)P/(Al*G)) * Al; 23 | this->Kt = (int)ceil((double)F/T); 24 | this->Z = (int)ceil((double)Kt/Kmax); 25 | this->N = min((int)ceil(ceil((double)Kt/Z)*T/W),(int)T/Al); 26 | 27 | if (ceil(ceil((double)F/T)/Z) > Kmax) { 28 | return false; 29 | } 30 | 31 | this->KtZ = partition(Kt, Z); 32 | this->TAlN = partition(T/Al, N); 33 | 34 | return true; 35 | }; 36 | 37 | const PartitionS Helper::partition(int I, int J) { 38 | PartitionS result; 39 | result.IL = (int)ceil((double)I/J); 40 | result.IS = (int)floor((double)I/J); 41 | result.JL = I - result.IS * J; 42 | result.JS = J - result.JL; 43 | 44 | return result; 45 | } 46 | 47 | 48 | const int Helper::getKmax() { 49 | return Kmax; 50 | } 51 | 52 | const int Helper::getP() { 53 | return P; 54 | } 55 | 56 | const int Helper::getF() { 57 | return F; 58 | } 59 | 60 | const int Helper::getW() { 61 | return W; 62 | } 63 | 64 | const int Helper::getAl() { 65 | return Al; 66 | } 67 | 68 | const int Helper::getKmin() { 69 | return Kmin; 70 | } 71 | 72 | const int Helper::getGmax() { 73 | return Gmax; 74 | } 75 | 76 | const int Helper::getG() { 77 | return G; 78 | } 79 | 80 | const int Helper::getT() { 81 | return T; 82 | } 83 | 84 | const int Helper::getKt() { 85 | return Kt; 86 | } 87 | 88 | const int Helper::getZ() { 89 | return Z; 90 | } 91 | 92 | const int Helper::getN() { 93 | return N; 94 | } 95 | 96 | const PartitionS Helper::getKtZ() { 97 | return KtZ; 98 | } 99 | 100 | const PartitionS Helper::getTAlN() { 101 | return TAlN; 102 | } 103 | 104 | void Helper::toString() { 105 | std::cout<<"Kmax="<=P 69 | int U; // P - H 70 | int B; // W - S 71 | int H1; //ceil(H/2) 72 | 73 | int L; //K+S+H 74 | int N; //received symbol number; set to K1 for encoder 75 | int N1; //received symbol plus extended one 76 | int M; //N+S+H 77 | TuplS *Tuples; //Tuples list 78 | int tupl_len; 79 | Symbol **C1; // size M: S+H zero + N symbols 80 | Symbol **C; // L intermediate symbols 81 | char **sources; // pointer to original source array 82 | Symbol **R; // repair symbols 83 | Elem **A; // generator matrix 84 | Elem **Abak; //backup of A 85 | #ifdef SPARSE 86 | int *rowh; // row list head 87 | int *colh; // column list head 88 | #endif 89 | Degree *degree; //number of 1 in row i 90 | int dgh; // degree list head 91 | int *isi; //Encoding Symbol ID list 92 | int status; /* 1: para inited, 2: source filled 3: intermediate generated 4: repair generated */ 93 | 94 | public: 95 | const TuplS Tupl(int X); 96 | const unsigned int RandYim(unsigned int y, unsigned char i,unsigned int m); 97 | const unsigned int Deg(unsigned int v); 98 | Symbol* LTEnc(Symbol** C_L, TuplS tupl); 99 | void verify(void); 100 | void PrintMatrix(); 101 | void ToString(); 102 | 103 | }; 104 | 105 | extern unsigned char octmul(unsigned char u, unsigned char v); 106 | extern unsigned char octdiv(unsigned char u, unsigned char v); 107 | 108 | -------------------------------------------------------------------------------- /Symbol.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include 3 | #include 4 | 5 | #include "Symbol.h" 6 | #include "Generators.h" 7 | 8 | using namespace std; 9 | 10 | Symbol::Symbol(void) 11 | { 12 | nbytes = 0; 13 | data = NULL; 14 | sbn = -1; 15 | esi = -1; 16 | } 17 | 18 | Symbol::Symbol(unsigned int size) 19 | { 20 | if (size % sizeof(int) != 0) { 21 | cout << "size must be a multiple of %d bytes" << endl; 22 | } 23 | 24 | data = new int[size/sizeof(int)]; 25 | memset(data, 0, size); 26 | nbytes = size; 27 | } 28 | 29 | Symbol::~Symbol(void) 30 | { 31 | if (data) delete[] data; 32 | nbytes = 0; 33 | } 34 | 35 | void Symbol::init(int size) 36 | { 37 | if (nbytes != size) { 38 | if (data) delete[] data; 39 | if (size % sizeof(int) != 0) { 40 | cout << "size must be a multiple of %d bytes" << endl; 41 | } 42 | nbytes = size; 43 | data = new int[size/sizeof(int)]; 44 | } 45 | memset(data, 0, size); 46 | } 47 | 48 | void Symbol::fillData(char *src, int size) 49 | { 50 | if (nbytes != size) { 51 | if (data) delete[] data; 52 | nbytes = size; 53 | data = new int[size/sizeof(int)]; 54 | } 55 | memcpy(data, src, size); 56 | } 57 | 58 | void Symbol::print(void) 59 | { 60 | int i; 61 | 62 | for (i=0; i< nbytes; i++) 63 | { 64 | cout << data[i] << " "; 65 | } 66 | cout << endl; 67 | 68 | } 69 | 70 | Symbol& Symbol::operator=(const Symbol &s) 71 | { 72 | if (nbytes != s.nbytes) { 73 | if (data) delete[] data; 74 | nbytes = s.nbytes; 75 | data = new int[nbytes/sizeof(int)]; 76 | } 77 | memcpy(data, s.data, s.nbytes); 78 | 79 | return *this; 80 | } 81 | 82 | Symbol& Symbol::operator^(const Symbol &s) 83 | { 84 | int i; 85 | 86 | if (nbytes != s.nbytes) 87 | cout << "Error! try to xor symbols with unmatched size" << endl; 88 | 89 | for (i=0;inbytes) 100 | cout << "Error! try to xor symbols with unmatched size" << endl; 101 | 102 | for (i=0;idata[i]; 104 | 105 | } 106 | 107 | void Symbol::mul(unsigned char u) 108 | { 109 | int i; 110 | unsigned char *p = (unsigned char*)data; 111 | 112 | for (i=0;inbytes) 131 | cout << "Error! try to muladd symbols with unmatched size" << endl; 132 | 133 | p = (unsigned char*)data; 134 | p1 = (unsigned char*)s->data; 135 | 136 | for (i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef WINDOWS 8 | #include "StdAfx.h" 9 | #include 10 | #include 11 | #endif 12 | 13 | #include 14 | 15 | #include "Helper.h" 16 | #include "Symbol.h" 17 | 18 | using namespace std; 19 | 20 | #define TEST 21 | 22 | time_t GetTickCount() 23 | { 24 | struct timeval t; 25 | 26 | gettimeofday(&t, NULL); 27 | 28 | return t.tv_sec * 1000 + t.tv_usec/1000; 29 | } 30 | 31 | int main(int argc, char* argv[]) { 32 | 33 | #ifdef TEST 34 | /* 35 | Helper helper; 36 | 37 | int al = 4; 38 | int kmin = 128; 39 | int gmax = 16; 40 | int packagesize = 1024; 41 | int w = 4096000; 42 | int overhead = 20; 43 | double loss = 0.1; 44 | int size = 256 * 1024; 45 | 46 | bool ret = helper.init(al,kmin,gmax,packagesize,size,w); 47 | 48 | if (ret) 49 | helper.toString(); 50 | else 51 | cout<<"error"<init(K,T); 117 | 118 | repairs = encoder->encode(source, overhead); 119 | 120 | end = GetTickCount(); 121 | 122 | cout << "encode bandwidth=" << K * T / ((end - start) * 1000.0) << "MB/s" << endl; 123 | 124 | /* send in packet erasure channel */ 125 | srand((unsigned)time(NULL)); 126 | 127 | char **received = new char*[K + overhead]; 128 | for (i=0;i lossrate && i!=2) { 140 | memcpy(received[n], source[i], T); 141 | esi[n] = i; 142 | n++; 143 | } else { 144 | lost[l++] = i; 145 | } 146 | } 147 | 148 | /* send repairs */ 149 | for (i=0; i< overhead; i++) { 150 | if (rand()/(RAND_MAX + 1.0) > lossrate) { 151 | memcpy(received[n], repairs[i]->data, T); 152 | esi[n] = K + i; 153 | n++; 154 | } 155 | delete repairs[i]; 156 | } 157 | delete[] repairs; 158 | 159 | cout << "Received " << n << " packets out of total " << K + overhead << endl; 160 | 161 | /* decode */ 162 | int no_decode = 0, success_decode = 0; 163 | int failed_decode1 = 0, failed_decode2 = 0, failed_decode3 = 0; 164 | Decoder *decoder; 165 | 166 | start = GetTickCount(); 167 | 168 | if (l == 0) { 169 | cout << "All source arrived!" << endl; 170 | no_decode ++; 171 | } else { 172 | if ( n < K ) { 173 | cout << "Too few packets got " << n << endl; 174 | failed_decode1++; 175 | } else { 176 | Symbol *s; 177 | 178 | decoder = new Decoder(); 179 | decoder->init(K,T); 180 | 181 | if (decoder->decode(received, n, esi)) { 182 | for (i=0;i < l; i++) { 183 | s = decoder->recover(lost[i]); 184 | #if 1 185 | if (memcmp(s->data, source[lost[i]], T)!=0) { 186 | cout << "Recoverd symbol is not correct! x=" << lost[i] << endl; 187 | failed_decode3++; 188 | //break; 189 | } else { 190 | cout << "Recoverd symbol is ok! x=" << lost[i] << endl; 191 | } 192 | #endif 193 | delete s; 194 | } 195 | cout << "All lost symbol recovered!" << endl; 196 | success_decode ++; 197 | }else{ 198 | cout << "Decode failed" << endl; 199 | failed_decode2++; 200 | } 201 | 202 | delete decoder; 203 | } 204 | } 205 | 206 | end = GetTickCount(); 207 | 208 | cout << "decode bandwidth=" << K * T / ((end - start) * 1000.0) << "MB/s" << endl; 209 | 210 | 211 | for (i=0;i 56403) { 53 | cout << "Invalid K, should in [1,56403]\n"; 54 | return false; 55 | } 56 | 57 | if (_N < _K) { 58 | cout << "N should not be smaller than K\n"; 59 | return false; 60 | } 61 | 62 | K = _K; 63 | T = _T; 64 | N = _N; 65 | 66 | I=0; 67 | while (K > lookup_table[I][0]) 68 | I++; 69 | 70 | K1 = lookup_table[I][0]; 71 | J_K = lookup_table[I][1]; 72 | S = lookup_table[I][2]; 73 | H = lookup_table[I][3]; 74 | W = lookup_table[I][4]; 75 | 76 | N1 = K1 - K + N; 77 | 78 | L = K1 + S + H; 79 | M = N1 + S + H; 80 | 81 | P = L - W; 82 | U = P - H; 83 | B = W - S; 84 | 85 | H1 = (int)ceil(H/2.0); 86 | 87 | //P1 be the smallest prime that is greater than or equal to P 88 | int _P1_len = P; 89 | int flag = false; 90 | while(!flag) 91 | { 92 | for(i = 2; i <= sqrt((double)_P1_len); i++) 93 | { 94 | if(_P1_len % i == 0) 95 | { 96 | _P1_len++; 97 | flag = false; 98 | break; 99 | } 100 | else 101 | flag = true; 102 | } 103 | } 104 | 105 | P1 = _P1_len; 106 | 107 | try { 108 | 109 | C1 = new Symbol*[M]; 110 | for (i = 0; i < M; i++) 111 | C1[i] = new Symbol(T); 112 | 113 | C = new Symbol*[L]; 114 | for (i = 0; i < L; i++) { 115 | C[i] = new Symbol(T); 116 | C[i]->esi = i; 117 | } 118 | 119 | R = NULL; 120 | 121 | A = new Elem*[M]; 122 | for(i = 0; i < (M); i++) 123 | A[i] = new Elem[L]; 124 | 125 | Abak = new Elem*[M]; 126 | for(i = 0; i < (M); i++) 127 | Abak[i] = new Elem[L]; 128 | 129 | 130 | for( i = 0; i < (M); i++) 131 | { 132 | for(j = 0; j < (L); j++) 133 | A[i][j].val = 0; 134 | //memset(&A[i][j], 0, sizeof(Elem)); 135 | } 136 | 137 | 138 | 139 | /* isi[i]=i for encoder; 140 | for decoder, isi[i] == the ESI for the ith received symbol for i in[0,N), ==i-N+K for [N,N1) */ 141 | 142 | isi = new int[N1]; 143 | for (i=0;iTuples = new TuplS[M + MAX_OVERHEAD]; 166 | } catch ( bad_alloc &e) { 167 | cout << "Allocate Tuples[] failed!" << e.what() << endl; 168 | abort(); 169 | } 170 | 171 | for (i=0; i < M + MAX_OVERHEAD; i++) { 172 | Tuples[i] = Tupl(i); 173 | } 174 | 175 | tupl_len = M + MAX_OVERHEAD; 176 | 177 | } 178 | 179 | /* Generate the LDPC rows of matrix A */ 180 | void Generators::_2_Matrix_GLDPC() { 181 | int i; 182 | int a,b; 183 | 184 | /* G_LDPC,1 */ 185 | for(i = 0; i < B; i++) 186 | { 187 | a = 1 + i / S; 188 | b = i % S; 189 | A[b][i].val = 1; 190 | 191 | b = (b + a) % S; 192 | A[b][i].val = 1; 193 | 194 | b = (b + a) % S; 195 | A[b][i].val = 1; 196 | } 197 | 198 | /* identity part */ 199 | for(i = 0; i < S; i++) 200 | A[i][B + i].val = 1; 201 | 202 | /* G_LDPC,2 */ 203 | for (i = 0; i < S; i++) { 204 | a = i % P; 205 | b = (i + 1) % P; 206 | A[i][W + a].val = 1; 207 | A[i][W + b].val = 1; 208 | } 209 | 210 | return ; 211 | } 212 | 213 | /* Generate G_HDPC */ 214 | void Generators::_3_Matrix_GHDPC() 215 | { 216 | int i,j,k; 217 | 218 | for (j=0; j< K1 + S - 1; j++) { 219 | i = RandYim(j+1, 6, H); 220 | A[S+i][j].val = 1; 221 | i = (RandYim(j+1, 6, H) + RandYim(j+1, 7, H - 1) + 1) % H; 222 | A[S+i][j].val = 1; 223 | } 224 | 225 | for (i=S; i < S + H; i++) { 226 | A[i][K1 + S - 1].val = OCT_EXP[i-S]; 227 | } 228 | 229 | for (i=S; i< S + H; i++) { 230 | for (j=0; j < K1 + S; j++) { 231 | unsigned char tmp = 0; 232 | for (k=j; k < K1 + S; k++) 233 | if (A[i][k].val) tmp ^= octmul(A[i][k].val,OCT_EXP[k - j]); 234 | A[i][j].val = tmp; 235 | } 236 | } 237 | 238 | /* identity part */ 239 | for(i = S; i < (S + H ) ; i++) 240 | A[i][K1 + i].val = 1; 241 | 242 | return; 243 | } 244 | 245 | /* LT rows of maxtrix A */ 246 | void Generators::_4_Matrix_GLT() 247 | { 248 | int i,j; 249 | int a,b,d; 250 | 251 | TuplS tupl; 252 | 253 | int flag1 = 0; 254 | 255 | i = 0; 256 | while(i < N1) 257 | { 258 | if ( isi[i] < tupl_len) 259 | tupl = Tuples[isi[i]]; 260 | else 261 | tupl = Tupl(isi[i]); 262 | 263 | a = tupl.a; 264 | b = tupl.b; 265 | d = tupl.d; 266 | 267 | A[S + H + i][b].val = 1; 268 | 269 | for(j = 1; j < d; j++) 270 | { 271 | b = (b + a) % W; 272 | A[S + H + i][b].val = 1; 273 | } 274 | 275 | a = tupl.a1; 276 | b = tupl.b1; 277 | d = tupl.d1; 278 | 279 | while (b >= P) 280 | b = (b + a) % P1; 281 | A[S + H + i][W + b].val = 1; 282 | 283 | for(j = 1; j < d; j++) 284 | { 285 | b = (b + a) % P1; 286 | while(b >= P) 287 | b = (b + a) % P1; 288 | A[S + H + i][W + b].val = 1; 289 | } 290 | 291 | i++; 292 | } 293 | 294 | return; 295 | } 296 | 297 | 298 | /* LT encoder 299 | arg: 300 | _K is K1 301 | C_L is the intermediate symbols 302 | tupl is the Tuple for giving ESI x 303 | return: 304 | pointer to encoded symbol 305 | caller need to handle the delete of symbol space 306 | */ 307 | Symbol* Generators::LTEnc(Symbol** C_L ,TuplS tupl) { 308 | int a = tupl.a; 309 | int b = tupl.b; 310 | int d = tupl.d; 311 | Symbol *s; 312 | 313 | s = new Symbol(T); 314 | 315 | *s = *C_L[b]; 316 | for (int j=1; j < d; j++) { 317 | b=(b + a) % W; 318 | s->xxor(C_L[b]); 319 | } 320 | 321 | a = tupl.a1; 322 | b = tupl.b1; 323 | d = tupl.d1; 324 | 325 | while (b >= P) 326 | b = (b + a) % P1; 327 | s->xxor(C_L[W + b]); 328 | 329 | for(int j = 1; j < d; j++) 330 | { 331 | b = (b + a) % P1; 332 | while(b >= P) 333 | b = (b + a) % P1; 334 | s->xxor(C_L[W + b]); 335 | } 336 | 337 | return s; 338 | } 339 | 340 | /* Tuple generator */ 341 | const TuplS Generators::Tupl(int X) { 342 | TuplS tupl; 343 | 344 | unsigned int A = (53591 + J_K*997); 345 | if (A % 2 == 0) A = A + 1; 346 | unsigned int B = 10267*(J_K + 1); 347 | unsigned int y = (B + X*A); 348 | 349 | int v = RandYim(y,0,1048576); 350 | tupl.d = Deg(v); 351 | tupl.a = 1 + RandYim(y, 1, W - 1); 352 | tupl.b = RandYim(y, 2, W); 353 | 354 | if (tupl.d < 4) tupl.d1 = 2 + RandYim(X, 3, 2); else tupl.d1 = 2; 355 | tupl.a1 = 1 + RandYim(X, 4, P1 - 1); 356 | tupl.b1 = RandYim(X, 5, P1); 357 | 358 | return tupl; 359 | } 360 | 361 | 362 | const unsigned int Generators::RandYim(unsigned int y, unsigned char i,unsigned int m) { 363 | return (V0[((y & 0xff) +i) & 0xff] ^ V1[(((y>>8) & 0xff) + i) & 0xff] ^ V2[(((y>>16) & 0xff) + i) & 0xff] ^ V3[(((y>>24) & 0xff) + i) & 0xff]) % m; 364 | } 365 | 366 | 367 | /* find j, f[j-1] <= v f[j]) 374 | j++; 375 | return min(j, W - 2); 376 | } 377 | 378 | /* clean up leftovers of last run, fill in new source block; 379 | called by the encoder/decoder, it can be called many times 380 | encoder->init 381 | while(get more source) { 382 | prepare 383 | decode 384 | } 385 | arg: 386 | source: source symbol list with Length _N 387 | _esi: the ESI list for the source list 388 | return: 389 | success or not 390 | */ 391 | bool Generators::prepare(char **source, int _N, int *_esi) { 392 | 393 | int i,j; 394 | 395 | if (_N < K) { 396 | cout << "Invalid N in prepare!" << N << endl; 397 | return false; 398 | } 399 | 400 | if (status != 1) { 401 | 402 | /* Not the first run, recover A; 403 | */ 404 | for( i = 0; i < (M); i++) 405 | { 406 | for(j = 0; j < (L); j++) 407 | A[i][j] = Abak[i][j]; 408 | } 409 | } 410 | 411 | status = 2; 412 | 413 | try { 414 | /* only decoder will provide esi(for each source block) */ 415 | if (_esi) { 416 | int _N1 = _N + K1 - K; 417 | 418 | /* maxtrix LT parts changed, the data struct is not efficent now */ 419 | for (i=0; i < M ;i++) 420 | delete []A[i]; 421 | delete []A; 422 | 423 | A = new Elem*[_N1 + S + H]; 424 | for(i = 0; i < (_N1 + S + H); i++) 425 | A[i] = new Elem[L]; 426 | 427 | for(i = 0; i < (_N1 + S + H); i++) 428 | { 429 | for(j = 0; j < (L); j++) 430 | if (i < S + H) 431 | A[i][j] = Abak[i][j]; 432 | else 433 | A[i][j].val = 0; 434 | } 435 | 436 | for (i=0; i < M ;i++) 437 | delete []Abak[i]; 438 | delete []Abak; 439 | 440 | Abak = new Elem*[_N1 + S + H]; 441 | for(i = 0; i < (_N1 + S + H); i++) 442 | Abak[i] = new Elem[L]; 443 | 444 | for(i = 0; i < (_N1 + S + H); i++) 445 | { 446 | for(j = 0; j < (L); j++) 447 | if (i < S + H) 448 | Abak[i][j] = A[i][j]; 449 | else 450 | Abak[i][j].val = 0; 451 | 452 | } 453 | 454 | 455 | delete[] degree; 456 | degree = new Degree[_N1 + S + H]; 457 | 458 | for (i = 0; i < M; i++) 459 | delete C1[i]; 460 | delete[] C1; 461 | 462 | this->C1 = new Symbol*[_N1 + S + H]; 463 | for (i = 0; i < _N1 + S + H; i++) 464 | C1[i] = new Symbol(T); 465 | 466 | M = _N1 + S + H; 467 | N = _N; 468 | N1 = _N1; 469 | 470 | delete[] isi; 471 | 472 | isi = new int[N1]; 473 | 474 | for (i = 0; i < N; i++) { 475 | if (_esi[i] < K) 476 | isi[i] = _esi[i]; 477 | else 478 | isi[i] = _esi[i] + K1 - K; 479 | } 480 | /* K1 - K (N1 - N) padding symbols */ 481 | for (i=N; i < N1; i++) 482 | isi[i] = i - N + K; 483 | 484 | _4_Matrix_GLT(); 485 | 486 | for (i = S + H; i < M; i++) 487 | for (j=0; j < L; j++) 488 | Abak[i][j] = A[i][j]; 489 | 490 | } 491 | } catch ( bad_alloc &e) { 492 | cout << "Allocation in prepare() failed!" << e.what() << endl; 493 | abort(); 494 | } 495 | 496 | 497 | for (i=0; iinit(T); 499 | C[i]->esi = i; 500 | } 501 | 502 | for (i=S + H; i< M; i++) 503 | if (i < S + H + N) 504 | C1[i]->fillData(source[i - S - H],T); 505 | else //padding 506 | C1[i]->init(T); 507 | 508 | sources = source; 509 | 510 | return true; 511 | } 512 | 513 | void Generators::swap_row(int i1, int i2) 514 | { 515 | if (i1 == i2) return; 516 | 517 | Elem *e; 518 | e = A[i1]; 519 | A[i1] = A[i2]; 520 | A[i2] = e; 521 | 522 | Degree d = degree[i1]; 523 | degree[i1] = degree[i2]; 524 | degree[i2] = d; 525 | 526 | 527 | Symbol *s; 528 | s = C1[i1]; 529 | C1[i1] = C1[i2]; 530 | C1[i2] = s; 531 | 532 | } 533 | 534 | void Generators::swap_col(int j1, int j2) 535 | { 536 | if (j1 == j2) return; 537 | 538 | for (int i=0; ixxor(C1[i2]); 561 | } 562 | 563 | int Generators::gaussian_elimination(int starti, int startj) 564 | { 565 | int i, k, q, jj, kk; 566 | int firstone; 567 | 568 | int* HI = new int[L]; 569 | int* LOW = new int[M]; 570 | 571 | for (jj=startj; jj 0) { 605 | int t = LOW[0]; 606 | LOW[0] = LOW[firstone]; 607 | LOW[firstone] = t; 608 | } 609 | 610 | 611 | if (A[LOW[0]][jj].val != 1) { 612 | unsigned char v = A[LOW[0]][jj].val; 613 | 614 | C1[LOW[0]]->div(v); 615 | for (q=jj; qmuladd(C1[LOW[0]],v); 624 | 625 | for (q=jj; qmuladd(C1[LOW[0]], v); 634 | 635 | for (q=jj; qinit(T); 669 | for (j = 0; j < L; j++) { 670 | if (Abak[i][j].val) 671 | s->muladd(C[j], Abak[i][j].val); 672 | } 673 | 674 | if (i < S + H || i >= S + H + N) 675 | p = (char*)s1->data; 676 | else 677 | p = (char*)sources[i - S - H]; 678 | 679 | if (memcmp(s->data, p, T) != 0) { 680 | printf("Check fail for line %d,%x vs %x\n", i, *(int*)s->data, *(int*)p); 681 | } 682 | } 683 | 684 | delete s; 685 | delete s1; 686 | } 687 | 688 | 689 | /* core decode algorithm here. Calculate C from equation A * C = C1 690 | return the intermediate symbol list C, NULL if decode fail 691 | */ 692 | Symbol ** Generators::generate_intermediates(void) 693 | { 694 | 695 | /* calculate A^^-1 to get intermediate symbol list C by Gaussian elimination */ 696 | 697 | if (status != 2) { 698 | cout << "Wrong call sequence! Filling the source block before generate intermediates" << endl; 699 | return NULL; 700 | } 701 | 702 | //#define GAUSSIAN 703 | #define RFC6330 704 | 705 | #ifdef GAUSSIAN 706 | int i; 707 | if (!gaussian_elimination(0,0)) return NULL; 708 | #endif 709 | 710 | #ifdef RFC6330 711 | int* cols1 = new int[L]; 712 | int* cols2 = new int[L]; 713 | 714 | int k1,k2; 715 | 716 | /* init degree list */ 717 | int i,j,d,gtone; 718 | for (i = 0; i < M; i++) 719 | { 720 | d = 0; 721 | gtone = 0; 722 | for (j=0; j < L - P; j++) 723 | if (A[i][j].val) { 724 | d++; 725 | if (A[i][j].val > 1) gtone++; 726 | } 727 | degree[i].curr = degree[i].ori = d; 728 | degree[i].gtone = gtone; 729 | } 730 | 731 | PrintMatrix(); 732 | 733 | /* step 1 */ 734 | int _I, _U, r; 735 | int gtone_start = 0; 736 | 737 | _I = 0; 738 | _U = P; 739 | 740 | while (_I + _U < L) { 741 | int index, o; 742 | 743 | //select minimal current degree with minimal original degree 744 | //gtone == 0 first 745 | retry: 746 | index = M; o = L; r = L; 747 | for (i = _I; i < M; i ++) { 748 | if ((gtone_start || (gtone_start==0 && degree[i].gtone==0)) && degree[i].curr > 0 && degree[i].curr <= r) { 749 | index = i; 750 | if (degree[i].curr < r || (degree[i].curr == r && degree[i].ori < o)) { 751 | o = degree[i].ori; 752 | r = degree[i].curr; 753 | } 754 | } 755 | } 756 | 757 | if (index == M) { 758 | if (gtone_start) goto retry; 759 | cout << "Cannot find enough rows to decode" << endl; 760 | PrintMatrix(); 761 | return NULL; 762 | } 763 | 764 | swap_row(_I, index); 765 | 766 | #ifdef DEBUG 767 | cout << "swap row:" << I << "index" << index << endl; 768 | PrintMatrix(); 769 | #endif 770 | 771 | k1 = k2 = 0; 772 | for (j = _I; j < L - _U; j++) { 773 | if (j < L - _U - r + 1) { 774 | if (A[_I][j].val != 0 ) { 775 | cols1[k1++] = j; 776 | } 777 | } else { 778 | if (A[_I][j].val == 0) 779 | cols2[k2++] = j; 780 | } 781 | } 782 | 783 | if (k1 != k2 + 1) { 784 | printf("Assert fail: %d!= %d + 1, _I=%d\n", k1, k2, _I); 785 | return NULL; 786 | //PrintMatrix(); 787 | } 788 | 789 | /* put one nonezero to [_I][_I], r-1 1 to [L-_U-r+1,L-_U) */ 790 | swap_col(_I,cols1[0]); 791 | //cout << "swap col:" << _I << "," << cols1[0] << endl; 792 | //PrintMatrix(); 793 | for (j=0; j 1) { 800 | unsigned char v = A[_I][_I].val; 801 | 802 | C1[_I]->div(v); 803 | for (j=_I; j 1) degree[i].gtone--; 814 | for (j = L - _U - (r - 1); j < L; j++) { 815 | int oldv = A[i][j].val; 816 | A[i][j].val ^= octmul(v, A[_I][j].val); 817 | if (j < L - _U) { 818 | if (A[i][j].val > 0) { 819 | degree[i].curr ++; 820 | if (A[i][j].val > 1) degree[i].gtone ++; 821 | } 822 | if (oldv > 0) { 823 | degree[i].curr --; 824 | if (oldv > 1) degree[i].gtone --; 825 | } 826 | } 827 | } 828 | C1[i]->muladd(C1[_I], v); 829 | } 830 | 831 | /* we calculate only the intersect part of A&V 832 | Note: lines with A[i][_I] == 0 also needs this 833 | */ 834 | for (j=L - _U - (r - 1); j < L - _U; j++) 835 | if (A[i][j].val) { 836 | degree[i].curr--; 837 | if (A[i][j].val > 1) degree[i].gtone--; 838 | } 839 | } 840 | 841 | _I++; 842 | _U += r - 1; 843 | } 844 | delete[] cols1; 845 | delete[] cols2; 846 | 847 | cout << "_I=" << _I << "_U=" << _U << endl; 848 | //PrintMatrix(); 849 | 850 | /* step 2 */ 851 | //gaussian elimination on the (M - _I) x _U matrix 852 | if (!gaussian_elimination(_I, _I)) return NULL; 853 | //cout << "After Step 2" << endl; 854 | //PrintMatrix(); 855 | 856 | /* step 3 */ 857 | for (int jj=_I; jjmuladd(C1[jj],v); 863 | } 864 | } 865 | 866 | #ifdef DEBUG 867 | cout << "After Step 3" << endl; 868 | PrintMatrix(); 869 | #endif 870 | 871 | #endif 872 | 873 | /* result now in C1, copy to C; C1 is useless from now on */ 874 | for (i=0; iesi to remember the real pos of C[i] 876 | C1[i]->esi = C[i]->esi; 877 | } 878 | 879 | for (i=0; iesi]; 884 | C[C1[i]->esi] = C1[i]; 885 | C1[i] = s; 886 | } 887 | 888 | #if 0 889 | verify(); 890 | #endif 891 | 892 | status = 3; 893 | 894 | return C; 895 | } 896 | 897 | /*Generate repair symbols using LT encoder,must be called after C is calculated 898 | The ESI of generated symbols starts from K 899 | arg: 900 | count: number of repair symbols to generate 901 | Return: 902 | the list of request count of repair symbols 903 | */ 904 | Symbol **Generators::generate_repairs(int count) 905 | { 906 | int i, isi; 907 | 908 | if (status != 3) { 909 | cout << "Wrong call sequence! Generate intermediates before generate repairs" << endl; 910 | return NULL; 911 | } 912 | 913 | /* caller needs to free R */ 914 | R = new Symbol*[count]; 915 | 916 | /* 917 | for (i=0; i < count; i++) 918 | { 919 | R[i].init(T); 920 | } 921 | */ 922 | 923 | for (i = K; i < K + count; i++) 924 | { 925 | TuplS tupl; 926 | isi = i + K1 - K; 927 | if (isi < tupl_len) 928 | tupl = Tuples[isi]; 929 | else 930 | tupl = Tupl(isi); 931 | R[i - K] = LTEnc(C, tupl); 932 | } 933 | 934 | status = 4; 935 | 936 | return R; 937 | } 938 | 939 | Symbol *Generators::recover_symbol(int x) 940 | { 941 | Symbol *s; 942 | 943 | if (x >= K) { 944 | printf("try to recover non-source symbols!\n"); 945 | return NULL; 946 | } 947 | 948 | TuplS tupl; 949 | tupl = Tuples[x]; 950 | 951 | s = LTEnc(C, tupl); 952 | 953 | return s; 954 | } 955 | 956 | int Generators::getL() { 957 | return this->L; 958 | } 959 | 960 | int Generators::getK() { 961 | return this->K; 962 | } 963 | 964 | void Generators::PrintMatrix(void) 965 | { 966 | #ifdef DEBUG 967 | int i; 968 | cout<<"Press a number to print the generation matrix:" << endl; 969 | cin >> i; 970 | for (i=0; i < M ;i++) { 971 | for (int j=0; j < L;j++) 972 | printf("%2x ", A[i][j].val); 973 | cout<