├── 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 |
--------------------------------------------------------------------------------