├── LDPC_Code.sln ├── LDPC_Code ├── LDPC_Code.vcxproj ├── LDPC_decoder.cpp ├── LDPC_decoder.h ├── LDPC_encoder.cpp ├── LDPC_encoder.h ├── LDPC_generator.cpp ├── LDPC_generator.h ├── benchmark.cpp ├── benchmark.h ├── main.cpp ├── simple_bitarray.h └── test.cpp └── README.md /LDPC_Code.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LDPC_Code", "LDPC_Code\LDPC_Code.vcxproj", "{32DE328B-DC40-4947-853A-33A5C48A829E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {32DE328B-DC40-4947-853A-33A5C48A829E}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {32DE328B-DC40-4947-853A-33A5C48A829E}.Debug|Win32.Build.0 = Debug|Win32 16 | {32DE328B-DC40-4947-853A-33A5C48A829E}.Release|Win32.ActiveCfg = Release|Win32 17 | {32DE328B-DC40-4947-853A-33A5C48A829E}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(Performance) = preSolution 23 | HasPerformanceSessions = true 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /LDPC_Code/LDPC_Code.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {32DE328B-DC40-4947-853A-33A5C48A829E} 15 | LDPC_Code 16 | 17 | 18 | 19 | Application 20 | true 21 | v120 22 | MultiByte 23 | 24 | 25 | Application 26 | false 27 | v120 28 | true 29 | MultiByte 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Level3 45 | Disabled 46 | true 47 | 48 | 49 | true 50 | 51 | 52 | 53 | 54 | Level3 55 | MaxSpeed 56 | true 57 | true 58 | true 59 | 60 | 61 | true 62 | true 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /LDPC_Code/LDPC_decoder.cpp: -------------------------------------------------------------------------------- 1 | #include "LDPC_decoder.h" 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | static chrono::high_resolution_clock::time_point get_tick(){ 7 | return chrono::high_resolution_clock::now(); 8 | } 9 | static double get_duration(chrono::high_resolution_clock::time_point& t1, chrono::high_resolution_clock::time_point& t2){ 10 | std::chrono::duration time_span = std::chrono::duration_cast>(t2 - t1); 11 | return time_span.count(); 12 | } 13 | 14 | LDPC_bp_decoder::LDPC_bp_decoder(int _code_len, int _msg_len) : 15 | code_len(_code_len), msg_len(_msg_len), 16 | messages(NULL), data_nodes(NULL), msg_sign(NULL), error(NULL), 17 | check_to_data(NULL), check_to_data_id(NULL), check_to_data_id_mem(NULL), check_to_data_mem(NULL), check_degree(NULL), 18 | data_to_check(NULL),data_to_check_mem(NULL),data_degree(NULL) {} 19 | 20 | LDPC_bp_decoder::~LDPC_bp_decoder(){ 21 | if (messages)delete[] messages; 22 | if (data_nodes) delete[] data_nodes; 23 | if (error) delete[] error; 24 | if (msg_sign) delete[] msg_sign; 25 | if (check_to_data) delete[] check_to_data; 26 | if (check_to_data_mem) delete[] check_to_data_mem; 27 | if (check_to_data_id) delete[] check_to_data_id; 28 | if (check_to_data_id_mem) delete[] check_to_data_id_mem; 29 | if (check_degree) delete[] check_degree; 30 | if (data_degree) delete[] data_degree; 31 | if (data_to_check)delete[] data_to_check; 32 | if (data_to_check_mem)delete[] data_to_check_mem; 33 | } 34 | 35 | 36 | 37 | bool LDPC_bp_decoder::init(LDPC_generator* gen){ 38 | auto res = gen->init(code_len, msg_len); 39 | if (res == LDPC_generator::GENERATOR_PROPERTY::INVALID)return false; 40 | 41 | auto g = gen->as_Tanner_graph(); 42 | 43 | //first: calc all the degrees 44 | int total = 0; 45 | int *p = new int[code_len + 1]; 46 | p[0] = 0; 47 | for (int i = 0; i < code_len; i++){ 48 | total += g->get_data_node(i).size(); 49 | p[i + 1] = total; 50 | } 51 | check_to_data = new int* [code_len - msg_len]; 52 | check_to_data_mem = new int[total]; 53 | check_degree = new int[code_len - msg_len]; 54 | 55 | data_to_check = new int* [code_len]; 56 | data_to_check_mem = new int[total]; 57 | data_degree = new int[code_len]; 58 | 59 | msg_sign = new bool[code_len]; 60 | 61 | messages = new double[total]; 62 | 63 | check_to_data_id_mem = new int[total]; 64 | check_to_data_id = new int*[code_len - msg_len]; 65 | 66 | for (int i = 0; i < code_len; i++){ 67 | data_to_check[i] = data_to_check_mem + p[i]; 68 | auto& nodes = g->get_data_node(i); 69 | data_degree[i] = nodes.size(); 70 | for (int j = 0; j < data_degree[i]; j++){ 71 | data_to_check[i][j] = p[i] + j; 72 | } 73 | } 74 | 75 | int total2 = 0; 76 | int check_len = code_len - msg_len; 77 | int* p2 = new int[check_len + 1]; 78 | check_to_data[0] = check_to_data_mem; 79 | check_to_data_id[0] = check_to_data_id_mem; 80 | for (int i = 0; i < check_len; i++){ 81 | auto& nodes = g->get_check_node(i); 82 | total2 += nodes.size(); 83 | if (i != check_len - 1){ 84 | p2[i + 1] = total2; 85 | check_to_data[i + 1] = check_to_data_mem + total2; 86 | check_to_data_id[i + 1] = check_to_data_id_mem + total2; 87 | } 88 | else assert(total2 == total); 89 | 90 | check_degree[i] = nodes.size(); 91 | for (int j = 0; j < check_degree[i]; j++){ 92 | check_to_data_id[i][j] = nodes[j]; 93 | auto& n2 = g->get_data_node(nodes[j]); 94 | int id = std::find(n2.begin(), n2.end(), i) - n2.begin(); 95 | check_to_data[i][j] = data_to_check[nodes[j]][id]; 96 | } 97 | } 98 | 99 | data_nodes = new double[code_len]; 100 | error = new double[code_len]; 101 | 102 | return true; 103 | } 104 | 105 | /*bool LDPC_bp_decoder::save_parities_to(const char* filename){ 106 | FILE* fp; 107 | fopen_s(&fp, filename, "w"); 108 | fprintf(fp, "%d %d\n", code_len, msg_len); 109 | 110 | }*/ 111 | bool LDPC_bp_decoder::init(const char* filename){ 112 | FILE* fp; 113 | fopen_s(&fp, filename, "rt"); 114 | int m; 115 | fscanf_s(fp, "%d%d", &code_len, &m); 116 | msg_len = code_len - m; 117 | 118 | //unused 119 | int cmax, rmax; 120 | fscanf_s(fp, "%d%d", &cmax, &rmax); 121 | 122 | check_degree = new int[code_len - msg_len]; 123 | data_degree = new int[code_len]; 124 | 125 | int* col_weight = new int[code_len+1]; 126 | col_weight[0] = 0; 127 | for (int i = 0; i < code_len; i++) { 128 | fscanf_s(fp, "%d", &data_degree[i]); 129 | col_weight[i + 1] = col_weight[i] + data_degree[i]; 130 | } 131 | int* row_weight = new int[m + 1]; 132 | row_weight[0] = 0; 133 | for (int j = 0; j < m; j++){ 134 | fscanf_s(fp, "%d", &check_degree[j]); 135 | row_weight[j + 1] = row_weight[j] + check_degree[j]; 136 | } 137 | 138 | assert(col_weight[code_len] == row_weight[m]); 139 | int total = col_weight[code_len]; 140 | 141 | check_to_data = new int*[code_len - msg_len]; 142 | check_to_data_mem = new int[total]; 143 | 144 | data_to_check = new int*[code_len]; 145 | data_to_check_mem = new int[total]; 146 | 147 | msg_sign = new bool[code_len]; 148 | 149 | messages = new double[total]; 150 | 151 | check_to_data_id_mem = new int[total]; 152 | check_to_data_id = new int*[code_len - msg_len]; 153 | 154 | data_nodes = new double[code_len]; 155 | error = new double[code_len]; 156 | 157 | int** data_to_check_id = new int*[code_len]; 158 | int* data_to_check_id_mem = new int[total]; 159 | 160 | for (int i = 0; i < code_len; i++){ 161 | data_to_check[i] = data_to_check_mem + col_weight[i]; 162 | data_to_check_id[i] = data_to_check_id_mem + col_weight[i]; 163 | data_degree[i] = col_weight[i + 1] - col_weight[i]; 164 | int j; 165 | for (j = 0; j < data_degree[i]; j++){ 166 | data_to_check[i][j] = col_weight[i] + j; 167 | fscanf_s(fp, "%d", &(data_to_check_id[i][j])); 168 | data_to_check_id[i][j]--; 169 | } 170 | 171 | for (; j < cmax; j++) { 172 | fscanf_s(fp, "%*d"); // skip the 0s (fillers) 173 | } 174 | } 175 | 176 | check_to_data[0] = check_to_data_mem; 177 | check_to_data_id[0] = check_to_data_id_mem; 178 | for (int i = 0; i < m; i++){ 179 | check_to_data[i] = check_to_data_mem + row_weight[i]; 180 | check_to_data_id[i] = check_to_data_id_mem + row_weight[i]; 181 | 182 | check_degree[i] = row_weight[i + 1] - row_weight[i]; 183 | int j; 184 | for (j = 0; j < check_degree[i]; j++){ 185 | fscanf_s(fp, "%d", &(check_to_data_id[i][j])); 186 | check_to_data_id[i][j]--; 187 | auto& n2 = data_to_check_id[check_to_data_id[i][j]]; 188 | int id = std::find(n2, n2+data_degree[check_to_data_id[i][j]], i) - n2; 189 | check_to_data[i][j] = data_to_check[check_to_data_id[i][j]][id]; 190 | } 191 | 192 | for (; j < rmax; j++) { 193 | fscanf_s(fp, "%*d"); // skip the 0s (fillers) 194 | } 195 | } 196 | 197 | delete[] data_to_check_id; 198 | delete[] data_to_check_id_mem; 199 | return true; 200 | } 201 | 202 | static inline double LLR(double d){ 203 | return log(d / (1 - d)); 204 | } 205 | bool LDPC_bp_decoder::check(const bit_array_t& data){ 206 | for (int i = 0; i < code_len - msg_len; i++){ 207 | auto check_node = check_to_data_id[i]; 208 | bool res = false; 209 | for (int j = 0; j < check_degree[i]; j++) 210 | res ^= data[check_node[j]]; 211 | if (res)return false; 212 | } 213 | return true; 214 | } 215 | 216 | bool LDPC_bp_decoder::decode_BSC(bit_array_t& data, double error_prob, int iterations){ 217 | for (int i = 0; i < code_len; i++)error[i] = data[i] ? (1 - error_prob) : error_prob; 218 | bool result = decode_BSC(data, error, iterations); 219 | return result; 220 | } 221 | 222 | bool LDPC_bp_decoder::decode_BEC(bit_array_t& data, bit_array_t& mask){ 223 | //first: initialize 224 | bool found = false; 225 | bool no_erasure = false; 226 | 227 | do{ 228 | found = false; 229 | no_erasure = true; 230 | for (int i = 0; i < code_len - msg_len; i++){ 231 | auto check_node = check_to_data_id[i]; 232 | int erasure_count = 0; 233 | int erasure_id = 0; 234 | bool other_xor = false; 235 | for (int j = 0; j < check_degree[i];j++){ 236 | if (!mask[check_node[j]]){ 237 | erasure_count++; 238 | erasure_id = check_node[j]; 239 | } 240 | else other_xor ^= data[check_node[j]]; 241 | } 242 | if (erasure_count > 0) 243 | no_erasure = false; 244 | if (erasure_count == 1){ 245 | data.set(erasure_id, other_xor); 246 | mask.set(erasure_id, true); 247 | found = true; 248 | } 249 | } 250 | } while (found&&!no_erasure); 251 | return no_erasure; 252 | } 253 | 254 | //just for test 255 | static void print_bitarr(const bit_array_t& src){ 256 | for (int i = 0; i < src.size(); i++) 257 | printf(src[i] ? "1" : "0"); 258 | printf("\n"); 259 | } 260 | 261 | inline double atanh2(double f){ 262 | return log((1 + f) / (1 - f)); 263 | } 264 | inline double trunc_atanh(double f){ 265 | if (-0.9999 < f && f < 0.9999)return atanh(f); 266 | else if (f < -0.9999)return -5; 267 | else return 5; 268 | } 269 | bool LDPC_bp_decoder::decode_BSC(bit_array_t& result, const double* data_prob, int iterations){ 270 | //first: initialze 271 | for (int i = 0; i < code_len; i++){ 272 | data_nodes[i] = LLR(data_prob[i]); 273 | auto data_node = data_to_check[i]; 274 | for (int j = 0; j < data_degree[i]; j++) 275 | messages[data_node[j]] = data_nodes[i]; 276 | } 277 | //second: bp 278 | for (int iter = 0; iter < iterations; iter++){ 279 | int m = code_len - msg_len; 280 | for (int i = 0; i < m; i++){ 281 | double total_msg = 0.0; 282 | bool sign = false; 283 | auto check_node = check_to_data[i]; 284 | for (int j = 0; j < check_degree[i];j++){ 285 | double t = tanh(messages[check_node[j]]*0.5); 286 | messages[check_node[j]] = log(fabs(t)); 287 | msg_sign[j] = t >= 0; 288 | sign ^= msg_sign[j]; 289 | total_msg += messages[check_node[j]]; 290 | } 291 | for (int j = 0; j < check_degree[i];j++){ 292 | messages[check_node[j]] = -atanh2(exp(total_msg - messages[check_node[j]])*((sign^msg_sign[j]) ? -1 : 1)); 293 | } 294 | } 295 | 296 | for (int i = 0; i < code_len; i++){ 297 | double total_LLR = data_nodes[i]; 298 | auto data_node = data_to_check[i]; 299 | for (int j = 0; j < data_degree[i];j++){ 300 | total_LLR += messages[data_node[j]]; 301 | } 302 | 303 | for (int j = 0; j < data_degree[i];j++){ 304 | messages[data_node[j]] = total_LLR - messages[data_node[j]]; 305 | } 306 | 307 | result.set(i, total_LLR>=0); 308 | } 309 | //check 310 | if (check(result)){ 311 | return true; 312 | } 313 | } 314 | 315 | return false; 316 | } 317 | bool LDPC_bp_decoder::decode_BSC(bit_array_t& data, int iterations){ 318 | //first: initialze 319 | bool* data_nodes_bin = (bool*)data_nodes; 320 | bool* messages_bin = (bool*)messages; 321 | 322 | for (int i = 0; i < code_len; i++){ 323 | data_nodes_bin[i] = data[i]; 324 | auto data_node = data_to_check[i]; 325 | for (int j = 0; j < data_degree[i];j++) 326 | messages_bin[data_node[j]] = data_nodes_bin[i]; 327 | } 328 | //second: bp 329 | for (int iter = 0; iter < iterations; iter++){ 330 | for (int i = 0; i < code_len - msg_len; i++){ 331 | bool msg_sum = false; 332 | auto check_node = check_to_data[i]; 333 | for (int j = 0; j < check_degree[i]; j++){ 334 | msg_sum ^= messages_bin[check_node[j]]; 335 | } 336 | for (int j = 0; j < check_degree[i]; j++){ 337 | messages_bin[check_node[j]] = msg_sum^messages_bin[check_node[j]]; 338 | } 339 | } 340 | for (int i = 0; i < code_len; i++){ 341 | auto data_node = data_to_check[i]; 342 | int pos = 0, neg = 0; 343 | for (int j = 0; j < data_degree[i];j++){ 344 | if (messages_bin[data_node[j]])pos++; 345 | else neg++; 346 | } 347 | 348 | int t = pos - neg + (data_nodes_bin[i] ? 1 : -1); 349 | for (int j = 0; j < data_degree[i];j++){ 350 | int tt = messages_bin[data_node[j]] ? (t - 1) : (t + 1); 351 | messages_bin[data_node[j]] = (tt == 0) ? data_nodes_bin[i] : (tt > 0); 352 | } 353 | data.set(i, t == 0 ? data_nodes_bin[i] : t > 0); 354 | } 355 | //check 356 | if (check(data)){ 357 | return true; 358 | } 359 | } 360 | 361 | return false; 362 | } -------------------------------------------------------------------------------- /LDPC_Code/LDPC_decoder.h: -------------------------------------------------------------------------------- 1 | #ifndef __LDPC_DECODER_H 2 | #define __LDPC_DECODER_H 3 | #include "LDPC_generator.h" 4 | #include "simple_bitarray.h" 5 | 6 | //belief-propagation decoder 7 | class LDPC_bp_decoder{ 8 | private: 9 | int code_len; 10 | int msg_len; 11 | 12 | double* messages; 13 | int** check_to_data; 14 | int* check_to_data_mem; 15 | int* check_degree; 16 | int** data_to_check; 17 | int* data_to_check_mem; 18 | int* data_degree; 19 | int** check_to_data_id; 20 | int* check_to_data_id_mem; 21 | 22 | bool* msg_sign; 23 | 24 | double* data_nodes; 25 | double* error; 26 | 27 | public: 28 | LDPC_bp_decoder(int code_len, int msg_len); 29 | ~LDPC_bp_decoder(); 30 | 31 | //init by a given generated parity check matrix 32 | bool init(LDPC_generator* generator); 33 | //init by a buffered sparse graph 34 | bool init(const char* filename); 35 | //check if a code is valid 36 | bool check(const bit_array_t& data); 37 | //soft-decision decoder for BSC 38 | bool decode_BSC(bit_array_t& data, double error_prob, int iterations=50); 39 | //hard-decision decoder for BEC 40 | bool decode_BEC(bit_array_t& data, bit_array_t& mask); 41 | //hard-decision decoder for generalized BEC 42 | template 43 | bool decode_BEC(T* arr, bit_array_t& mask){ 44 | //first: initialize 45 | bool found = false; 46 | bool no_erasure = false; 47 | 48 | do{ 49 | found = false; 50 | no_erasure = true; 51 | for (int i = 0; i < code_len - msg_len; i++){ 52 | auto check_node = check_to_data_id[i]; 53 | int erasure_count = 0; 54 | int erasure_id = 0; 55 | T other_xor; 56 | for (int j = 0; j < check_degree[i]; j++){ 57 | if (!mask[check_node[j]]){ 58 | erasure_count++; 59 | erasure_id = check_node[j]; 60 | } 61 | else other_xor ^= arr[check_node[j]]; 62 | } 63 | if (erasure_count > 0) 64 | no_erasure = false; 65 | if (erasure_count == 1){ 66 | arr[erasure_id] = other_xor; 67 | mask.set(erasure_id, true); 68 | found = true; 69 | } 70 | } 71 | } while (found&&!no_erasure); 72 | return no_erasure; 73 | } 74 | //soft-decision decoder for BSC, given all symbol's belief 75 | bool decode_BSC(bit_array_t& result, const double* data_prob, int iterations=50); 76 | //hard-decision decoder for BSC 77 | bool decode_BSC(bit_array_t& data, int iterations = 50); 78 | }; 79 | #endif -------------------------------------------------------------------------------- /LDPC_Code/LDPC_encoder.cpp: -------------------------------------------------------------------------------- 1 | #include "LDPC_encoder.h" 2 | #include 3 | #define INF 10000000 4 | LDPC_encoder::LDPC_encoder(int _code_len,int _msg_len): 5 | code_len(_code_len), 6 | msg_len(_msg_len){} 7 | 8 | static void print_bitarr(const bit_array_t& src){ 9 | for (int i = 0; i < src.size(); i++) 10 | printf(src[i] ? "1" : "0"); 11 | printf("\n"); 12 | } 13 | static void print_matrix(const binary_matrix& mat){ 14 | for (int i = 0; i < mat.height(); i++){ 15 | auto bitarr = mat[i]; 16 | print_bitarr(bitarr); 17 | } 18 | printf("\n"); 19 | } 20 | bool LDPC_encoder::init(LDPC_generator* generator, int& actual_msg_len){ 21 | auto res = generator->init(code_len, msg_len); 22 | int check_len = code_len - msg_len; 23 | if ((res&LDPC_generator::GENERATOR_PROPERTY::UPPER_TRIANGLE) == LDPC_generator::GENERATOR_PROPERTY::UPPER_TRIANGLE){ 24 | //directly map it 25 | auto graph = generator->as_Tanner_graph(); 26 | if ((res&LDPC_generator::GENERATOR_PROPERTY::FULL_RANK) == 0){ 27 | while (graph->get_check_node(check_len - 1).size() == 0)check_len--; 28 | } 29 | parities.reserve(check_len); 30 | 31 | for (int i = 0; i < check_len; i++)parity_nodes.push_back(i); 32 | for (int i = 0; i < check_len; i++){ 33 | std::vector parity; 34 | parities.push_back(parity); 35 | auto& parity_ref = parities[parities.size() - 1]; 36 | 37 | auto& covered = graph->get_check_node(i); 38 | parity_ref.reserve(covered.size()); 39 | for (auto it : covered){ 40 | parity_ref.push_back(it); 41 | } 42 | } 43 | actual_msg_len = code_len - check_len; 44 | return true; 45 | } 46 | else if ((res&LDPC_generator::GENERATOR_PROPERTY::PSEUDO_UPPER_TRIANGLE) == LDPC_generator::GENERATOR_PROPERTY::PSEUDO_UPPER_TRIANGLE){ 47 | //find the steps 48 | auto graph = generator->as_Tanner_graph(); 49 | if ((res&LDPC_generator::GENERATOR_PROPERTY::FULL_RANK) == 0){ 50 | while (graph->get_check_node(check_len - 1).size() == 0)check_len--; 51 | } 52 | parities.reserve(check_len); 53 | for (int i = 0; i < check_len; i++){ 54 | auto& covered = graph->get_check_node(i); 55 | parity_nodes.push_back(covered[0]); 56 | } 57 | 58 | for (int i = 0; i < check_len; i++){ 59 | auto& covered = graph->get_check_node(i); 60 | parities.push_back(std::vector()); 61 | auto& parity_ref = parities[parities.size() - 1]; 62 | parity_ref.reserve(covered.size()); 63 | for (auto it : covered)parity_ref.push_back(it); 64 | } 65 | actual_msg_len = code_len - check_len; 66 | return true; 67 | } 68 | else { 69 | //the default algo 70 | //first: initialize states 71 | auto graph = generator->as_Tanner_graph(); 72 | 73 | for (int i = 0; i < code_len; i++){ 74 | printf("encoder init: %d/%d checks\n", i, check_len); 75 | auto& data_node = graph->get_data_node(i); 76 | int degree = data_node.size(); 77 | if (degree == 0)continue; 78 | else if (degree != 1){ 79 | //first: choose the best one 80 | int smallest_degree = INF; 81 | int smallest_check = 0; 82 | for (auto it : data_node){ 83 | int _size; 84 | if ((_size = graph->get_check_node(it).size()) < smallest_degree){ 85 | smallest_degree = _size; 86 | smallest_check = it; 87 | } 88 | } 89 | 90 | //second: modify each 91 | auto smallest_node = graph->get_check_node(smallest_check); 92 | auto data_node_copy = data_node; 93 | for (auto it : data_node_copy){ 94 | if (it == smallest_check)continue; 95 | 96 | std::vector newrow; 97 | auto& check_node = graph->get_check_node(it); 98 | 99 | int t = 0, t2 = 0; 100 | for (; t2 < (int)(check_node.size()) && t < (int)(smallest_node.size());){ 101 | if (smallest_node[t] == check_node[t2]){ 102 | auto& _data_node = graph->get_data_node(smallest_node[t]); 103 | _data_node.erase(std::remove(_data_node.begin(), _data_node.end(), it), _data_node.end()); 104 | t++; t2++; 105 | } 106 | else if (smallest_node[t] < check_node[t2]){ 107 | newrow.push_back(smallest_node[t]); 108 | graph->get_data_node(smallest_node[t]).push_back(it); 109 | t++; 110 | } 111 | else{ 112 | newrow.push_back(check_node[t2]); 113 | t2++; 114 | } 115 | } 116 | for (; t < (int)(smallest_node.size()); t++){ 117 | newrow.push_back(smallest_node[t]); 118 | graph->get_data_node(smallest_node[t]).push_back(it); 119 | } 120 | for (; t2 < (int)(check_node.size()); t2++)newrow.push_back(check_node[t2]); 121 | 122 | graph->get_check_node(it) = newrow; 123 | } 124 | } 125 | //third: mark 126 | //select this node as parity 127 | //and remove this check node 128 | parity_nodes.push_back(i); 129 | assert(data_node.size() == 1); 130 | auto check_id = data_node[0]; 131 | auto& check_node = graph->get_check_node(check_id); 132 | parities.push_back(check_node); 133 | for (auto it : check_node){ 134 | auto& _data_node = graph->get_data_node(it); 135 | _data_node.erase(std::remove(_data_node.begin(), _data_node.end(), check_id), _data_node.end()); 136 | 137 | } 138 | } 139 | 140 | actual_msg_len = code_len - parities.size(); 141 | //save_parities_to("parities.txt"); 142 | return true; 143 | } 144 | } 145 | bool LDPC_encoder::init(const char* filename){ 146 | FILE* fp; 147 | fopen_s(&fp, filename, "r"); 148 | int size; 149 | fscanf_s(fp, "%d %d %d", &code_len, &msg_len, &size); 150 | parity_nodes.reserve(size); 151 | for (int i = 0; i < size; i++){ 152 | int t; 153 | fscanf_s(fp, "%d", &t); 154 | parity_nodes.push_back(t); 155 | } 156 | parities.reserve(size); 157 | for (int i = 0; i < size; i++){ 158 | parities.push_back(std::vector()); 159 | parities[i].clear(); 160 | int len; 161 | fscanf_s(fp, "%d", &len); 162 | parities[i].reserve(len); 163 | int t; 164 | for (int j = 0; j < len; j++){ 165 | fscanf_s(fp, "%d", &t); 166 | parities[i].push_back(t); 167 | } 168 | } 169 | return true; 170 | } 171 | bool LDPC_encoder::save_parities_to(const char* filename){ 172 | FILE* fp; 173 | fopen_s(&fp, filename, "w"); 174 | fprintf(fp, "%d %d %d\n", code_len, msg_len, parity_nodes.size()); 175 | for (unsigned int i = 0; i < parity_nodes.size();i++){ 176 | fprintf(fp, "%d\n", parity_nodes[i]); 177 | } 178 | for (unsigned int i = 0; i < parities.size(); i++){ 179 | auto& parity = parities[i]; 180 | fprintf(fp, "%d", parity.size()); 181 | for (unsigned int i = 0; i < parity.size(); i++) 182 | fprintf(fp, " %d", parity[i]); 183 | fprintf(fp, "\n"); 184 | } 185 | fclose(fp); 186 | return true; 187 | } 188 | 189 | void LDPC_encoder::encode(const bit_array_t& bitarr,bit_array_t& dest){ 190 | assert(dest.size() == code_len); 191 | dest.clear(); 192 | int size = parity_nodes.size(); 193 | for (int i = 0, it = 0; i < code_len; i++){ 194 | if (it < size && parity_nodes[it] == i)it++; 195 | else if (i - it < bitarr.size()){ 196 | dest.set(i, bitarr[i - it]); 197 | } 198 | } 199 | 200 | for (int i = parities.size() - 1; i >= 0;i--){ 201 | auto& parity = parities[i]; 202 | for (int i = parity.size() - 1; i > 0; i--) 203 | dest.xor(parity[0], dest[parity[i]]); 204 | } 205 | } -------------------------------------------------------------------------------- /LDPC_Code/LDPC_encoder.h: -------------------------------------------------------------------------------- 1 | #ifndef __LDPC_ENCODER_H 2 | #define __LDPC_ENCODER_H 3 | #include "LDPC_generator.h" 4 | #include 5 | 6 | //encode an LDPC code from a given parity check matrix/Tanner graph 7 | class LDPC_encoder{ 8 | private: 9 | int code_len; 10 | int msg_len; 11 | 12 | std::vector parity_nodes; 13 | 14 | std::vector> parities; 15 | public: 16 | LDPC_encoder(int code_len, int msg_len); 17 | ~LDPC_encoder(); 18 | 19 | //init by a generator 20 | bool init(LDPC_generator* generator, int& actual_msg_len); 21 | //init by a buffered matrix saved to filename 22 | bool init(const char* filename); 23 | //save the generated matrix to filename 24 | bool save_parities_to(const char* filename); 25 | 26 | //encode a bit array 27 | void encode(const bit_array_t& bitarr, bit_array_t& dest); 28 | //encode an arbitary array 29 | template 30 | void encode(const T* arr, int arrsize, T* dest){ 31 | int size = parity_nodes.size(); 32 | for (int i = 0, it = 0; i < code_len; i++){ 33 | if (it < size && parity_nodes[it] == i)it++; 34 | else if (i - it < arrsize){ 35 | dest[i] = arr[i - it]; 36 | } 37 | } 38 | 39 | for (int i = parities.size() - 1; i >= 0; i--){ 40 | auto& parity = parities[i]; 41 | for (int i = parity.size() - 1; i > 0; i--) 42 | dest[parity[0]] ^= dest[parity[i]]; 43 | } 44 | } 45 | }; 46 | #endif -------------------------------------------------------------------------------- /LDPC_Code/LDPC_generator.cpp: -------------------------------------------------------------------------------- 1 | #include "LDPC_generator.h" 2 | #include 3 | using namespace std; 4 | 5 | /////////////////////////// 6 | // miscellaneous // 7 | // // 8 | /////////////////////////// 9 | //enum OR operator 10 | inline LDPC_generator::GENERATOR_PROPERTY operator | (LDPC_generator::GENERATOR_PROPERTY p1,LDPC_generator::GENERATOR_PROPERTY p2){ 11 | return static_cast(static_cast(p1)|static_cast(p2)); 12 | 13 | } 14 | inline LDPC_generator::GENERATOR_PROPERTY operator | (int p1, LDPC_generator::GENERATOR_PROPERTY p2){ 15 | return static_cast(p1 | static_cast(p2)); 16 | } 17 | static void init_rand(int seed){ 18 | srand(seed); 19 | } 20 | static inline int rand_next(int max){ 21 | return rand()%max; 22 | } 23 | 24 | static inline bool choose(int fz,int fm){ 25 | return rand_next(fm)as_Tanner_graph(); 42 | FILE* fp; 43 | fopen_s(&fp, filename, "w"); 44 | if (fp == NULL){ 45 | fprintf(stderr, "cannot open %s\n", filename); 46 | return false; 47 | } 48 | 49 | fprintf_s(fp, "%d %d\n", t->get_code_len(), t->get_check_len()); 50 | 51 | //get rmax and cmax 52 | unsigned int rmax = 0, cmax = 0; 53 | for (int i = 0; i < t->get_code_len(); i++){ 54 | auto& n = t->get_data_node(i); 55 | if (n.size()>cmax)cmax = n.size(); 56 | } 57 | for (int i = 0; i < t->get_check_len(); i++){ 58 | auto& n = t->get_check_node(i); 59 | if (n.size()>rmax)rmax = n.size(); 60 | } 61 | 62 | fprintf_s(fp, "%d %d\n", cmax, rmax); 63 | 64 | //output col weights and row weights 65 | for (int i = 0; i < t->get_code_len(); i++){ 66 | fprintf(fp, "%d ", t->get_data_node(i).size()); 67 | } 68 | fprintf(fp, "\n"); 69 | for (int i = 0; i < t->get_check_len(); i++){ 70 | fprintf(fp, "%d ", t->get_check_node(i).size()); 71 | } 72 | fprintf(fp, "\n"); 73 | 74 | //output links 75 | for (int i = 0; i < t->get_code_len(); i++){ 76 | auto& n = t->get_data_node(i); 77 | for (auto j : n) 78 | fprintf(fp, "%d ", j+1); 79 | for (int j = n.size(); j < cmax; j++)fprintf(fp, "0 "); 80 | fprintf(fp, "\n"); 81 | } 82 | for (int i = 0; i < t->get_check_len(); i++){ 83 | auto& n = t->get_check_node(i); 84 | for (auto j : n) 85 | fprintf(fp, "%d ", j+1); 86 | for (int j = n.size(); j < rmax; j++)fprintf(fp, "0 "); 87 | fprintf(fp, "\n"); 88 | } 89 | fclose(fp); 90 | return true; 91 | } 92 | 93 | /////////////////////////// 94 | // Generator from plist // 95 | // // 96 | /////////////////////////// 97 | 98 | LDPC_plist_generator::LDPC_plist_generator(const char* _filename) :code_len(0), msg_len(0), filename(new char[strlen(_filename) + 1]){ 99 | strcpy_s(filename, strlen(_filename)+1, _filename); 100 | } 101 | LDPC_generator::GENERATOR_PROPERTY LDPC_plist_generator::init(int _code_len, int _msg_len){ 102 | FILE* fp; 103 | fopen_s(&fp, filename, "rt"); 104 | if (fp == NULL) { 105 | fprintf(stderr, "cannot open %s\n", filename); 106 | return LDPC_generator::GENERATOR_PROPERTY::INVALID; 107 | } 108 | int m; 109 | fscanf_s(fp, "%d%d", &code_len, &m); 110 | msg_len = code_len - m; 111 | fclose(fp); 112 | if (code_len == _code_len && msg_len == _msg_len) 113 | return LDPC_generator::GENERATOR_PROPERTY::VALID; 114 | return LDPC_generator::GENERATOR_PROPERTY::INVALID; 115 | } 116 | unique_ptr LDPC_plist_generator::as_Tanner_graph(){ 117 | FILE* fp; 118 | fopen_s(&fp, filename, "rt"); 119 | if (fp == NULL) { 120 | fprintf(stderr, "cannot open %s\n", filename); 121 | exit(-2); 122 | } 123 | int m; 124 | fscanf_s(fp, "%d%d", &code_len, &m); 125 | msg_len = code_len - m; 126 | 127 | //unused 128 | int cmax, rmax; 129 | fscanf_s(fp, "%d%d", &cmax, &rmax); 130 | 131 | int* col_weight = new int[code_len]; 132 | for (int i = 0; i < code_len; i++) { 133 | fscanf_s(fp, "%d", &col_weight[i]); 134 | } 135 | int* row_weight = new int[m]; 136 | for (int j = 0; j < m; j++) 137 | fscanf_s(fp, "%d", &row_weight[j]); 138 | 139 | //skip n lines 140 | for (int i = 0; i < code_len; i++) { 141 | for (int j = 0; j < cmax; j++) 142 | fscanf_s(fp, "%*d"); 143 | } 144 | 145 | unique_ptr res(new Tanner_graph(code_len, m)); 146 | 147 | for (int j = 0; j < m; j++) { 148 | int i = 0; 149 | for (i = 0; i < row_weight[j]; i++) { 150 | int v; 151 | fscanf_s(fp, "%d", &v); 152 | res->insert_duplex_edge(v - 1, j); 153 | } 154 | for (; i < rmax; i++) { 155 | fscanf_s(fp, "%*d"); // skip the 0s (fillers) 156 | } 157 | } 158 | fclose(fp); 159 | delete[] col_weight; 160 | delete[] row_weight; 161 | return res; 162 | } 163 | 164 | unique_ptr LDPC_plist_generator::as_binary_matrix(){ 165 | return to_binary_matrix(as_Tanner_graph(), code_len, msg_len); 166 | } 167 | 168 | /////////////////////////// 169 | // Gallager generator // 170 | // // 171 | /////////////////////////// 172 | LDPC_Gallager_generator::LDPC_Gallager_generator(int _Wr,int _Wc,int _seed, bool _check_cycle): 173 | Wr(_Wr),Wc(_Wc),seed(_seed),check_cycle(_check_cycle){ 174 | init_rand(seed); 175 | } 176 | LDPC_generator::GENERATOR_PROPERTY LDPC_Gallager_generator::init(int _code_len,int _msg_len){ 177 | int r=_code_len-_msg_len; 178 | if( 179 | _code_len%Wr!=0|| //not regular row 180 | (r%Wc!=0)|| //not regular column 181 | (r/(_code_len/Wr)!=Wc)) //LDPC constraint 182 | return GENERATOR_PROPERTY::INVALID; 183 | if(check_cycle&&code_len/Wrcode_len=_code_len; 186 | this->msg_len=_msg_len; 187 | return GENERATOR_PROPERTY::REGULAR; 188 | } 189 | 190 | struct __map_state_t{ 191 | private: 192 | int W,Wr; 193 | bit_array_t bitmap; 194 | int* count; 195 | 196 | __map_state_t(const __map_state_t&); 197 | public: 198 | __map_state_t(int _Wr,int _W):W(_W),Wr(_Wr),bitmap(_W),count(new int[_Wr]){ 199 | bitmap.clear(false); 200 | memset(count,0,sizeof(int)*Wr); 201 | } 202 | ~__map_state_t(){ 203 | delete[] count; 204 | } 205 | 206 | __map_state_t& operator=(const __map_state_t& state){ 207 | this->bitmap=state.bitmap; 208 | memcpy(this->count,state.count,sizeof(int)*Wr); 209 | return *this; 210 | } 211 | 212 | inline void insert(int pos){ 213 | if(bitmap[pos])return; 214 | bitmap.set(pos,true); 215 | count[pos/(W/Wr)]++; 216 | } 217 | inline bool operator [] (int index){ 218 | return bitmap[index]; 219 | } 220 | inline int get_count(int x){ 221 | return count[x]; 222 | } 223 | inline void clear(){ 224 | bitmap.clear(false); 225 | memset(count,0,sizeof(int)*Wr); 226 | } 227 | }; 228 | 229 | unique_ptr LDPC_Gallager_generator::wocycle_as_Tanner_graph(){ 230 | unique_ptr res(new Tanner_graph(code_len,code_len-msg_len)); 231 | //first: mark the first submatrix 232 | int slice=code_len/Wr; 233 | for(int i=0;iinsert_duplex_edge(j+i*slice,i); 236 | 237 | //second: randomly choose each subsubmatrices 238 | 239 | binary_matrix bitmap(code_len,slice); 240 | int* onecount=new int[Wr]; 241 | memset(onecount,0,sizeof(int)*Wr); 242 | 243 | __map_state_t mark(code_len,Wr); 244 | __map_state_t current(code_len,Wr); 245 | 246 | for(int i=0;iget_check_node(i*slice+j); 257 | for(auto it:check){ 258 | current.insert(it); 259 | } 260 | //choose this 261 | mark.insert(x+k*slice); 262 | res->insert_duplex_edge(x+k*slice,i*slice+j); 263 | 264 | break; 265 | } 266 | curr++; 267 | } 268 | } 269 | } 270 | } 271 | return res; 272 | } 273 | unique_ptr LDPC_Gallager_generator::wcycle_as_binary_matrix(){ 274 | //first: generate one slice 275 | unique_ptr res(new binary_matrix(code_len,msg_len)); 276 | for(int i=0;ioperator[](i/Wr).set(i,true); 278 | 279 | //second: permutation 280 | int slice_len=code_len/Wr; 281 | int* perm=new int[code_len]; 282 | for(int i=1;ioperator[](i*slice_len+j).set(k,res->operator[](j)[perm[k]]); 287 | } 288 | } 289 | delete[] perm; 290 | return res; 291 | } 292 | unique_ptr LDPC_Gallager_generator::as_binary_matrix(){ 293 | if(!check_cycle)return wcycle_as_binary_matrix(); 294 | auto graph=wocycle_as_Tanner_graph(); 295 | return to_binary_matrix(graph,code_len,msg_len); 296 | } 297 | unique_ptr LDPC_Gallager_generator::as_Tanner_graph(){ 298 | if(!check_cycle){ 299 | auto matrix=as_binary_matrix(); 300 | unique_ptr res(new Tanner_graph(code_len,code_len-msg_len)); 301 | 302 | for(int j=0;joperator[](j)[i]){ 306 | res->insert_duplex_edge(i,j); 307 | rest--; 308 | } 309 | } 310 | } 311 | return res; 312 | } 313 | return to_Tanner_graph(wcycle_as_binary_matrix(),code_len,msg_len); 314 | } 315 | 316 | /////////////////////////// 317 | // Quasi-Cyclic generator// 318 | // // 319 | /////////////////////////// 320 | LDPC_QuasiCyclic_generator::LDPC_QuasiCyclic_generator(int _Wr,int _Wc,int _seed): 321 | Wr(_Wr), 322 | Wc(_Wc), 323 | seed(_seed){} 324 | 325 | LDPC_generator::GENERATOR_PROPERTY LDPC_QuasiCyclic_generator::init(int _code_len,int _msg_len){ 326 | if(_code_len%Wr!=0||(_code_len-_msg_len)%Wc!=0|| 327 | (_code_len/Wr!=(_code_len-_msg_len)/Wc)) 328 | return GENERATOR_PROPERTY::INVALID; 329 | this->code_len=_code_len; 330 | this->msg_len=_msg_len; 331 | return GENERATOR_PROPERTY::REGULAR; 332 | } 333 | unique_ptr LDPC_QuasiCyclic_generator::as_Tanner_graph(){ 334 | unique_ptr res(new Tanner_graph(code_len,code_len-msg_len)); 335 | int sidelen=code_len/Wr; 336 | 337 | init_rand(seed); 338 | 339 | for(int i=0;iinsert_duplex_edge(j*sidelen+(k+ran)%sidelen,i*sidelen+k); 344 | } 345 | return res; 346 | } 347 | unique_ptr LDPC_QuasiCyclic_generator::as_binary_matrix(){ 348 | unique_ptr res(new binary_matrix(code_len,code_len-msg_len)); 349 | int sidelen=code_len/Wr; 350 | 351 | init_rand(seed); 352 | 353 | for(int i=0;ioperator[](i*sidelen+k).set(j*sidelen+(k+ran)%sidelen,true); 358 | } 359 | return res; 360 | } 361 | 362 | LDPC_array_generator::LDPC_array_generator(int _Wr,int _Wc,bool _upper_tri): 363 | Wr(_Wr), 364 | Wc(_Wc), 365 | upper_tri(_upper_tri){} 366 | 367 | LDPC_generator::GENERATOR_PROPERTY LDPC_array_generator::init(int _code_len, int _msg_len){ 368 | if (_code_len%Wr != 0 || (_code_len - _msg_len) % Wc != 0 || 369 | (_code_len / Wr != (_code_len - _msg_len) / Wc)) 370 | return GENERATOR_PROPERTY::INVALID; 371 | 372 | if (Wr>_code_len / Wr)return GENERATOR_PROPERTY::INVALID; 373 | 374 | this->code_len = _code_len; 375 | this->msg_len = _msg_len; 376 | 377 | 378 | if (upper_tri)return (Wr <= 3 ? 0 : GENERATOR_PROPERTY::GIRTH_6) | GENERATOR_PROPERTY::UPPER_TRIANGLE | GENERATOR_PROPERTY::FULL_RANK; 379 | else return (Wr <= 3 ? 0 : GENERATOR_PROPERTY::GIRTH_6) | GENERATOR_PROPERTY::FULL_RANK | GENERATOR_PROPERTY::REGULAR; 380 | } 381 | 382 | std::unique_ptr LDPC_array_generator::as_Tanner_graph(){ 383 | unique_ptr res(new Tanner_graph(code_len,code_len-msg_len)); 384 | int sidelen=code_len/Wr; 385 | for(int i=0;iinsert_duplex_edge(xoffset+(power+k)%sidelen,yoffset+k); 393 | } 394 | else{ 395 | if(iinsert_duplex_edge(xoffset+(power+k)%sidelen,yoffset+k); 401 | } 402 | } 403 | return res; 404 | } 405 | std::unique_ptr LDPC_array_generator::as_binary_matrix(){ 406 | return to_binary_matrix(as_Tanner_graph(),code_len,msg_len); 407 | } 408 | 409 | 410 | -------------------------------------------------------------------------------- /LDPC_Code/LDPC_generator.h: -------------------------------------------------------------------------------- 1 | #ifndef __LDPC_GENERATOR_H 2 | #define __LDPC_GENERATOR_H 3 | #include 4 | #include 5 | #include 6 | #include "simple_bitarray.h" 7 | 8 | //the structure of Tanner Graph 9 | class Tanner_graph{ 10 | private: 11 | const int data_num, check_num; 12 | std::vector* data_nodes; 13 | std::vector* check_nodes; 14 | 15 | //no copy 16 | Tanner_graph(const Tanner_graph& graph); 17 | Tanner_graph& operator =(const Tanner_graph& graph); 18 | public: 19 | Tanner_graph(int _data_num, int _check_num) : 20 | data_num(_data_num), 21 | check_num(_check_num), 22 | data_nodes(new std::vector[data_num]), 23 | check_nodes(new std::vector[check_num]) 24 | { 25 | } 26 | ~Tanner_graph(){ 27 | delete[] data_nodes; 28 | delete[] check_nodes; 29 | } 30 | //insert an duplex edge between data node and check node. 31 | void insert_duplex_edge(int data_id, int check_id){ 32 | data_nodes[data_id].push_back(check_id); 33 | check_nodes[check_id].push_back(data_id); 34 | } 35 | //get the data node given node index 36 | std::vector& get_data_node(int id){ 37 | return data_nodes[id]; 38 | } 39 | //get the check node given node index 40 | std::vector& get_check_node(int id){ 41 | return check_nodes[id]; 42 | } 43 | int get_code_len() const{ return data_num; } 44 | int get_check_len() const{ return check_num; } 45 | }; 46 | 47 | //binary matrix, to present parity matrix 48 | class binary_matrix{ 49 | private: 50 | int w; 51 | int h; 52 | bit_array_t* bit_array; 53 | public: 54 | binary_matrix(int _w, int _h) : 55 | w(_w), h(_h), 56 | bit_array(new bit_array_t[_h]){ 57 | for (int i = 0; i < h; i++){ 58 | bit_array[i] = bit_array_t(w); 59 | bit_array[i].clear(false); 60 | } 61 | } 62 | ~binary_matrix(){ 63 | delete[] bit_array; 64 | } 65 | bit_array_t& operator [](int j) const{ 66 | return bit_array[j]; 67 | } 68 | inline int width() const{ return w; } 69 | inline int height() const{ return h; } 70 | }; 71 | static std::unique_ptr to_binary_matrix(const std::unique_ptr& graph, int code_len, int msg_len){ 72 | std::unique_ptr res(new binary_matrix(code_len, code_len - msg_len)); 73 | for (int i = 0; i < code_len - msg_len; i++){ 74 | auto& row = res->operator[](i); 75 | auto list = graph->get_check_node(i); 76 | for (auto it : list) 77 | row.set(it, true); 78 | } 79 | return res; 80 | } 81 | static std::unique_ptr to_Tanner_graph(const std::unique_ptr mat, int code_len, int msg_len){ 82 | int h = code_len - msg_len; 83 | std::unique_ptr res; 84 | for (int i = 0; i < h; i++) 85 | for (int j = 0; j < code_len; j++) 86 | if (mat->operator[](i)[j]) 87 | res->insert_duplex_edge(j, i); 88 | return res; 89 | } 90 | 91 | //generating parity check matrix/Tanner graph 92 | class LDPC_generator{ 93 | public: 94 | enum GENERATOR_PROPERTY{ 95 | INVALID = 0, 96 | VALID=1, 97 | WR_REGULAR = 3, 98 | WC_REGULAR = 5, 99 | REGULAR = 7, 100 | UPPER_TRIANGLE = 57, 101 | PSEUDO_UPPER_TRIANGLE = 41, 102 | FULL_RANK = 33, 103 | GIRTH_6 = 65 104 | }; 105 | virtual GENERATOR_PROPERTY init(int code_len, int msg_len) = 0; 106 | virtual std::unique_ptr as_Tanner_graph() = 0; 107 | virtual std::unique_ptr as_binary_matrix() = 0; 108 | bool save_to_plist(const char* filename); 109 | }; 110 | 111 | //read from an existing plist file 112 | class LDPC_plist_generator : public LDPC_generator{ 113 | private: 114 | int code_len, msg_len; 115 | char* const filename; 116 | public: 117 | LDPC_plist_generator(const char* filename); 118 | ~LDPC_plist_generator(){ if (filename) delete[] filename; } 119 | virtual GENERATOR_PROPERTY init(int code_len, int msg_len); 120 | virtual std::unique_ptr as_Tanner_graph(); 121 | virtual std::unique_ptr as_binary_matrix(); 122 | }; 123 | class LDPC_Gallager_generator :public LDPC_generator{ 124 | private: 125 | int code_len, msg_len; 126 | const int Wr, Wc; 127 | const int seed; 128 | const bool check_cycle; 129 | 130 | std::unique_ptr wocycle_as_Tanner_graph(); 131 | std::unique_ptr wcycle_as_binary_matrix(); 132 | public: 133 | LDPC_Gallager_generator(int Wr, int Wc, int seed, bool _check_cycle); 134 | virtual GENERATOR_PROPERTY init(int code_len, int msg_len); 135 | virtual std::unique_ptr as_Tanner_graph(); 136 | virtual std::unique_ptr as_binary_matrix(); 137 | }; 138 | 139 | //quasi-cyclic code 140 | class LDPC_QuasiCyclic_generator:public LDPC_generator{ 141 | private: 142 | int code_len,msg_len; 143 | const int Wr,Wc; 144 | const int seed; 145 | public: 146 | LDPC_QuasiCyclic_generator(int Wr,int Wc,int seed); 147 | virtual GENERATOR_PROPERTY init(int code_len,int msg_len); 148 | virtual std::unique_ptr as_Tanner_graph(); 149 | virtual std::unique_ptr as_binary_matrix(); 150 | }; 151 | 152 | //array code 153 | class LDPC_array_generator :public LDPC_generator{ 154 | private: 155 | int code_len, msg_len; 156 | const int Wr, Wc; 157 | const bool upper_tri; 158 | public: 159 | LDPC_array_generator(int Wr, int Wc, bool upper_tri); 160 | virtual GENERATOR_PROPERTY init(int code_len, int msg_len); 161 | virtual std::unique_ptr as_Tanner_graph(); 162 | virtual std::unique_ptr as_binary_matrix(); 163 | }; 164 | 165 | /* 166 | class LDPC_random_generator:public LDPC_generator{ 167 | private: 168 | int code_len,msg_len; 169 | public: 170 | LDPC_random_generator(int Wr, int Wc, int seed); 171 | virtual GENERATOR_PROPERTY init(int code_len,int msg_len); 172 | virtual std::unique_ptr> as_Tanner_graph(); 173 | virtual std::unique_ptr as_binary_matrix(); 174 | }; 175 | */ 176 | #endif 177 | -------------------------------------------------------------------------------- /LDPC_Code/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | static chrono::high_resolution_clock::time_point get_tick(){ 8 | return chrono::high_resolution_clock::now(); 9 | } 10 | static double get_duration(chrono::high_resolution_clock::time_point& t1, chrono::high_resolution_clock::time_point& t2){ 11 | std::chrono::duration time_span = std::chrono::duration_cast>(t2 - t1); 12 | return time_span.count(); 13 | } 14 | 15 | static bit_array_t generate_bitarr(int len, function gen_func){ 16 | bit_array_t res(len); 17 | res.clear(); 18 | for (int i = 0; i < len; i++) 19 | res.set(i, gen_func(i)); 20 | return res; 21 | } 22 | static void __rand_n_k(int n, int k, int* dest){ 23 | memset(dest, 0, sizeof(int)*k); 24 | 25 | if (n <= k*k) 26 | { 27 | //O(n) implementation 28 | int t = 0; 29 | for (int i = 0; i < n && t < k; i++){ 30 | if (rand()*(n - i) < (k - t)*RAND_MAX) 31 | dest[t++] = i; 32 | } 33 | } 34 | else 35 | { 36 | //O(k^2) implementation 37 | for (int j = 0; j < k; j++) 38 | { 39 | int x = rand() % n; 40 | for (int t = 0; t < j; t++) 41 | if (dest[t] == x){ 42 | x = rand() % n; 43 | t = -1; 44 | } 45 | dest[j] = x; 46 | } 47 | } 48 | } 49 | 50 | void rand_flip(bit_array_t& arr, int num){ 51 | int* place = new int[num]; 52 | __rand_n_k(arr.size(), num, place); 53 | for (int i = 0; i < num; i++) 54 | arr.xor(place[i], true); 55 | } 56 | 57 | float get_ber(bit_array_t& truth, bit_array_t& fact){ 58 | int error = 0; 59 | for (int i = 0; i < truth.size(); i++) 60 | if (truth[i] != fact[i])error++; 61 | return error / (float)truth.size(); 62 | } 63 | 64 | const int duplication = 3; 65 | 66 | unique_ptr do_benchmark(int code_len, int msg_len, LDPC_generator* gen, float max_BER, float min_BER, int case_num, int iteration){ 67 | bit_array_t src = generate_bitarr(msg_len, [](int i){return rand() % 2 == 0; }); 68 | bit_array_t dest(code_len); 69 | 70 | int actual_msg_len=0; 71 | unique_ptr res(new benchmark_s()); 72 | res->case_num = case_num; 73 | res->BER_after = new float[case_num]; 74 | res->BER_before = new float[case_num]; 75 | res->failed_cases = new int[case_num]; 76 | res->BER_after_succeed = new float[case_num]; 77 | 78 | srand((int)time(0)); 79 | 80 | auto t0 = get_tick(); 81 | LDPC_encoder* encoder = new LDPC_encoder(code_len, msg_len); 82 | if ( 83 | encoder->init(gen, actual_msg_len) 84 | //encoder->init("parities.txt") 85 | ){ 86 | auto t1 = get_tick(); 87 | double d1 = get_duration(t0, t1); 88 | res->encoding_prepare_time = (int)(d1 * 1000); 89 | res->rate = msg_len / (float)code_len; 90 | res->actual_rate = actual_msg_len / (float)code_len; 91 | auto t2 = get_tick(); 92 | encoder->encode(src, dest); 93 | auto t3 = get_tick(); 94 | res->encoding_time_per_100_codes = (int)(get_duration(t2, t3) * 100000); 95 | 96 | } 97 | else return res; 98 | 99 | LDPC_bp_decoder* decoder = new LDPC_bp_decoder(code_len, msg_len); 100 | 101 | auto t4 = get_tick(); 102 | if ( 103 | //decoder->init("20000.10000.3.631.alist") 104 | decoder->init(gen) 105 | ){ 106 | auto t5 = get_tick(); 107 | res->decoding_prepare_time = (int)(get_duration(t4, t5) * 1000); 108 | double decoding_time = 0; 109 | if (decoder->check(dest)){ 110 | for (int i = 0; i < case_num; i++){ 111 | float ber = min_BER + (max_BER - min_BER) / (case_num - 1)*i; 112 | res->BER_before[i] = ber; 113 | res->BER_after[i] = 0; 114 | res->failed_cases[i] = 0; 115 | res->BER_after_succeed[i] = 0; 116 | for (int j = 0; j < duplication; j++){ 117 | bit_array_t dest_copy = dest; 118 | rand_flip(dest_copy, (int)(dest_copy.size()*ber+0.5)); 119 | auto t6 = get_tick(); 120 | if (!decoder->decode_BSC(dest_copy, ber, iteration)){ 121 | res->failed_cases[i]++; 122 | } 123 | else res->BER_after_succeed[i] += get_ber(dest, dest_copy); 124 | auto t7 = get_tick(); 125 | decoding_time += get_duration(t6, t7); 126 | res->BER_after[i] += get_ber(dest, dest_copy); 127 | } 128 | res->BER_after[i] /= duplication; 129 | res->BER_after_succeed[i] /= duplication - res->failed_cases[i]; 130 | } 131 | res->decoding_time_per_100_codes = (int)(decoding_time / (case_num *duplication / 100.0) * 1000); 132 | } 133 | } 134 | return res; 135 | } -------------------------------------------------------------------------------- /LDPC_Code/benchmark.h: -------------------------------------------------------------------------------- 1 | #include "LDPC_decoder.h" 2 | #include "LDPC_encoder.h" 3 | #include 4 | #include 5 | 6 | struct benchmark_s{ 7 | float rate; 8 | float actual_rate; 9 | int encoding_prepare_time; 10 | int decoding_prepare_time; 11 | int encoding_time_per_100_codes; 12 | int decoding_time_per_100_codes; 13 | int case_num; 14 | float *BER_before; 15 | float *BER_after; 16 | int* failed_cases; 17 | float* BER_after_succeed; 18 | 19 | void output(){ 20 | std::cout << "Rate:\t" << rate << std::endl << 21 | "Actual rate:\t" << actual_rate << std::endl << 22 | "Encoding prepare time:\t" << encoding_prepare_time << std::endl << 23 | "Decoding prepare time:\t" << decoding_prepare_time << std::endl << 24 | "Encoding time per 100 codes:\t" << encoding_time_per_100_codes << std::endl << 25 | "Decoding time per 100 codes:\t" << decoding_time_per_100_codes << std::endl << 26 | "BER change:" << std::endl; 27 | for (int i = 0; i < case_num; i++){ 28 | std::cout << BER_before[i] << "\t-->\t" << BER_after[i] << "\t" << BER_after_succeed[i] << "\t" << failed_cases[i] << std::endl; 29 | } 30 | } 31 | benchmark_s() :BER_before(NULL), BER_after(NULL), failed_cases(NULL), BER_after_succeed(NULL){} 32 | ~benchmark_s(){ 33 | if (BER_before)delete[] BER_before; 34 | if (BER_after)delete[] BER_after; 35 | if (failed_cases)delete[] failed_cases; 36 | if (BER_after_succeed)delete[] BER_after_succeed; 37 | } 38 | }; 39 | std::unique_ptr do_benchmark(int code_len, int msg_len, LDPC_generator* gen, float max_BER, float min_BER, int case_num, int iteration); -------------------------------------------------------------------------------- /LDPC_Code/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "LDPC_decoder.h" 4 | #include "LDPC_encoder.h" 5 | #include "LDPC_generator.h" 6 | using namespace std; 7 | 8 | 9 | struct symbol_s{ 10 | bool* symbol; 11 | int len; 12 | symbol_s() :symbol(NULL), len(0){} 13 | symbol_s(int _len, const bool* _content):len(_len), symbol(new bool[_len]){ 14 | if(_content)memcpy_s(symbol, len, _content, len); 15 | } 16 | ~symbol_s(){ if(symbol)delete[] symbol; } 17 | symbol_s& operator ^=(const symbol_s& s){ 18 | if (!symbol){ 19 | symbol = new bool[s.len]; 20 | memset(symbol, 0, sizeof(bool)*s.len); 21 | len = s.len; 22 | } 23 | assert(len == s.len); 24 | for (int i = 0; i < len; i++) 25 | symbol[i] ^= s.symbol[i]; 26 | return *this; 27 | } 28 | symbol_s& operator = (const symbol_s& s){ 29 | if (symbol)delete[] symbol; 30 | len = s.len; 31 | if (!len)symbol = NULL; 32 | else{ 33 | symbol = new bool[s.len]; 34 | memcpy_s(symbol, len, s.symbol, len); 35 | } 36 | return *this; 37 | } 38 | void reset(int len, const bool* content){ 39 | this->len = len; 40 | if (this->symbol)delete[] this->symbol; 41 | this->symbol = new bool[len]; 42 | if (content)memcpy_s(this->symbol, len, content, len); 43 | } 44 | }; 45 | 46 | int main(int argc, char** args){ 47 | if (argc <= 1)return -1; 48 | if (strcmp(args[1], "prepare")==0){ 49 | int code_len = atoi(args[2]); 50 | int msg_len = atoi(args[3]); 51 | char* plist_out = args[4]; 52 | char* parity_out = args[5]; 53 | LDPC_generator* gen; 54 | if (strcmp(args[6], "quasicyclic") == 0){ 55 | int Wr = atoi(args[7]); 56 | int Wc = atoi(args[8]); 57 | int seed = atoi(args[9]); 58 | gen = new LDPC_QuasiCyclic_generator(Wr, Wc, seed); 59 | } 60 | else if (strcmp(args[6], "arrayregular") == 0){ 61 | int Wr = atoi(args[7]); 62 | int Wc = atoi(args[8]); 63 | gen = new LDPC_array_generator(Wr, Wc, false); 64 | } 65 | else if (strcmp(args[6], "arrayirregular") == 0){ 66 | int Wr = atoi(args[7]); 67 | int Wc = atoi(args[8]); 68 | gen = new LDPC_array_generator(Wr, Wc, true); 69 | } 70 | else if (strcmp(args[6], "gallager") == 0){ 71 | int Wr = atoi(args[7]); 72 | int Wc = atoi(args[8]); 73 | int seed = atoi(args[9]); 74 | gen = new LDPC_Gallager_generator(Wr, Wc, seed, true); 75 | } 76 | else if (strcmp(args[6], "plist") == 0){ 77 | gen = new LDPC_plist_generator(args[7]); 78 | } 79 | else return -2; 80 | LDPC_encoder* enc = new LDPC_encoder(code_len, msg_len); 81 | int act; 82 | if (!enc->init(gen, act))return -3; 83 | enc->save_parities_to(parity_out); 84 | gen->save_to_plist(plist_out); 85 | return 0; 86 | } 87 | else if (strcmp(args[1], "encodearbitary")==0){ 88 | int code_len = atoi(args[2]); 89 | int msg_len = atoi(args[3]); 90 | char* parity_in = args[4]; 91 | int len = atoi(args[5]); 92 | LDPC_encoder* enc = new LDPC_encoder(code_len, msg_len); 93 | if (!enc->init(parity_in))return -3; 94 | symbol_s* in = new symbol_s[msg_len]; 95 | symbol_s* out = new symbol_s[code_len]; 96 | while (true){ 97 | for (int i = 0; i < msg_len; i++){ 98 | in[i].reset(len, NULL); 99 | for (int j = 0; j < len; j++){ 100 | int c = getc(stdin); 101 | if (c == EOF)goto RET1; 102 | in[i].symbol[j] = c == '1'; 103 | } 104 | } 105 | enc->encode(in, msg_len, out); 106 | for (int i = 0; i < code_len; i++) 107 | for (int j = 0; j < len; j++) 108 | putc(out[i].symbol[j] ? '1' : '0', stdout); 109 | } 110 | RET1: 111 | return 0; 112 | } 113 | else if (strcmp(args[1], "encodebin") == 0){ 114 | int code_len = atoi(args[2]); 115 | int msg_len = atoi(args[3]); 116 | char* parity_in = args[4]; 117 | LDPC_encoder* enc = new LDPC_encoder(code_len, msg_len); 118 | if (!enc->init(parity_in))return -3; 119 | bit_array_t in(msg_len); 120 | bit_array_t out(code_len); 121 | while (true){ 122 | for (int i = 0; i < msg_len; i++){ 123 | int c = getc(stdin); 124 | if (c == EOF)goto RET2; 125 | in.set(i, c == '1'); 126 | } 127 | enc->encode(in, out); 128 | for (int j = 0; j < code_len; j++){ 129 | putc(out[j] ? '1' : '0', stdout); 130 | } 131 | } 132 | RET2: 133 | return 0; 134 | } 135 | else if (strcmp(args[1], "decodebsc") == 0){ 136 | int code_len = atoi(args[2]); 137 | int msg_len = atoi(args[3]); 138 | char* plist_in = args[4]; 139 | double p = atof(args[5]); 140 | LDPC_bp_decoder* dec = new LDPC_bp_decoder(code_len, msg_len); 141 | if (!dec->init(plist_in))return -3; 142 | bit_array_t in(code_len); 143 | while (true){ 144 | for (int i = 0; i < code_len; i++){ 145 | int c = getc(stdin); 146 | if (c == EOF)goto RET3; 147 | in.set(i, c == '1'); 148 | } 149 | if (!dec->decode_BSC(in, p, 30))putc('0', stdout); 150 | else{ 151 | putc('1', stdout); 152 | for (int i = 0; i < code_len; i++){ 153 | putc(in[i] ? '1' : '0', stdout); 154 | } 155 | } 156 | } 157 | RET3: 158 | return 0; 159 | } 160 | else if (strcmp(args[1], "decodebec") == 0){ 161 | int code_len = atoi(args[2]); 162 | int msg_len = atoi(args[3]); 163 | char* plist_in = args[4]; 164 | int len = atoi(args[5]); 165 | LDPC_bp_decoder* dec = new LDPC_bp_decoder(code_len, msg_len); 166 | if (!dec->init(plist_in))return -3; 167 | bit_array_t mask(code_len); 168 | symbol_s* in = new symbol_s[code_len]; 169 | while (true){ 170 | //first:mask 171 | for (int i = 0; i < code_len; i++){ 172 | int c = getc(stdin); 173 | if (c == EOF)goto RET4; 174 | mask.set(i, c == '1'); 175 | } 176 | for (int i = 0; i < code_len; i++){ 177 | in[i].reset(len, NULL); 178 | for (int j = 0; j < len; j++){ 179 | int c = getc(stdin); 180 | if (c == EOF)goto RET4; 181 | in[i].symbol[j] = (c == '1'); 182 | } 183 | } 184 | if (!dec->decode_BEC(in, mask))putc('0', stdout); 185 | else{ 186 | putc('1', stdout); 187 | for (int i = 0; i < code_len; i++){ 188 | for (int j = 0; j < len; j++){ 189 | putc(in[i].symbol[j] ? '1' : '0', stdout); 190 | } 191 | } 192 | } 193 | } 194 | RET4: 195 | return 0; 196 | } 197 | else return -2; 198 | } -------------------------------------------------------------------------------- /LDPC_Code/simple_bitarray.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifndef __BIT_ARRAY_H 6 | #define __BIT_ARRAY_H 7 | 8 | #define __BIT_ARRAY_CHECK 9 | 10 | 11 | #if 0 12 | class simple_bit_array_t{ 13 | private: 14 | int len; 15 | bool* buffer; 16 | simple_bit_array_t(int _len, bool* _buffer) :len(_len), buffer(_buffer){} 17 | public: 18 | simple_bit_array_t() :len(0), buffer(NULL){} 19 | simple_bit_array_t(int _len) :len(_len), buffer(new bool[_len]){} 20 | ~simple_bit_array_t(){ 21 | if (buffer != NULL)delete[] buffer; buffer = NULL; 22 | } 23 | simple_bit_array_t(simple_bit_array_t& arr){ 24 | this->len = arr.len; 25 | this->buffer = new bool[len]; 26 | memcpy(buffer, arr.buffer, sizeof(bool)*len); 27 | } 28 | simple_bit_array_t(bool* arr, int _len) :len(_len), buffer(new bool[_len]){ 29 | memcpy(buffer, arr, sizeof(bool)*len); 30 | } 31 | int size() const{ return len; } 32 | simple_bit_array_t& operator=(const simple_bit_array_t& arr){ 33 | this->len = arr.len; 34 | if (this->buffer != NULL)delete[] this->buffer; 35 | this->buffer = new bool[len]; 36 | memcpy(buffer, arr.buffer, sizeof(bool)*len); 37 | return *this; 38 | } 39 | void clear(bool value = false){ 40 | if (!value)memset(buffer, 0, sizeof(bool)*(len)); 41 | else memset(buffer, true, sizeof(bool)*(len)); 42 | } 43 | inline bool get(int index) const{ 44 | return buffer[index]; 45 | } 46 | simple_bit_array_t operator |(const simple_bit_array_t& arr){ 47 | simple_bit_array_t res(len); 48 | for (int i = 0; i < len; i++) 49 | res.buffer[i] = arr.buffer[i] | buffer[i]; 50 | return res; 51 | } 52 | 53 | simple_bit_array_t operator ^(const simple_bit_array_t& arr){ 54 | simple_bit_array_t res(len); 55 | for (int i = 0; i < len; i++) 56 | res.buffer[i] = arr.buffer[i] ^ buffer[i]; 57 | return res; 58 | } 59 | simple_bit_array_t operator &(const simple_bit_array_t& arr){ 60 | simple_bit_array_t res(len); 61 | for (int i = 0; i < len; i++) 62 | res.buffer[i] = arr.buffer[i] & buffer[i]; 63 | return res; 64 | } 65 | simple_bit_array_t operator !(){ 66 | simple_bit_array_t res(len); 67 | for (int i = 0; i < len; i++) 68 | res.buffer[i] = !buffer[i]; 69 | return res; 70 | } 71 | 72 | simple_bit_array_t& operator |=(const simple_bit_array_t& arr){ 73 | for (int i = 0; i < len; i++) 74 | buffer[i] |= arr.buffer[i]; 75 | return *this; 76 | } 77 | 78 | simple_bit_array_t& operator &=(const simple_bit_array_t& arr){ 79 | for (int i = 0; i < len; i++) 80 | buffer[i] &= arr.buffer[i]; 81 | return *this; 82 | } 83 | simple_bit_array_t& operator ^=(const simple_bit_array_t& arr){ 84 | for (int i = 0; i < len; i++) 85 | buffer[i] ^= arr.buffer[i]; 86 | return *this; 87 | } 88 | inline void set(int index, bool val){ 89 | buffer[index] = val; 90 | } 91 | inline void xor(int index, bool val){ 92 | buffer[index] ^= val; 93 | } 94 | inline bool operator [](int id) const{ 95 | return get(id); 96 | } 97 | }; 98 | typedef simple_bit_array_t bit_array_t; 99 | 100 | #else 101 | class bit_array_t{ 102 | private: 103 | typedef char uint8_t; 104 | int len; 105 | char* buffer; 106 | bit_array_t(int _len, char* _buffer) :len(_len), buffer(_buffer){} 107 | public: 108 | bit_array_t() :len(0), buffer(NULL){} 109 | bit_array_t(int _len) :len(_len), buffer(new char[(_len + 7) / 8]){} 110 | ~bit_array_t(){ if (buffer != NULL)delete[] buffer; buffer = NULL; } 111 | bit_array_t(bit_array_t& arr){ 112 | this->len = arr.len; 113 | this->buffer = new char[(len + 7) / 8]; 114 | memcpy(buffer, arr.buffer, sizeof(char)*((len + 7) / 8)); 115 | } 116 | bit_array_t(bool* arr, int _len) :len(_len), buffer(new char[(_len + 7) / 8]){ 117 | for (int i = 0; i < len; i++) 118 | set(i, arr[i]); 119 | } 120 | int size() const{ return len; } 121 | bit_array_t& operator=(const bit_array_t& arr){ 122 | this->len = arr.len; 123 | if (this->buffer != NULL)delete[] this->buffer; 124 | this->buffer = new char[(len + 7) / 8]; 125 | memcpy(buffer, arr.buffer, sizeof(char)*((len + 7) / 8)); 126 | return *this; 127 | } 128 | void clear(bool value = false){ 129 | if (!value)memset(buffer, 0, sizeof(char)*((len + 7) / 8)); 130 | else memset(buffer, 255, sizeof(char)*((len + 7) / 8)); 131 | } 132 | inline bool get(int index) const{ 133 | #ifdef __BIT_ARRAY_CHECK 134 | assert(index < len); 135 | #endif 136 | return (buffer[index / 8] >> (index % 8)) & 1; 137 | } 138 | bit_array_t operator |(const bit_array_t& arr){ 139 | assert(arr.len == len); 140 | bit_array_t res(len); 141 | for (int i = 0; i < (len + 7) / 8; i++) 142 | res.buffer[i] = arr.buffer[i] | buffer[i]; 143 | return res; 144 | } 145 | 146 | bit_array_t operator ^(const bit_array_t& arr){ 147 | assert(arr.len == len); 148 | bit_array_t res(len); 149 | for (int i = 0; i < (len + 7) / 8; i++) 150 | res.buffer[i] = arr.buffer[i] ^ buffer[i]; 151 | return res; 152 | } 153 | bit_array_t operator &(const bit_array_t& arr){ 154 | assert(arr.len == len); 155 | bit_array_t res(len); 156 | for (int i = 0; i < (len + 7) / 8; i++) 157 | res.buffer[i] = arr.buffer[i] & buffer[i]; 158 | return res; 159 | } 160 | bit_array_t operator !(){ 161 | bit_array_t res(len); 162 | for (int i = 0; i < (len + 7) / 8; i++) 163 | res.buffer[i] = !buffer[i]; 164 | return res; 165 | } 166 | 167 | bit_array_t& operator |=(const bit_array_t& arr){ 168 | for (int i = 0; i < (len + 7) / 8; i++) 169 | buffer[i] |= arr.buffer[i]; 170 | return *this; 171 | } 172 | 173 | bit_array_t& operator &=(const bit_array_t& arr){ 174 | for (int i = 0; i < (len + 7) / 8; i++) 175 | buffer[i] &= arr.buffer[i]; 176 | return *this; 177 | } 178 | bit_array_t& operator ^=(const bit_array_t& arr){ 179 | for (int i = 0; i < (len + 7) / 8; i++) 180 | buffer[i] ^= arr.buffer[i]; 181 | return *this; 182 | } 183 | inline void set(int index, bool val){ 184 | #ifdef __BIT_ARRAY_CHECK 185 | assert(index < len); 186 | #endif 187 | if (val) 188 | buffer[index / 8] |= (char)(1 << (index % 8)); 189 | else 190 | buffer[index / 8] &= (char)~(1 << (index % 8)); 191 | } 192 | inline void xor(int index, bool val){ 193 | #ifdef __BIT_ARRAY_CHECK 194 | assert(index < len); 195 | #endif 196 | if (val) 197 | buffer[index / 8] ^= (char)(1 << (index % 8)); 198 | } 199 | inline bool operator [](int id) const{ 200 | return get(id); 201 | } 202 | }; 203 | #endif 204 | #endif 205 | -------------------------------------------------------------------------------- /LDPC_Code/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "LDPC_decoder.h" 5 | #include "LDPC_encoder.h" 6 | #include "LDPC_generator.h" 7 | #include "benchmark.h" 8 | using namespace std; 9 | 10 | bit_array_t generate_bitarr(int len, function gen_func){ 11 | bit_array_t res(len); 12 | res.clear(); 13 | for (int i = 0; i < len; i++) 14 | res.set(i, gen_func(i)); 15 | return res; 16 | } 17 | 18 | void print_bitarr(const bit_array_t& src){ 19 | for (int i = 0; i < src.size(); i++) 20 | printf(src[i] ? "1" : "0"); 21 | printf("\n"); 22 | } 23 | void print_matrix(const binary_matrix& mat){ 24 | for (int i = 0; i < mat.height(); i++){ 25 | auto bitarr = mat[i]; 26 | print_bitarr(bitarr); 27 | } 28 | printf("\n"); 29 | } 30 | 31 | 32 | int main(){ 33 | 34 | auto res = do_benchmark(996, 498, new LDPC_QuasiCyclic_generator(6,3,3), 0.1f, 0.0f, 10, 50); 35 | res->output(); 36 | 37 | return 0; 38 | 39 | 40 | #if 0 41 | //first generate 42 | auto gen = new LDPC_array_generator(4, 2, false); 43 | LDPC_encoder* encoder = new LDPC_encoder(16, 8); 44 | bit_array_t src = generate_bitarr(8, [](int i){return i % 3 == 0; }); 45 | bit_array_t dest(16); 46 | 47 | int actual_msg_len; 48 | 49 | gen->init(16, 8); 50 | print_matrix(*(gen->as_binary_matrix())); 51 | print_matrix(*to_binary_matrix(gen->as_Tanner_graph(),16,8)); 52 | 53 | if (encoder->init(gen,actual_msg_len)){ 54 | printf("%d\n", actual_msg_len); 55 | print_matrix(*(gen->as_binary_matrix())); 56 | printf("\n"); 57 | 58 | encoder->encode(src, dest); 59 | print_bitarr(src); 60 | print_bitarr(dest); 61 | } 62 | 63 | LDPC_bp_decoder* decoder = new LDPC_bp_decoder(16, 8); 64 | 65 | if (decoder->init(gen)){ 66 | printf("%d\n", decoder->check(dest)); 67 | } 68 | 69 | //dest.xor(2, true); 70 | 71 | //dest.xor(4, true); 72 | //dest.xor(6, true); 73 | 74 | double prob[16]; 75 | 76 | for (int i = 0; i < 16; i++){ 77 | if (dest[i])prob[i] = 0.9; 78 | else prob[i] = 0.1; 79 | } 80 | prob[4] = 0.11; 81 | prob[6] = 0.11; 82 | 83 | 84 | if (decoder->decode_BSC(dest, prob, 50)){ 85 | print_bitarr(dest); 86 | } 87 | printf("\n"); 88 | bool mask[16]; 89 | for (int i = 0; i < 16; i++)mask[i] = true; 90 | mask[3] = mask[7] = mask[10]=mask[11]=false; 91 | dest.xor(3, true); 92 | dest.xor(7, true); 93 | dest.xor(10, true); 94 | dest.xor(11, true); 95 | if (decoder->decode_BEC(dest, bit_array_t(mask,16))){ 96 | print_bitarr(dest); 97 | } 98 | #endif 99 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LDPC_codes 2 | Low density parity check codes. Encoder and belief propagation decoder written in C++. 3 | 4 | It supports: 5 | 6 | 1. generating parity check matrix: quasi-cyclic codes, regular array codes, irregular array codes, gallager codes, or codes from alist file from http://www.inference.phy.cam.ac.uk/mackay/codes/data.html. 7 | 8 | 2. encoding messages (bit-wise or message-wise) by a given parity check matrix. 9 | 10 | 3. decoding messages by a given parity check matrix using belief propagation. BEC and BSC channels are supported. For BSC, soft-decision decoding and hard-decision decoding are supported. 11 | 12 | Although worked, this project still lacks performance optimizations. 13 | 14 | The compiler must support C++11. 15 | --------------------------------------------------------------------------------