template <class GF_q, class real> bool linear_code_utils<GF_q, real>::is_systematic( const matrix<GF_q> & genMat) { int dim_k = genMat.size().rows(); int loop1 = 0; bool isSystematic = true; //easy check - is the diagonal made of 1s while (isSystematic && (loop1 < dim_k)) { if (genMat(loop1, loop1) != GF_q(1)) { isSystematic = false; } loop1++; } //check that the non-diagonal entries are zero loop1 = 0; int loop2 = 1; while (isSystematic && (loop1 < dim_k)) { do { if ((GF_q(0) != genMat(loop1, loop2)) && (loop1 != loop2)) { isSystematic = false; } loop2++; } while (isSystematic && (loop2 < dim_k)); loop2 = 0; loop1++; } return isSystematic; }
template <class GF_q, class real> bool linear_code_utils<GF_q, real>::compute_syndrome( const matrix<GF_q> & parMat, const array1gfq_t & received_word_hd, array1gfq_t & syndrome_vec) { bool dec_success = true; int dim_m = parMat.size().rows(); int length_n = parMat.size().cols(); //check that we have compatible lengths assertalways(received_word_hd.size().length() == length_n); syndrome_vec.init(dim_m); GF_q tmp_val = GF_q(0); for (int rows = 0; rows < dim_m; rows++) { tmp_val = GF_q(0); for (int cols = 0; cols < length_n; cols++) { tmp_val += parMat(rows, cols) * received_word_hd(cols); } if (tmp_val != GF_q(0)) { //the syndrome is non-zero dec_success = false; } syndrome_vec(rows) = tmp_val; } return dec_success; }
template <class GF_q, class real> void linear_code_utils<GF_q, real>::encode_cw( const matrix<GF_q> & mat_G, const array1i_t & source, array1i_t & encoded) { #if DEBUG>=2 libbase::trace << std::endl << "encoding"; #endif //initialise encoded int length_n = mat_G.size().cols(); int dim_k = mat_G.size().rows(); assertalways(dim_k == source.size().length()); encoded.init(length_n); for (int i = 0; i < length_n; i++) { GF_q val = GF_q(0); for (int j = 0; j < dim_k; j++) { val += GF_q(source(j)) * mat_G(j, i); } encoded(i) = val; } #if DEBUG>=2 libbase::trace << std::endl << "finished encoding"; #endif }
//determine the most likely symbol template <class GF_q, class real> void linear_code_utils<GF_q, real>::get_most_likely_received_word( const array1dv_t& received_likelihoods, array1d_t & received_word_sd, array1gfq_t& received_word_hd) { //some helper variables int length_n = received_likelihoods.size(); real mostlikely_sofar = real(0.0); int indx = 0; array1d_t tmp_vec; int num_of_symbs; received_word_sd.init(length_n); received_word_hd.init(length_n); for (int loop_n = 0; loop_n < length_n; loop_n++) { mostlikely_sofar = 0; indx = 0; tmp_vec = received_likelihoods(loop_n); num_of_symbs = tmp_vec.size(); for (int loop_q = 0; loop_q < num_of_symbs; loop_q++) { if (mostlikely_sofar <= tmp_vec(loop_q)) { mostlikely_sofar = tmp_vec(loop_q); indx = loop_q; } } received_word_sd(loop_n) = mostlikely_sofar; received_word_hd(loop_n) = GF_q(indx); } }
template <class GF_q, class real> void linear_code_utils<GF_q, real>::compute_dual_code( const matrix<GF_q> & orgMat, matrix<GF_q> & dualCodeGenMatrix, array1i_t & systematic_perm) { int length_n = orgMat.size().cols(); int dim_k = orgMat.size().rows(); int dim_m = length_n - dim_k; matrix<GF_q> refOrgMat; #if DEBUG>=2 std::cout << "The original matrix is given by:" << std::endl; orgMat.serialize(std::cout, '\n'); #endif linear_code_utils::compute_row_dim(orgMat, refOrgMat); dim_k = refOrgMat.size().rows(); dim_m = length_n - dim_k; // Now we need to check that the columns are systematic //if they aren't then we need to perform some column permutation //otherwise the permutation is simple the identy map systematic_perm.init(length_n); for (int loop1 = 0; loop1 < length_n; loop1++) { //the identity permutation systematic_perm(loop1) = loop1; } bool needsPermutation = !(libbase::linear_code_utils<GF_q, real>::is_systematic(refOrgMat)); if (needsPermutation) { //matrix needs its columns permuted before it is in systematic form //find the pivots int col_pos = 0; for (int loop1 = 0; loop1 < dim_k; loop1++) { while ((GF_q(1)) != refOrgMat(loop1, col_pos)) { col_pos++; } std::swap(systematic_perm(loop1), systematic_perm(col_pos)); col_pos++; } #if DEBUG>=2 std::cout << std::endl << "The permutation is given by:" << std::endl; systematic_perm.serialize(std::cout, ' '); #endif if (needsPermutation) { //rejig the matrix matrix<GF_q> tmprefMatrix; tmprefMatrix.init(dim_k, length_n); int col_index; for (int loop1 = 0; loop1 < length_n; loop1++) { col_index = systematic_perm(loop1); tmprefMatrix.insertcol(refOrgMat.extractcol(col_index), loop1); } refOrgMat = tmprefMatrix; } } //the matrix should now be in the right format #if DEBUG>=2 std::cout << "After permuting any columns, the matrix is now given by:" << std::endl; refOrgMat.serialize(std::cout, '\n'); #endif //extract the P part of G'=(I_k|P) matrix<GF_q> tmp_p_mat; tmp_p_mat.init(dim_k, dim_m); for (int loop = dim_k; loop < length_n; loop++) { tmp_p_mat.insertcol(refOrgMat.extractcol(loop), loop - dim_k); } //this will hold -P^t=P^t (as we are in char GF(q)=2) matrix<GF_q> tmp_p_mat_t; tmp_p_mat_t.init(dim_m, length_n - dim_m); //now transpose yourself tmp_p_mat_t = tmp_p_mat.transpose(); matrix<GF_q> id_m = matrix<GF_q>::eye(dim_m); //Construct the dual code gen matrix which is of the form //H=(-P^t|I_m) dualCodeGenMatrix.init(dim_m, length_n); //insert the transposed matrix for (int loop = 0; loop < (length_n - dim_m); loop++) { dualCodeGenMatrix.insertcol(tmp_p_mat_t.extractcol(loop), loop); } //now add the identity matrix int counter = 0; for (int loop = (length_n - dim_m); loop < length_n; loop++) { dualCodeGenMatrix.insertcol(id_m.extractcol(counter), loop); counter++; } #if DEBUG>=2 std::cout << "The generator matrix of the permuted dual code is given by:" << std::endl; dualCodeGenMatrix.serialize(std::cout, '\n'); #endif //undo any permutation that we did if (needsPermutation) { matrix<GF_q> tmpdualCodeGenMatrix; tmpdualCodeGenMatrix.init(dim_m, length_n); int col_index; for (int loop1 = 0; loop1 < length_n; loop1++) { col_index = systematic_perm(loop1); tmpdualCodeGenMatrix.insertcol(dualCodeGenMatrix.extractcol(loop1), col_index); } dualCodeGenMatrix = tmpdualCodeGenMatrix; } #if DEBUG>=2 std::cout << "After undoing the permutation, the generator matrix of the dual code is given by:" << std::endl; dualCodeGenMatrix.serialize(std::cout, '\n'); #endif #if DEBUG>=2 std::cout << "we now multiply the generator matrix by the transpose of the original matrix, ie:" << std::endl; std::cout << "the transpose of:" << std::endl; orgMat.serialize(std::cout, '\n'); std::cout << "is:" << std::endl; matrix<GF_q> trans(orgMat.transpose()); trans.serialize(std::cout, '\n'); matrix<GF_q> zeroTest(dualCodeGenMatrix*trans); std::cout << "the result is:" << std::endl; zeroTest.serialize(std::cout, '\n'); assertalways(GF_q(0)==zeroTest.max()); #endif }
template <class GF_q, class real> void linear_code_utils<GF_q, real>::compute_row_dim( const matrix<GF_q>& orgMat, matrix<GF_q> & maxRowSpaceMat) { int length_n = orgMat.size().cols(); int dim_k = orgMat.size().rows(); //copy original matrix and reduce it to REF, ie G'=(I_k|P) matrix<GF_q> refOrgMat(orgMat.reduce_to_ref()); #if DEBUG>=2 std::cout << "The REF is given by:" << std::endl; refOrgMat.serialize(std::cout, '\n'); #endif //quick check that we at least have the right dimension //since the matrix is in REF, the last rows of the matrix //should not be equal to zero. If the last row of the matrix is zero //then keep dropping it until it isn't. Consequently, the row dimension //of the generator matrix is reduced by the number of dropped rows. int loop1 = dim_k; int loop2; bool isZero = true; while (isZero && (loop1 > 0)) { loop1--; loop2 = length_n; while (isZero && (loop2 >= dim_k)) { loop2--; if (refOrgMat(loop1, loop2) != (GF_q(0))) { isZero = false; } } } #if DEBUG>=2 std::cout << "We have " << (dim_k - loop1) - 1 << " zero rows." << std::endl; #endif //compensate for the fact the we start counting rows from 0 loop1++; if (loop1 < dim_k) { dim_k = loop1; //the matrix contains zero rows - drop them maxRowSpaceMat.init(dim_k, length_n); for (loop2 = 0; loop2 < dim_k; loop2++) { maxRowSpaceMat.insertrow(refOrgMat.extractrow(loop2), loop2); } #if DEBUG>=2 std::cout << "After dropping zero rows, the REF is given by:" << std::endl; maxRowSpaceMat.serialize(std::cout, '\n'); #endif } else { //the original matrix is ok already maxRowSpaceMat = refOrgMat; } }
void sum_prod_alg_trad<GF_q, real>::compute_r_mn(int m, int n, const array1i_t & tmpN_m) { //the number of remaining symbols that can vary int num_of_var_syms = tmpN_m.size() - 1; int num_of_elements = GF_q::elements(); //for each check node we need to consider num_of_elements^num_of_var_symbols cases int num_of_cases = int(pow(num_of_elements, num_of_var_syms)); int pos_n = tmpN_m(n) - 1;//we count from 1; int bitmask = num_of_elements - 1; //only use the entries that are variable array1i_t rel_N_m; rel_N_m.init(num_of_var_syms); int indx = 0; for (int loop = 0; loop < num_of_var_syms; loop++) { if (indx == n) { indx++; } rel_N_m(loop) = tmpN_m(indx); indx++; } //go through all cases - this will use bitwise manipulation GF_q syndrome_sym = GF_q(0); GF_q h_m_n_dash; //GF_q h_m_n; GF_q tmp_chk_val; int int_sym_val; int bits; int pos_n_dash; real q_nm_prod = real(1.0); this->marginal_probs(m, pos_n).r_mxn = 0.0; GF_q check_value = this->marginal_probs(m, pos_n).val; for (int loop1 = 0; loop1 < num_of_cases; loop1++) { bits = loop1; syndrome_sym = GF_q(0); q_nm_prod = 1.0; for (int loop2 = 0; loop2 < num_of_var_syms; loop2++) { pos_n_dash = rel_N_m(loop2) - 1;//we count from zero //extract int value of the first symbol int_sym_val = bits & bitmask; //shift bits to the right by the dimension of the finite field bits = bits >> GF_q::dimension(); //the parity check symbol at this position h_m_n_dash = this->marginal_probs(m, pos_n_dash).val; //compute the value that at this check tmp_chk_val = h_m_n_dash * GF_q(int_sym_val); //add it to the syndrome syndrome_sym = syndrome_sym + tmp_chk_val; //look up the prob that the chk_val was actually sent q_nm_prod *= this->marginal_probs(m, pos_n_dash).q_mxn(int_sym_val); } //adjust the appropriate rmn value int_sym_val = syndrome_sym / check_value; this->marginal_probs(m, pos_n).r_mxn(int_sym_val) += q_nm_prod; } }