diff --git a/cpp_test/TestUnionFind.cpp b/cpp_test/TestUnionFind.cpp index e8b16ca..26aad77 100644 --- a/cpp_test/TestUnionFind.cpp +++ b/cpp_test/TestUnionFind.cpp @@ -4,6 +4,7 @@ #include "union_find.hpp" #include "util.hpp" #include "bp.hpp" +#include "robin_set.h" using namespace std; using namespace ldpc::uf; @@ -111,15 +112,102 @@ TEST(UfDecoder, ring_code3){ auto syndrome = vector{1, 0, 1}; - auto decoding = bpd.peel_decode(syndrome, ldpc::uf::NULL_DOUBLE_VECTOR,3); + auto decoding = bpd.peel_decode(syndrome, ldpc::uf::EMPTY_DOUBLE_VECTOR, 3); + ASSERT_TRUE(bpd.pcm_max_bit_degree_2); + tsl::robin_set boundary_bits = {}; + ASSERT_EQ(bpd.planar_code_boundary_bits,boundary_bits); +} + + +TEST(UfDecoder, rep_code){ + + for(int n = 5; n < 20; n++){ + + auto pcm = ldpc::gf2codes::rep_code(n); + auto bpd = UfDecoder(pcm); + ASSERT_TRUE(bpd.pcm_max_bit_degree_2); + tsl::robin_set boundary_bits = {0,n-1}; + ASSERT_EQ(bpd.planar_code_boundary_bits,boundary_bits); + auto syndrome = vector(n,0); + syndrome[0] = 1; + syndrome[n-2] = 1; + auto decoding = bpd.peel_decode(syndrome, ldpc::uf::EMPTY_DOUBLE_VECTOR, 1); + auto expected_decoding = vector(n,0); + expected_decoding[0] = 1; + expected_decoding[n-1] = 1; + ASSERT_EQ(decoding,expected_decoding); + + } + +} + +TEST(UfDecoder, peeling_with_boundaries){ + + + auto pcm = ldpc::gf2sparse::GF2Sparse(2,7); + pcm.insert_entry(0,0); + pcm.insert_entry(0,1); + pcm.insert_entry(0,2); + pcm.insert_entry(0,3); + pcm.insert_entry(1,3); + pcm.insert_entry(1,4); + pcm.insert_entry(1,5); + pcm.insert_entry(1,6); + + // ldpc::sparse_matrix_util::print_sparse_matrix(pcm); + + auto bpd = UfDecoder(pcm); + ASSERT_TRUE(bpd.pcm_max_bit_degree_2); + tsl::robin_set boundary_bits = {0,1,2,4,5,6}; + ASSERT_EQ(bpd.planar_code_boundary_bits,boundary_bits); + auto syndrome = vector{1,1}; + auto weights = vector{-1,0,0,10,0,0,-1}; + auto decoding = bpd.peel_decode(syndrome, weights,1); + + // ldpc::sparse_matrix_util::print_vector(decoding); + auto expected_decoding = vector(7,0); + expected_decoding[0] = 1; + expected_decoding[6] = 1; + ASSERT_EQ(decoding,expected_decoding); + + } +TEST(UfDecoder, peeling_with_boundaries_edge_case){ + + auto pcm = ldpc::gf2sparse::GF2Sparse(20,41); + pcm.insert_entry(0,0);pcm.insert_entry(0,5);pcm.insert_entry(0,25);pcm.insert_entry(1,1);pcm.insert_entry(1,6);pcm.insert_entry(1,25);pcm.insert_entry(1,26);pcm.insert_entry(2,2);pcm.insert_entry(2,7);pcm.insert_entry(2,26);pcm.insert_entry(2,27);pcm.insert_entry(3,3);pcm.insert_entry(3,8);pcm.insert_entry(3,27);pcm.insert_entry(3,28);pcm.insert_entry(4,4);pcm.insert_entry(4,9);pcm.insert_entry(4,28);pcm.insert_entry(5,5);pcm.insert_entry(5,10);pcm.insert_entry(5,29);pcm.insert_entry(6,6);pcm.insert_entry(6,11);pcm.insert_entry(6,29);pcm.insert_entry(6,30);pcm.insert_entry(7,7);pcm.insert_entry(7,12);pcm.insert_entry(7,30);pcm.insert_entry(7,31);pcm.insert_entry(8,8);pcm.insert_entry(8,13);pcm.insert_entry(8,31);pcm.insert_entry(8,32);pcm.insert_entry(9,9);pcm.insert_entry(9,14);pcm.insert_entry(9,32);pcm.insert_entry(10,10);pcm.insert_entry(10,15);pcm.insert_entry(10,33);pcm.insert_entry(11,11);pcm.insert_entry(11,16);pcm.insert_entry(11,33);pcm.insert_entry(11,34);pcm.insert_entry(12,12);pcm.insert_entry(12,17);pcm.insert_entry(12,34);pcm.insert_entry(12,35);pcm.insert_entry(13,13);pcm.insert_entry(13,18);pcm.insert_entry(13,35);pcm.insert_entry(13,36);pcm.insert_entry(14,14);pcm.insert_entry(14,19);pcm.insert_entry(14,36);pcm.insert_entry(15,15);pcm.insert_entry(15,20);pcm.insert_entry(15,37);pcm.insert_entry(16,16);pcm.insert_entry(16,21);pcm.insert_entry(16,37);pcm.insert_entry(16,38);pcm.insert_entry(17,17);pcm.insert_entry(17,22);pcm.insert_entry(17,38);pcm.insert_entry(17,39);pcm.insert_entry(18,18);pcm.insert_entry(18,23);pcm.insert_entry(18,39);pcm.insert_entry(18,40);pcm.insert_entry(19,19);pcm.insert_entry(19,24);pcm.insert_entry(19,40); + + auto error_rate = std::vector(41,0.18); + auto bpd = ldpc::bp::BpDecoder(pcm, error_rate, 1, ldpc::bp::MINIMUM_SUM, ldpc::bp::PARALLEL, 0.625); + + auto syndrome_sparse = std::vector{3, 5, 7, 8, 12, 17, 18, 19}; + + auto syndrome = std::vector(pcm.m,0); + for(int i : syndrome_sparse){ + syndrome[i] = 1; + } + + bpd.decode(syndrome); + ASSERT_FALSE(bpd.converge); + auto ufd = UfDecoder(pcm); + + // ldpc::sparse_matrix_util::print_vector(bpd.log_prob_ratios); + + auto decoding = ufd.peel_decode(syndrome, bpd.log_prob_ratios,1); + + auto decoding_syndrome = pcm.mulvec(decoding); + ASSERT_EQ(decoding_syndrome,syndrome); + + + +} diff --git a/python_test/pcms/hx_surface_2.npz b/python_test/pcms/hx_surface_2.npz new file mode 100644 index 0000000..0cdb674 Binary files /dev/null and b/python_test/pcms/hx_surface_2.npz differ diff --git a/python_test/pcms/hx_surface_20.npz b/python_test/pcms/hx_surface_20.npz new file mode 100644 index 0000000..96882d6 Binary files /dev/null and b/python_test/pcms/hx_surface_20.npz differ diff --git a/python_test/pcms/hx_surface_3 copy.npz b/python_test/pcms/hx_surface_3 copy.npz new file mode 100644 index 0000000..ffc8f3b Binary files /dev/null and b/python_test/pcms/hx_surface_3 copy.npz differ diff --git a/python_test/pcms/hx_surface_3.npz b/python_test/pcms/hx_surface_3.npz new file mode 100644 index 0000000..ffc8f3b Binary files /dev/null and b/python_test/pcms/hx_surface_3.npz differ diff --git a/python_test/pcms/hx_surface_4.npz b/python_test/pcms/hx_surface_4.npz new file mode 100644 index 0000000..e0de4d1 Binary files /dev/null and b/python_test/pcms/hx_surface_4.npz differ diff --git a/python_test/pcms/hx_surface_5.npz b/python_test/pcms/hx_surface_5.npz new file mode 100644 index 0000000..559c3f3 Binary files /dev/null and b/python_test/pcms/hx_surface_5.npz differ diff --git a/python_test/pcms/lx_surface_2.npz b/python_test/pcms/lx_surface_2.npz new file mode 100644 index 0000000..6146b9e Binary files /dev/null and b/python_test/pcms/lx_surface_2.npz differ diff --git a/python_test/pcms/lx_surface_20.npz b/python_test/pcms/lx_surface_20.npz new file mode 100644 index 0000000..c356f22 Binary files /dev/null and b/python_test/pcms/lx_surface_20.npz differ diff --git a/python_test/pcms/lx_surface_3.npz b/python_test/pcms/lx_surface_3.npz new file mode 100644 index 0000000..1836bd1 Binary files /dev/null and b/python_test/pcms/lx_surface_3.npz differ diff --git a/python_test/pcms/lx_surface_4.npz b/python_test/pcms/lx_surface_4.npz new file mode 100644 index 0000000..58b1dc4 Binary files /dev/null and b/python_test/pcms/lx_surface_4.npz differ diff --git a/python_test/pcms/lx_surface_5.npz b/python_test/pcms/lx_surface_5.npz new file mode 100644 index 0000000..723ded7 Binary files /dev/null and b/python_test/pcms/lx_surface_5.npz differ diff --git a/python_test/test_belief_find.py b/python_test/test_belief_find.py new file mode 100644 index 0000000..d905000 --- /dev/null +++ b/python_test/test_belief_find.py @@ -0,0 +1,27 @@ +import pytest +import numpy as np +from ldpc.belief_find_decoder import BeliefFindDecoder +from ldpc.codes import hamming_code, rep_code, ring_code + +def test_peeling_input(): + + pcm = rep_code(3) + decoder = BeliefFindDecoder(pcm, error_rate = 0.1, uf_method="peeling") + + pcm = ring_code(3) + decoder = BeliefFindDecoder(pcm, error_rate = 0.1, uf_method="peeling") + + pcm = hamming_code(3) + + # decoder = BeliefFindDecoder(pcm, error_rate = 0.1, uf_method="peeling") + + with pytest.raises(ValueError): + decoder = BeliefFindDecoder(pcm, error_rate = 0.1, uf_method="peeling") + + +if __name__ == "__main__": + test_peeling_input() + + + + diff --git a/python_test/test_qcodes.py b/python_test/test_qcodes.py index f89f5d5..64649f1 100644 --- a/python_test/test_qcodes.py +++ b/python_test/test_qcodes.py @@ -99,7 +99,7 @@ def test_400_16_6_hgp(): decoder = BpLsdDecoder(hx, error_rate=error_rate, max_iter=max_iter, bp_method="ms", ms_scaling_factor=0.625, schedule="parallel", bits_per_step=1, lsd_order=0) ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder, - f"Min-sum LSD parallel schedule osd={osd_order}") + f"Min-sum LSD-0 parallel schedule") decoder = BpLsdDecoder(hx, error_rate=error_rate, max_iter=5, bp_method="ms", ms_scaling_factor=0.625, schedule="parallel", bits_per_step=1, lsd_order=osd_order) @@ -112,7 +112,7 @@ def test_toric_20(): hx = scipy.sparse.load_npz("python_test/pcms/hx_toric_20.npz") lx = scipy.sparse.load_npz("python_test/pcms/lx_toric_20.npz") - error_rate = 0.05 + error_rate = 0.03 run_count = 500 seed = 42 max_iter = 10 @@ -143,6 +143,43 @@ def test_toric_20(): schedule="parallel", bits_per_step=1, osd_order=5) ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Min-sum LSD parallel schedule") +def test_surface_20(): + hx = scipy.sparse.load_npz("python_test/pcms/hx_surface_20.npz") + lx = scipy.sparse.load_npz("python_test/pcms/lx_surface_20.npz") + + error_rate = 0.01 + run_count = 10000 + seed = 42 + max_iter = 5 + + print(hx.shape) + + print(f"Code: [[761, 1, 20]] Surface, error rate: {error_rate}, bp iterations:, {max_iter}, run count: {run_count}, seed: {seed}") + print("...................................................") + print() + + decoder = BpOsdDecoder(hx, error_rate=error_rate, max_iter=max_iter, bp_method="ms", ms_scaling_factor = 0.625, schedule="parallel", osd_method = "osd0") + ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder, "Min-sum osd-0 parallel schedule") + + decoder = BpOsdDecoder(hx, error_rate=error_rate, max_iter=max_iter, bp_method="ms", ms_scaling_factor = 0.625, schedule="parallel", osd_method = "osd_cs", osd_order = 5) + ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Min-sum osd-cs-5 parallel schedule") + + decoder = BpOsdDecoder(hx, error_rate=error_rate, max_iter=max_iter, bp_method="ms", ms_scaling_factor = 0.625, schedule="parallel", osd_method = "osd_e", osd_order = 5) + ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Min-sum osd-e-5 parallel schedule") + + decoder = BpOsdDecoder(hx, error_rate=error_rate, max_iter=max_iter, bp_method="ms", ms_scaling_factor = 0.625, schedule="serial", osd_method = "osd0") + ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Min-sum osd-0 serial schedule") + + decoder = BpOsdDecoder(hx, error_rate=error_rate, max_iter=max_iter, bp_method="ps", schedule="parallel", osd_method = "osd0") + ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Prod-sum osd-0 parallel schedule") + + decoder = BeliefFindDecoder(hx, error_rate=error_rate, max_iter=max_iter, bp_method="ms", ms_scaling_factor=0.625, schedule="parallel", uf_method="peeling", bits_per_step=1) + ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Belief-find parallel schedule") + + decoder = BpLsdDecoder(hx, error_rate=error_rate, max_iter=max_iter, bp_method="ms", ms_scaling_factor=0.625, + schedule="parallel", bits_per_step=1, lsd_order=5) + ler, min_logical, speed, _ = quantum_mc_sim(hx, lx, error_rate, run_count, seed, decoder,"Min-sum LSD parallel schedule") + def test_cl_size(): hx = scipy.sparse.load_npz("python_test/pcms/hx_400_16_6.npz") @@ -212,4 +249,4 @@ def test_failing_case_lsd_w(): if __name__ == "__main__": - test_failing_case_lsd_w() \ No newline at end of file + test_surface_20() \ No newline at end of file diff --git a/python_test/test_union_find.py b/python_test/test_union_find.py new file mode 100644 index 0000000..e69de29 diff --git a/src_cpp/union_find.hpp b/src_cpp/union_find.hpp index d03a456..d316c5b 100644 --- a/src_cpp/union_find.hpp +++ b/src_cpp/union_find.hpp @@ -18,782 +18,550 @@ #include "gf2sparse_linalg.hpp" #include "bp.hpp" -namespace ldpc::uf{ - -const std::vector NULL_DOUBLE_VECTOR = {}; - -std::vector sort_indices(std::vector& B){ - std::vector indices(B.size()); - std::iota(indices.begin(),indices.end(),0); - std::sort(indices.begin(), indices.end(), [&](int i, int j) { return B[i] < B[j];}); - return indices; -} - - -struct Cluster{ - ldpc::bp::BpSparse& pcm; - int cluster_id; - bool active; - bool valid; - tsl::robin_set bit_nodes; - tsl::robin_set check_nodes; - tsl::robin_set boundary_check_nodes; - std::vector candidate_bit_nodes; - tsl::robin_set enclosed_syndromes; - tsl::robin_map spanning_tree_check_roots; - tsl::robin_set spanning_tree_bits; - tsl::robin_set spanning_tree_leaf_nodes; - - Cluster** global_check_membership; - Cluster** global_bit_membership; - tsl::robin_set merge_list; - - std::vector cluster_decoding; - std::vector matrix_to_cluster_bit_map; - tsl::robin_map cluster_to_matrix_bit_map; - std::vector matrix_to_cluster_check_map; - tsl::robin_map cluster_to_matrix_check_map; - - Cluster() = default; - - Cluster(ldpc::bp::BpSparse& parity_check_matrix, int syndrome_index, Cluster** ccm, Cluster** bcm): - pcm(parity_check_matrix){ - - this->active=true; - this->valid=false; - this->cluster_id = syndrome_index; - this->boundary_check_nodes.insert(syndrome_index); - this->check_nodes.insert(syndrome_index); - this->enclosed_syndromes.insert(syndrome_index); - this->global_check_membership = ccm; - this->global_bit_membership = bcm; - this->global_check_membership[syndrome_index]=this; +namespace ldpc::uf { + const std::vector EMPTY_DOUBLE_VECTOR = {}; + tsl::robin_set EMPTY_INT_ROBIN_SET = {}; - - } - ~Cluster(){ - this->bit_nodes.clear(); - this->check_nodes.clear(); - this->boundary_check_nodes.clear(); - this->candidate_bit_nodes.clear(); - this->enclosed_syndromes.clear(); - this->merge_list.clear(); - } - - int parity(){ - return this->enclosed_syndromes.size() % 2; + std::vector sort_indices(std::vector &B) { + std::vector indices(B.size()); + std::iota(indices.begin(), indices.end(), 0); + std::sort(indices.begin(), indices.end(), [&](int i, int j) { return B[i] < B[j]; }); + return indices; } - void get_candidate_bit_nodes(){ - - std::vector erase_boundary_check; - this->candidate_bit_nodes.clear(); - - // std::cout<<"After candidate bits"<pcm.iterate_row(check_index)){ - if(this->global_bit_membership[e.col_index] != this ){ - candidate_bit_nodes.push_back(e.col_index); - erase = false; + struct Cluster { + ldpc::bp::BpSparse &pcm; + tsl::robin_set &planar_code_boundary_bits; + int cluster_id; + bool contains_boundary_bits; + bool active; + bool valid; + tsl::robin_set bit_nodes; + tsl::robin_set check_nodes; + tsl::robin_set boundary_check_nodes; + std::vector candidate_bit_nodes; + tsl::robin_set enclosed_syndromes; + tsl::robin_map spanning_tree_check_roots; + tsl::robin_set spanning_tree_bits; + tsl::robin_set spanning_tree_leaf_nodes; + int spanning_tree_boundary_bit; + Cluster **global_check_membership; + Cluster **global_bit_membership; + tsl::robin_set merge_list; + std::vector cluster_decoding; + std::vector matrix_to_cluster_bit_map; + tsl::robin_map cluster_to_matrix_bit_map; + std::vector matrix_to_cluster_check_map; + tsl::robin_map cluster_to_matrix_check_map; + + Cluster() = default; + + Cluster(ldpc::bp::BpSparse &parity_check_matrix, int syndrome_index, Cluster **ccm, Cluster **bcm, + tsl::robin_set &planar_code_boundary_bits = EMPTY_INT_ROBIN_SET) : + pcm(parity_check_matrix), planar_code_boundary_bits(planar_code_boundary_bits) { + this->active = true; + this->valid = false; + this->cluster_id = syndrome_index; + this->boundary_check_nodes.insert(syndrome_index); + this->check_nodes.insert(syndrome_index); + this->enclosed_syndromes.insert(syndrome_index); + this->global_check_membership = ccm; + this->global_bit_membership = bcm; + this->global_check_membership[syndrome_index] = this; + this->contains_boundary_bits = false; + this->spanning_tree_boundary_bit = -1; + } + + ~Cluster() { + this->bit_nodes.clear(); + this->check_nodes.clear(); + this->boundary_check_nodes.clear(); + this->candidate_bit_nodes.clear(); + this->enclosed_syndromes.clear(); + this->merge_list.clear(); + } + + int parity() { + return this->enclosed_syndromes.size() % 2; + } + + void get_candidate_bit_nodes() { + std::vector erase_boundary_check; + this->candidate_bit_nodes.clear(); + for (int check_index: boundary_check_nodes) { + bool erase = true; + for (auto &e: this->pcm.iterate_row(check_index)) { + if (this->global_bit_membership[e.col_index] != this) { + candidate_bit_nodes.push_back(e.col_index); + erase = false; + } + } + if (erase) { + erase_boundary_check.push_back(check_index); } } - if(erase) erase_boundary_check.push_back(check_index); - } - - - - for(int check_index: erase_boundary_check){ - this->boundary_check_nodes.erase(check_index); - } - - } - - int add_bit_node_to_cluster(int bit_index){ - - // std::cout<<"Add bit node function. Bit: "<global_bit_membership[bit_index]; - if(bit_membership == this) return 0; //if the bit is already in the cluster terminate. - else if(bit_membership == NULL){ - //if the bit has not yet been assigned to a cluster we add it. - this->bit_nodes.insert(bit_index); - this->global_bit_membership[bit_index] = this; - } - else{ - //if the bit already exists in a cluster, we mark down that this cluster should be - //merged with the exisiting cluster. - this->merge_list.insert(bit_membership); - this->global_bit_membership[bit_index] = this; + for (int check_index: erase_boundary_check) { + this->boundary_check_nodes.erase(check_index); + } + } + + int add_bit_node_to_cluster(int bit_index) { + auto bit_membership = this->global_bit_membership[bit_index]; + if (bit_membership == this) return 0; //if the bit is already in the cluster terminate. + else if (bit_membership == NULL) { + //if the bit has not yet been assigned to a cluster we add it. + this->bit_nodes.insert(bit_index); + this->global_bit_membership[bit_index] = this; + } else { + //if the bit already exists in a cluster, we mark down that this cluster should be + //merged with the exisiting cluster. + this->merge_list.insert(bit_membership); + this->global_bit_membership[bit_index] = this; + } + if (this->planar_code_boundary_bits.contains(bit_index)) { + this->contains_boundary_bits = true; + } + for (auto &e: this->pcm.iterate_column(bit_index)) { + int check_index = e.row_index; + auto check_membership = this->global_check_membership[check_index]; + if (check_membership == this) continue; + else if (check_membership == NULL) { + this->check_nodes.insert(check_index); + this->boundary_check_nodes.insert(check_index); + this->global_check_membership[check_index] = this; + } else { + this->check_nodes.insert(check_index); + this->boundary_check_nodes.insert(check_index); + this->merge_list.insert(check_membership); + this->global_check_membership[check_index] = this; + } + } + return 1; } - for(auto& e: this->pcm.iterate_column(bit_index)){ - int check_index = e.row_index; - auto check_membership = this->global_check_membership[check_index]; - if(check_membership == this) continue; - else if (check_membership == NULL){ + void merge_with_cluster(Cluster *cl2) { + for (auto bit_index: cl2->bit_nodes) { + this->bit_nodes.insert(bit_index); + this->global_bit_membership[bit_index] = this; + } + for (auto check_index: cl2->check_nodes) { this->check_nodes.insert(check_index); - this->boundary_check_nodes.insert(check_index); this->global_check_membership[check_index] = this; } - else{ - this->check_nodes.insert(check_index); + for (auto check_index: cl2->boundary_check_nodes) { this->boundary_check_nodes.insert(check_index); - this->merge_list.insert(check_membership); - this->global_check_membership[check_index] = this; + } + if (cl2->contains_boundary_bits) { + this->contains_boundary_bits = true; + } + cl2->active = false; + for (auto j: cl2->enclosed_syndromes) { + this->enclosed_syndromes.insert(j); } } - return 1; - - } - - void merge_with_cluster(Cluster* cl2){ - - // std::cout<<"Hello from merge function"<bit_nodes){ - this->bit_nodes.insert(bit_index); - this->global_bit_membership[bit_index] = this; - } - - // std::cout<<"bit nodes copied"<check_nodes){ - this->check_nodes.insert(check_index); - this->global_check_membership[check_index] = this; - } - - // std::cout<<"check nodes copied"<boundary_check_nodes){ - this->boundary_check_nodes.insert(check_index); - } - - // std::cout<<"boundary check nodes copied"<active = false; - for(auto j: cl2->enclosed_syndromes){ - this->enclosed_syndromes.insert(j); - } - } - - int grow_cluster(const std::vector& bit_weights = NULL_DOUBLE_VECTOR, int bits_per_step = 0){ - if(!this->active) return 0; - - this->get_candidate_bit_nodes(); - - - this->merge_list.clear(); - - if(bit_weights == NULL_DOUBLE_VECTOR){ - for(int bit_index: this->candidate_bit_nodes){ - this->add_bit_node_to_cluster(bit_index); + int grow_cluster(const std::vector &bit_weights = EMPTY_DOUBLE_VECTOR, int bits_per_step = 0) { + if (!this->active) { + return 0; } - } + this->get_candidate_bit_nodes(); + this->merge_list.clear(); - else{ - std::vector cluster_bit_weights; - for(int bit: this->candidate_bit_nodes){ - cluster_bit_weights.push_back(bit_weights[bit]); + if (bit_weights == EMPTY_DOUBLE_VECTOR) { + for (int bit_index: this->candidate_bit_nodes) { + this->add_bit_node_to_cluster(bit_index); + } + } else { + std::vector cluster_bit_weights; + for (auto bit: this->candidate_bit_nodes) { + cluster_bit_weights.push_back(bit_weights[bit]); + } + auto sorted_indices = sort_indices(cluster_bit_weights); + int count = 0; + for (auto i: sorted_indices) { + if (count == bits_per_step) break; + int bit_index = this->candidate_bit_nodes[i]; + this->add_bit_node_to_cluster(bit_index); + count++; + } } - auto sorted_indices = sort_indices(cluster_bit_weights); - int count = 0; - for(int i: sorted_indices){ - if(count == bits_per_step) break; - int bit_index = this->candidate_bit_nodes[i]; - this->add_bit_node_to_cluster(bit_index); - count++; + for (auto cl: merge_list) { + this->merge_with_cluster(cl); + cl->active = false; } - + return 1; } - // std::cout<<"Before merge"<merge_with_cluster(cl); - cl->active = false; - } - return 1; - } - - int find_spanning_tree_parent(int check_index){ + int find_spanning_tree_parent(const int check_index) { int parent = this->spanning_tree_check_roots[check_index]; - if(parent != check_index){ + if (parent != check_index) { return find_spanning_tree_parent(parent); + } else { + return parent; } - else return parent; } - void find_spanning_tree(){ - - this->spanning_tree_bits.clear(); - this->spanning_tree_check_roots.clear(); - this->spanning_tree_leaf_nodes.clear(); - - for(int bit_index: this->bit_nodes){ - this->spanning_tree_bits.insert(bit_index); - } - - for(int check_index: this->check_nodes){ - this->spanning_tree_check_roots[check_index] = check_index; - } - - int check_neighbours[2]; - for(int bit_index: this->bit_nodes){ - check_neighbours[0] = this->pcm.column_heads[bit_index]->up->row_index; - check_neighbours[1] = this->pcm.column_heads[bit_index]->down->row_index; - - int root0 = this->find_spanning_tree_parent(check_neighbours[0]); - int root1 = this->find_spanning_tree_parent(check_neighbours[1]); - - if(root0!=root1){ - this->spanning_tree_check_roots[root1] = root0; + void find_spanning_tree() { + this->spanning_tree_bits.clear(); + this->spanning_tree_check_roots.clear(); + this->spanning_tree_leaf_nodes.clear(); + for (int bit_index: this->bit_nodes) { + this->spanning_tree_bits.insert(bit_index); } - else{ - // std::cout<spanning_tree_bits.erase(bit_index); + // add the virtual boundary check + if (this->contains_boundary_bits) { + this->check_nodes.insert(-1); } - } - - for(int check_index: this->check_nodes){ - int spanning_tree_connectivity = 0; - for(auto& e: this->pcm.iterate_row(check_index)){ - if(this->spanning_tree_bits.contains(e.col_index)) spanning_tree_connectivity+=1; + for (int check_index: this->check_nodes) { + this->spanning_tree_check_roots[check_index] = check_index; } - if(spanning_tree_connectivity == 1) this->spanning_tree_leaf_nodes.insert(check_index); - } - - } + int check_neighbours[2]; - std::vector peel_decode(const std::vector& syndrome){ - std::vector erasure; - tsl::robin_set synds; - for(auto check_index: check_nodes){ - if(syndrome[check_index] == 1) synds.insert(check_index); + for (int bit_index: this->bit_nodes) { + check_neighbours[0] = this->pcm.column_heads[bit_index]->up->row_index; + check_neighbours[1] = this->pcm.column_heads[bit_index]->down->row_index; + if (check_neighbours[0] == check_neighbours[1]) { + check_neighbours[1] = -1; //set the first check neighbour to the boundary check. + this->spanning_tree_boundary_bit = bit_index; + } + int root0 = this->find_spanning_tree_parent(check_neighbours[0]); + int root1 = this->find_spanning_tree_parent(check_neighbours[1]); + if (root0 != root1) { + this->spanning_tree_check_roots[root1] = root0; + } else { + this->spanning_tree_bits.erase(bit_index); + } + } + for (int check_index: this->check_nodes) { + if (check_index == -1) { + this->spanning_tree_leaf_nodes.insert(check_index); + } else { + int spanning_tree_connectivity = 0; + for (auto &e: this->pcm.iterate_row(check_index)) { + if (this->spanning_tree_bits.contains(e.col_index)) { + spanning_tree_connectivity += 1; + } + } + if (spanning_tree_connectivity == 1) { + this->spanning_tree_leaf_nodes.insert(check_index); + } + } + } } - this->find_spanning_tree(); - while(synds.size()>0){ - - int leaf_node_index = *(this->spanning_tree_leaf_nodes.begin()); - int bit_index = -1; - int check2 = -1; - - for(auto& e: this->pcm.iterate_row(leaf_node_index)){ - bit_index = e.col_index; - if(this->spanning_tree_bits.contains(bit_index)) break; + std::vector peel_decode(const std::vector &syndrome) { + std::vector erasure; + tsl::robin_set synds; + for (auto check_index: check_nodes) { + if (syndrome[check_index] == 1) synds.insert(check_index); } - - - for(auto& e: this->pcm.iterate_column(bit_index)){ - if(e.row_index!=leaf_node_index) check2 = e.row_index; + if (this->contains_boundary_bits == true && this->parity() == 1) { + synds.insert(-1); } + this->find_spanning_tree(); + while (!synds.empty()) { + int leaf_node_index = *(this->spanning_tree_leaf_nodes.begin()); + int bit_index; + int check2 = -1; //we assume it is a boundary node at first. + if (leaf_node_index == -1) { + bit_index = this->spanning_tree_boundary_bit; + } else { + for (auto &e: this->pcm.iterate_row(leaf_node_index)) { + bit_index = e.col_index; + if (this->spanning_tree_bits.contains(bit_index)) break; + } + } + for (auto &e: this->pcm.iterate_column(bit_index)) { + if (e.row_index != leaf_node_index) { + check2 = e.row_index; + } + } - if(synds.contains(leaf_node_index)){ - this->spanning_tree_leaf_nodes.erase(leaf_node_index); - // this->spanning_tree_leaf_nodes.insert(check2); - erasure.push_back(bit_index); - this->spanning_tree_bits.erase(bit_index); - if(synds.contains(check2)) synds.erase(check2); - else synds.insert(check2); - synds.erase(leaf_node_index); - } - else{ - this->spanning_tree_leaf_nodes.erase(leaf_node_index); - // this->spanning_tree_leaf_nodes.insert(check2); - this->spanning_tree_bits.erase(bit_index); - } - - //check whether new check node is a leaf - int spanning_tree_connectivity = 0; - for(auto& e: this->pcm.iterate_row(check2)){ - if(this->spanning_tree_bits.contains(e.col_index)) spanning_tree_connectivity+=1; + if (synds.contains(leaf_node_index)) { + this->spanning_tree_leaf_nodes.erase(leaf_node_index); + // this->spanning_tree_leaf_nodes.insert(check2); + erasure.push_back(bit_index); + this->spanning_tree_bits.erase(bit_index); + if (synds.contains(check2)) synds.erase(check2); + else synds.insert(check2); + synds.erase(leaf_node_index); + } else { + this->spanning_tree_leaf_nodes.erase(leaf_node_index); + // this->spanning_tree_leaf_nodes.insert(check2); + this->spanning_tree_bits.erase(bit_index); + } + //check whether new check node is a leaf + if (check2 == -1) { + this->spanning_tree_leaf_nodes.insert(check2); + } else { + int spanning_tree_connectivity = 0; + for (auto &e: this->pcm.iterate_row(check2)) { + if (this->spanning_tree_bits.contains(e.col_index)) { + spanning_tree_connectivity += 1; + } + } + if (spanning_tree_connectivity == 1) { + this->spanning_tree_leaf_nodes.insert(check2); + } + } } - if(spanning_tree_connectivity == 1) this->spanning_tree_leaf_nodes.insert(check2); - + return erasure; } - return erasure; - } - - ldpc::bp::BpSparse convert_to_matrix(const std::vector& bit_weights = NULL_DOUBLE_VECTOR){ - - this->matrix_to_cluster_bit_map.clear(); - this->matrix_to_cluster_check_map.clear(); - this->cluster_to_matrix_bit_map.clear(); - this->cluster_to_matrix_check_map.clear(); - + ldpc::bp::BpSparse convert_to_matrix(const std::vector &bit_weights = EMPTY_DOUBLE_VECTOR) { + this->matrix_to_cluster_bit_map.clear(); + this->matrix_to_cluster_check_map.clear(); + this->cluster_to_matrix_bit_map.clear(); + this->cluster_to_matrix_check_map.clear(); - if(bit_weights!=NULL_DOUBLE_VECTOR){ - std::vector cluster_bit_weights; - std::vector bit_nodes_temp; - for(int bit: this->bit_nodes){ - cluster_bit_weights.push_back(bit_weights[bit]); - bit_nodes_temp.push_back(bit); + if (bit_weights != EMPTY_DOUBLE_VECTOR) { + std::vector cluster_bit_weights; + std::vector bit_nodes_temp; + for (int bit: this->bit_nodes) { + cluster_bit_weights.push_back(bit_weights[bit]); + bit_nodes_temp.push_back(bit); + } + auto sorted_indices = sort_indices(cluster_bit_weights); + int count = 0; + for (auto i: sorted_indices) { + int bit_index = bit_nodes_temp[i]; + this->matrix_to_cluster_bit_map.push_back(bit_index); + this->cluster_to_matrix_bit_map[bit_index] = count; + count++; + } + } else { + int count = 0; + for (auto bit_index: this->bit_nodes) { + this->matrix_to_cluster_bit_map.push_back(bit_index); + this->cluster_to_matrix_bit_map[bit_index] = count; + count++; + } } - auto sorted_indices = sort_indices(cluster_bit_weights); int count = 0; - for(int i: sorted_indices){ - int bit_index = bit_nodes_temp[i]; - this->matrix_to_cluster_bit_map.push_back(bit_index); - this->cluster_to_matrix_bit_map[bit_index] = count; - count++; - } - } - else{ - int count = 0; - for(int bit_index: this->bit_nodes){ - this->matrix_to_cluster_bit_map.push_back(bit_index); - this->cluster_to_matrix_bit_map[bit_index] = count; + for (auto check_index: this->check_nodes) { + this->matrix_to_cluster_check_map.push_back(check_index); + this->cluster_to_matrix_check_map[check_index] = count; count++; } + auto cluster_pcm = ldpc::bp::BpSparse(this->check_nodes.size(), this->bit_nodes.size()); - } - - int count = 0; - - for(int check_index: this->check_nodes){ - this->matrix_to_cluster_check_map.push_back(check_index); - this->cluster_to_matrix_check_map[check_index] = count; - count++; - } - - auto cluster_pcm = ldpc::bp::BpSparse(this->check_nodes.size(),this->bit_nodes.size()); - - for(int check_index: this->check_nodes){ - for(auto& e: this->pcm.iterate_row(check_index)){ - int bit_index = e.col_index; - if(this->bit_nodes.contains(bit_index)){ - int matrix_bit_index = cluster_to_matrix_bit_map[bit_index]; - int matrix_check_index = cluster_to_matrix_check_map[check_index]; - cluster_pcm.insert_entry(matrix_check_index,matrix_bit_index); + for (int check_index: this->check_nodes) { + for (auto &e: this->pcm.iterate_row(check_index)) { + int bit_index = e.col_index; + if (this->bit_nodes.contains(bit_index)) { + int matrix_bit_index = cluster_to_matrix_bit_map[bit_index]; + int matrix_check_index = cluster_to_matrix_check_map[check_index]; + cluster_pcm.insert_entry(matrix_check_index, matrix_bit_index); + } } } + return cluster_pcm; } - return cluster_pcm; - - } - - - std::vector invert_decode(const std::vector& syndrome, const std::vector& bit_weights){ - - auto cluster_pcm = this->convert_to_matrix(bit_weights); - - std::vector cluster_syndrome; - for(int check_index: check_nodes){ - cluster_syndrome.push_back(syndrome[check_index]); - } - - auto rr = ldpc::gf2sparse_linalg::RowReduce(cluster_pcm); - auto cluster_solution = rr.fast_solve(cluster_syndrome); - - auto candidate_cluster_syndrome = cluster_pcm.mulvec(cluster_solution); - - bool equal = true; - for(int i =0; i invert_decode(const std::vector &syndrome, const std::vector &bit_weights) { + auto cluster_pcm = this->convert_to_matrix(bit_weights); + std::vector cluster_syndrome; - this->cluster_decoding.clear(); - this->valid = equal; - for(int i = 0; icluster_decoding.push_back(this->matrix_to_cluster_bit_map[i]); + for (auto check_index: check_nodes) { + cluster_syndrome.push_back(syndrome[check_index]); } - } - - // delete cluster_pcm; - - return this->cluster_decoding; - - } - - std::vector invert_decode2(const std::vector& syndrome, std::vector& bit_weights){ - - auto cluster_pcm = this->convert_to_matrix(bit_weights); - - std::cout<<"After cluter pcm gen"< cluster_syndrome; - int synd_weight = 0; - for(int check_index: check_nodes){ - cluster_syndrome.push_back(syndrome[check_index]); - synd_weight += syndrome[check_index]; - } - - // std::cout<<"HEllo"<cluster_decoding.clear(); - bool equal; - if(synd_weight > 0){ - - - auto rr = ldpc::gf2sparse_linalg::RowReduce(cluster_pcm); auto cluster_solution = rr.fast_solve(cluster_syndrome); - auto candidate_cluster_syndrome = cluster_pcm.mulvec(cluster_solution); + bool equal = true; - - - equal = true; - for(int i =0; icluster_decoding.clear(); + this->valid = equal; + for (auto i = 0; i < cluster_solution.size(); i++) { + if (cluster_solution[i] == 1) { this->cluster_decoding.push_back(this->matrix_to_cluster_bit_map[i]); } } - + return this->cluster_decoding; } - else{ - equal = false; - } - - this->valid = equal; - - - // std::cout<<"HEllo2"<cluster_decoding; - - } + void print(); + }; - void print(); -}; - - -Cluster* bit_cluster(ldpc::bp::BpSparse& parity_check_matrix, int bit_index, Cluster** ccm, Cluster** bcm){ - - Cluster* cl = new Cluster(parity_check_matrix, bit_index, ccm, bcm); - - - cl->global_check_membership[bit_index] = NULL; - cl->global_bit_membership[bit_index] = cl; - cl->bit_nodes.insert(bit_index); - cl->check_nodes.clear(); - cl->enclosed_syndromes.clear(); - cl->boundary_check_nodes.clear(); - - - for(auto& e: cl->pcm.iterate_column(bit_index)){ - int check_index = e.row_index; - cl->check_nodes.insert(check_index); - cl->boundary_check_nodes.insert(check_index); - cl->global_check_membership[check_index] = cl; - } - - return cl; - -} - - - - -class UfDecoder{ + class UfDecoder { private: bool weighted; - ldpc::bp::BpSparse& pcm; + ldpc::bp::BpSparse &pcm; public: std::vector decoding; int bit_count; int check_count; - UfDecoder(ldpc::bp::BpSparse& parity_check_matrix): pcm(parity_check_matrix){ + tsl::robin_set planar_code_boundary_bits; + bool pcm_max_bit_degree_2; + + UfDecoder(ldpc::bp::BpSparse &parity_check_matrix) : pcm(parity_check_matrix) { this->bit_count = pcm.n; this->check_count = pcm.m; this->decoding.resize(this->bit_count); this->weighted = false; + + this->pcm_max_bit_degree_2 = true; + for (auto i = 0; i < this->pcm.n; i++) { + int col_weight = this->pcm.get_col_degree(i); + if (col_weight > 2) { + this->pcm_max_bit_degree_2 = false; + } else if (col_weight == 1) { + this->planar_code_boundary_bits.insert(i); + } else if (col_weight == 0) { + throw (std::runtime_error("Invalid parity check matrix. Column weight is zero.")); + } + } } - std::vector& peel_decode(const std::vector& syndrome, const std::vector& bit_weights = NULL_DOUBLE_VECTOR, int bits_per_step = 1){ + std::vector & + peel_decode(const std::vector &syndrome, const std::vector &bit_weights = EMPTY_DOUBLE_VECTOR, + int bits_per_step = 1) { - fill(this->decoding.begin(), this->decoding.end(), 0); - - std::vector clusters; - std::vector invalid_clusters; - Cluster** global_bit_membership = new Cluster*[pcm.n](); - Cluster** global_check_membership = new Cluster*[pcm.m](); + if (!this->pcm_max_bit_degree_2) { + throw (std::runtime_error( + "Peel decoder only works for planar codes. Use the matrix_decode method for more general codes.")); + } - for(int i =0; ipcm.m; i++){ - if(syndrome[i] == 1){ - Cluster* cl = new Cluster(this->pcm, i, global_check_membership, global_bit_membership); + fill(this->decoding.begin(), this->decoding.end(), 0); + std::vector clusters; + std::vector invalid_clusters; + auto **global_bit_membership = new Cluster *[pcm.n](); + auto **global_check_membership = new Cluster *[pcm.m](); + + for (int i = 0; i < this->pcm.m; i++) { + if (syndrome[i] == 1) { + auto *cl = new Cluster(this->pcm, i, global_check_membership, global_bit_membership, + this->planar_code_boundary_bits); clusters.push_back(cl); invalid_clusters.push_back(cl); } } - while(invalid_clusters.size()>0){ - - for(auto cl: invalid_clusters){ - if(cl->active){ - cl->grow_cluster(bit_weights,bits_per_step); + while (!invalid_clusters.empty()) { + for (auto cl: invalid_clusters) { + if (cl->active) { + cl->grow_cluster(bit_weights, bits_per_step); } } invalid_clusters.clear(); - for(auto cl: clusters){ - if(cl->active == true && cl->parity() == 1){ + for (auto cl: clusters) { + if (cl->active && cl->parity() == 1 && !cl->contains_boundary_bits) { invalid_clusters.push_back(cl); } } - - std::sort(invalid_clusters.begin(), invalid_clusters.end(), [](const Cluster* lhs, const Cluster* rhs){return lhs->bit_nodes.size() < rhs->bit_nodes.size();}); - + std::sort(invalid_clusters.begin(), invalid_clusters.end(), [](const Cluster *lhs, const Cluster *rhs) { + return lhs->bit_nodes.size() < rhs->bit_nodes.size(); + }); } - - for(auto cl: clusters){ - if(cl->active){ + for (auto cl: clusters) { + if (cl->active) { auto erasure = cl->peel_decode(syndrome); - for(int bit: erasure) this->decoding[bit] = 1; + for (int bit: erasure) this->decoding[bit] = 1; } delete cl; } - delete[] global_bit_membership; delete[] global_check_membership; - return this->decoding; - } - std::vector& matrix_decode(const std::vector& syndrome, const std::vector& bit_weights = NULL_DOUBLE_VECTOR, int bits_per_step = 1){ - + std::vector & + matrix_decode(const std::vector &syndrome, + const std::vector &bit_weights = EMPTY_DOUBLE_VECTOR, + int bits_per_step = 1) { fill(this->decoding.begin(), this->decoding.end(), 0); - std::vector clusters; - std::vector invalid_clusters; - Cluster** global_bit_membership = new Cluster*[pcm.n](); - Cluster** global_check_membership = new Cluster*[pcm.m](); + std::vector clusters; + std::vector invalid_clusters; + auto **global_bit_membership = new Cluster *[pcm.n](); + auto **global_check_membership = new Cluster *[pcm.m](); - for(int i =0; ipcm.m; i++){ - if(syndrome[i] == 1){ - Cluster* cl = new Cluster(this->pcm, i, global_check_membership, global_bit_membership); + for (auto i = 0; i < this->pcm.m; i++) { + if (syndrome[i] == 1) { + auto *cl = new Cluster(this->pcm, i, global_check_membership, global_bit_membership); clusters.push_back(cl); invalid_clusters.push_back(cl); } } - while(invalid_clusters.size()>0){ - - for(auto cl: invalid_clusters){ - if(cl->active){ - cl->grow_cluster(bit_weights,bits_per_step); - auto cluster_decoding = cl->invert_decode(syndrome,bit_weights); + while (!invalid_clusters.empty()) { + for (auto cl: invalid_clusters) { + if (cl->active) { + cl->grow_cluster(bit_weights, bits_per_step); + auto cluster_decoding = cl->invert_decode(syndrome, bit_weights); } } - // for(auto cl: invalid_clusters){ - // if(cl->active){ - // auto cluster_decoding = cl->invert_decode(syndrome,bit_weights); - // } - // } - invalid_clusters.clear(); - for(auto cl: clusters){ - if(cl->active == true && cl->valid == false){ + for (auto cl: clusters) { + if (cl->active && !cl->valid) { invalid_clusters.push_back(cl); } } - - std::sort(invalid_clusters.begin(), invalid_clusters.end(), [](const Cluster* lhs, const Cluster* rhs){return lhs->bit_nodes.size() < rhs->bit_nodes.size();}); - + std::sort(invalid_clusters.begin(), invalid_clusters.end(), [](const Cluster *lhs, const Cluster *rhs) { + return lhs->bit_nodes.size() < rhs->bit_nodes.size(); + }); } - for(auto cl: clusters){ - if(cl->active){ - for(int bit: cl->cluster_decoding) this->decoding[bit] = 1; + for (auto cl: clusters) { + if (cl->active) { + for (int bit: cl->cluster_decoding) this->decoding[bit] = 1; } delete cl; } - delete[] global_bit_membership; delete[] global_check_membership; - - // std::cout<<"hello from end of C++ function"<decoding; - - } - - std::vector& bit_cluster_decode(const std::vector& syndrome, std::vector& bit_weights, int bits_per_step = 1, int cluster_count = 10){ - - fill(this->decoding.begin(), this->decoding.end(), 0); - - std::vector clusters; - std::vector invalid_clusters; - Cluster** global_bit_membership = new Cluster*[pcm.n](); - Cluster** global_check_membership = new Cluster*[pcm.m](); - - std::vector sparse_syndrome; - - - for(int i =0; ipcm.m; i++){ - if(syndrome[i] == 1){ - sparse_syndrome.push_back(i); - } - } - - - std::vector col_indices; - for(int i = 0; ipcm.n; i++){ - col_indices.push_back(i); - } - - ldpc::sort::soft_decision_col_sort(bit_weights, col_indices, this->pcm.n); - - int max_clusters = std::min(cluster_count, pcm.n); - - for(int i = 0; i < max_clusters; i++){ - - int bit_index = col_indices[i]; - - Cluster* cl = new Cluster(this->pcm, bit_index, global_check_membership, global_bit_membership); - cl->active=true; - cl->valid=false; - cl->cluster_id = bit_index; - cl->boundary_check_nodes.clear(); - cl->check_nodes.clear(); - cl->enclosed_syndromes.clear(); - cl->global_check_membership[bit_index] = NULL; - cl->global_bit_membership[bit_index] = cl; - - clusters.push_back(cl); - invalid_clusters.push_back(cl); - - } - - // while(invalid_clusters.size()>0){ - - // for(auto cl: invalid_clusters){ - // if(cl->active){ - // std::cout<print(); - - // cl->grow_cluster(bit_weights,bits_per_step); - // std::cout<<"HEllo64"<invert_decode2(syndrome,bit_weights); - // std::cout<<"HEllo66"<active == true && cl->valid == false){ - // invalid_clusters.push_back(cl); - // } - // } - - - - // sort(invalid_clusters.begin(), invalid_clusters.end(), [](const Cluster* lhs, const Cluster* rhs){return lhs->bit_nodes.size() < rhs->bit_nodes.size();}); - - // bool exit_while = true; - // for(auto synd_index: sparse_syndrome){ - // auto cl = global_check_membership[synd_index]; - // if(cl==NULL){ - // exit_while = false; - // } - // else if (cl->valid == false){ - // exit_while = false; - // } - - // } - - - - // if(exit_while) break; - - - - // } - - - - - for(auto cl: clusters){ - if(cl->active){ - for(int bit: cl->cluster_decoding) this->decoding[bit] = 1; - } - // delete cl; - } - - - std::cout<<"HEllo7"<decoding); - - - return this->decoding; - } - -}; - -void Cluster::print(){ - std::cout<<"........."<cluster_id<active<enclosed_syndromes) std::cout<bit_nodes) std::cout<check_nodes) std::cout<candidate_bit_nodes) std::cout<boundary_check_nodes) std::cout<spanning_tree_bits) std::cout<cluster_id << std::endl; + std::cout << "Active: " << this->active << std::endl; + std::cout << "Enclosed syndromes: "; + for (auto i: this->enclosed_syndromes) std::cout << i << " "; + std::cout << std::endl; + std::cout << "Cluster bits: "; + for (auto i: this->bit_nodes) std::cout << i << " "; + std::cout << std::endl; + std::cout << "Cluster checks: "; + for (auto i: this->check_nodes) std::cout << i << " "; + std::cout << std::endl; + std::cout << "Candidate bits: "; + for (auto i: this->candidate_bit_nodes) std::cout << i << " "; + std::cout << std::endl; + std::cout << "Boundary Checks: "; + for (auto i: this->boundary_check_nodes) std::cout << i << " "; + std::cout << std::endl; + std::cout << "Spanning tree bits: "; + for (auto i: this->spanning_tree_bits) std::cout << i << " "; + std::cout << std::endl; + std::cout << "Spanning tree leaf nodes: "; + for (auto i: this->spanning_tree_leaf_nodes) std::cout << i << " "; + std::cout << std::endl; + std::cout << "Contains boundary bits: " << this->contains_boundary_bits << std::endl; + std::cout << "Boundary bits: "; + for (auto i: this->planar_code_boundary_bits) std::cout << i << " "; + std::cout << std::endl; + std::cout << "........." << std::endl; } - - }//end namespace uf #endif \ No newline at end of file diff --git a/src_python/ldpc/belief_find_decoder/__init__.pyi b/src_python/ldpc/belief_find_decoder/__init__.pyi index 44d230c..f16f0f4 100644 --- a/src_python/ldpc/belief_find_decoder/__init__.pyi +++ b/src_python/ldpc/belief_find_decoder/__init__.pyi @@ -74,5 +74,4 @@ class BeliefFindDecoder(BpDecoderBase): @property def uf_method(self): - @uf_method.setter - def uf_method(self, uf_method: str): \ No newline at end of file + def set_uf_method(self, uf_method: str): \ No newline at end of file diff --git a/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pxd b/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pxd index 85e02fe..38c3347 100644 --- a/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pxd +++ b/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pxd @@ -15,7 +15,7 @@ cdef extern from "union_find.hpp" namespace "ldpc::uf": vector[uint8_t]& matrix_decode(vector[uint8_t]& syndrome, const vector[double]& bit_weights, int bits_per_step) vector[uint8_t] decoding - cdef const vector[double] NULL_DOUBLE_VECTOR + cdef const vector[double] EMPTY_DOUBLE_VECTOR cdef class BeliefFindDecoder(BpDecoderBase): cdef uf_decoder_cpp* ufd diff --git a/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pyx b/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pyx index c8ddf8b..f61043e 100644 --- a/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pyx +++ b/src_python/ldpc/belief_find_decoder/_belief_find_decoder.pyx @@ -54,12 +54,22 @@ cdef class BeliefFindDecoder(BpDecoderBase): def __cinit__(self, pcm: Union[np.ndarray, scipy.sparse.spmatrix], error_rate: Optional[float] = None, error_channel: Optional[List[float]] = None, max_iter: Optional[int] = 0, bp_method: Optional[str] = 'minimum_sum', ms_scaling_factor: Optional[float] = 1.0, schedule: Optional[str] = 'parallel', omp_thread_count: Optional[int] = 1, - random_schedule_seed: Optional[int] = 0, serial_schedule_order: Optional[List[int]] = None, uf_method: str = True, bits_per_step:int = 0, input_vector_type: str = "syndrome"): + random_schedule_seed: Optional[int] = 0, serial_schedule_order: Optional[List[int]] = None, uf_method: str = "peeling", bits_per_step:int = 0, input_vector_type: str = "syndrome"): self.MEMORY_ALLOCATED=False self.ufd = new uf_decoder_cpp(self.pcm[0]) self.bf_decoding.resize(self.n) #C vector for the bf decoding self.residual_syndrome.resize(self.m) #C vector for the bf decoding - self.uf_method = uf_method + if uf_method.lower() in ["inversion", "invert", "matrix"]: + self.uf_method = "inversion" + elif uf_method.lower() in ["peeling", "peel"]: + self.uf_method = "peeling" + # Check that the PCM is suitable for the peeling method + for i in range(self.n): + if self.pcm.get_col_degree(i) > 2: + raise ValueError(f"The 'peeling' method is only suitable for LDPC codes with point like syndromes. Each column of the PCM must have at most 2 entries. Column {i} has degree {self.pcm.get_col_degree(i)}.") + else: + raise ValueError(f"Invalid UF method: {uf_method}. Must be one of 'inversion' or 'peeling'.") + if bits_per_step == 0: self.bits_per_step = pcm.shape[1] else: @@ -129,17 +139,3 @@ cdef class BeliefFindDecoder(BpDecoderBase): @property def uf_method(self): return self.uf_method - - @uf_method.setter - def uf_method(self, uf_method: str): - if uf_method.lower() in ["inversion", "invert", "matrix"]: - self.uf_method = "inversion" - elif uf_method.lower() in ["peeling", "peel"]: - self.uf_method = "peeling" - else: - raise ValueError(f"Invalid UF method: {uf_method}. Must be one of 'inversion' or 'peeling'.") - - - - # def maximum_cluster_size(self): - # return self.ufd.maximum_cluster_size[0], self.ufd.maximum_cluster_size[1] \ No newline at end of file diff --git a/src_python/ldpc/bp_decoder/_bp_decoder.pxd b/src_python/ldpc/bp_decoder/_bp_decoder.pxd index e7fa9f5..41493ae 100644 --- a/src_python/ldpc/bp_decoder/_bp_decoder.pxd +++ b/src_python/ldpc/bp_decoder/_bp_decoder.pxd @@ -41,6 +41,9 @@ cdef extern from "bp.hpp" namespace "ldpc::bp": vector[vector[int]] nonzero_coordinates() int entry_count() + int get_col_degree(int col) + int get_row_degree(int row) + cdef cppclass BpDecoderCpp "ldpc::bp::BpDecoder": BpDecoderCpp( BpSparse& parity_check_matrix, diff --git a/src_python/ldpc/bplsd_decoder/_bplsd_decoder.pxd b/src_python/ldpc/bplsd_decoder/_bplsd_decoder.pxd index 881913a..b8c91c0 100644 --- a/src_python/ldpc/bplsd_decoder/_bplsd_decoder.pxd +++ b/src_python/ldpc/bplsd_decoder/_bplsd_decoder.pxd @@ -13,7 +13,7 @@ from libcpp.unordered_map cimport unordered_map as cpp_map cdef extern from "lsd.hpp" namespace "ldpc::lsd": - cdef const vector[double] NULL_DOUBLE_VECTOR "ldpc::lsd::NULL_DOUBLE_VECTOR" + cdef const vector[double] EMPTY_DOUBLE_VECTOR "ldpc::lsd::EMPTY_DOUBLE_VECTOR" cdef struct ClusterStatistics "ldpc::lsd::ClusterStatistics": int final_bit_count diff --git a/src_python/ldpc/union_find_decoder/_union_find_decoder.pxd b/src_python/ldpc/union_find_decoder/_union_find_decoder.pxd index 0bcce64..98bad54 100644 --- a/src_python/ldpc/union_find_decoder/_union_find_decoder.pxd +++ b/src_python/ldpc/union_find_decoder/_union_find_decoder.pxd @@ -15,7 +15,7 @@ cdef extern from "union_find.hpp" namespace "ldpc::uf": vector[uint8_t]& matrix_decode(vector[uint8_t]& syndrome, const vector[double]& bit_weights, int bits_per_step) vector[uint8_t] decoding - cdef const vector[double] NULL_DOUBLE_VECTOR "ldpc::uf::NULL_DOUBLE_VECTOR" + cdef const vector[double] EMPTY_DOUBLE_VECTOR "ldpc::uf::EMPTY_DOUBLE_VECTOR" cdef class UnionFindDecoder(): cdef int m diff --git a/src_python/ldpc/union_find_decoder/_union_find_decoder.pyx b/src_python/ldpc/union_find_decoder/_union_find_decoder.pyx index 304bb9f..8bb97b8 100644 --- a/src_python/ldpc/union_find_decoder/_union_find_decoder.pyx +++ b/src_python/ldpc/union_find_decoder/_union_find_decoder.pyx @@ -146,14 +146,14 @@ cdef class UnionFindDecoder: if llrs is not None: self.ufd.decoding = self.ufd.matrix_decode(self._syndrome, self.uf_llrs,self.bits_per_step) else: - self.ufd.decoding = self.ufd.matrix_decode(self._syndrome, NULL_DOUBLE_VECTOR,self.bits_per_step) + self.ufd.decoding = self.ufd.matrix_decode(self._syndrome, EMPTY_DOUBLE_VECTOR,self.bits_per_step) else: if llrs is not None: self.ufd.decoding = self.ufd.peel_decode(self._syndrome, self.uf_llrs,self.bits_per_step) else: - self.ufd.decoding = self.ufd.peel_decode(self._syndrome, NULL_DOUBLE_VECTOR,self.bits_per_step) + self.ufd.decoding = self.ufd.peel_decode(self._syndrome, EMPTY_DOUBLE_VECTOR,self.bits_per_step) out = np.zeros(self.n,dtype=DTYPE)