2
3
4
5
6
7
8
9
10
11
12
13
14
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
57#define BOLD(x) "\033[1m" x "\033[0m"
61template <FiniteFieldType T>
63 constexpr size_t q = T::get_size();
65 auto a = Vector<InfInt>(n + 1);
66 for (size_t i = 0; i < n + 1; ++i) a.set_component(i, A[i]);
68 Matrix<InfInt> K(n + 1, n + 1);
69 for (size_t i = 0; i < n + 1; ++i) {
70 if (a[i] == 0)
continue;
71 for (size_t j = 0; j < n + 1; ++j) {
74 for (size_t h = 0; h <= j; ++h) {
76
77
78
79
80
83 const auto b = bin<
InfInt>(i, h);
85 const auto c = sqm<
InfInt>(q - 1, j - h);
93 K.set_component(i, j, sum);
96 return Polynomial<InfInt>(Vector<InfInt>(a) * Matrix<InfInt>(K) / sqm<InfInt>(q, k));
125template <ComponentType T>
137 if (
this != &other) {
148 virtual Vector<T>
enc(
const Vector<T>& u)
const {
throw std::logic_error(
"Encoding not supported for this code!"); }
150 throw std::logic_error(
"Inverse encoding not supported for this code!");
153 throw std::logic_error(
"Bounded distance decoding not supported for this code!");
156 throw std::logic_error(
"Boosted bounded distance decoding not supported for this code!");
159 throw std::logic_error(
"ML decoding not supported for this code!");
162 throw std::logic_error(
"Viterbi decoding not supported for this code!");
165 throw std::logic_error(
"Soft-input ML decoding not supported for this code!");
168 throw std::logic_error(
"Soft-input Viterbi decoding not supported for this code!");
171 throw std::logic_error(
"BCJR decoding not supported for this code!");
174 throw std::logic_error(
"Burst decoding not supported for this code!");
177 throw std::logic_error(
"Recursive decoding not supported for this code!");
180 throw std::logic_error(
"Meggitt decoding not supported for this code!");
183 throw std::logic_error(
"Welch-Berlekamp decoding not supported for this code!");
186 throw std::logic_error(
"Berlekamp-Massey decoding not supported for this code!");
188#ifdef CECCO_ERASURE_SUPPORT
190 throw std::
logic_error(
"BD error/erasure decoding not supported for this code!");
193 throw std::
logic_error(
"ML error/erasure decoding not supported for this code!");
196 throw std::
logic_error(
"Viterbi error/erasure decoding not supported for this code!");
199 throw std::
logic_error(
"Recursive error/erasure decoding not supported for this code!");
202 throw std::
logic_error(
"Welch-Berlekamp error/erasure decoding not supported for this code!");
205 throw std::
logic_error(
"Berlekamp-Massey error/erasure decoding not supported for this code!");
211#ifdef CECCO_ERASURE_SUPPORT
222template <ComponentType T>
234 Code<T>::get_info(os);
240template <FieldType T>
243template <FiniteFieldType T>
246template <FiniteFieldType T>
249template <FiniteFieldType T>
252template <FiniteFieldType T>
255template <FieldType T,
class B>
259template <FiniteFieldType T>
273 constexpr size_t q = T::get_size();
274 if (s < C.get_size()) {
275 const size_t k = C.get_k();
276 for (size_t i = 0; i < k; ++i) {
277 u.set_component(i, T((s % q).toInt()));
287 constexpr size_t q = T::get_size();
288 const size_t k = C.get_k();
290 if (counter < C.get_size()) {
292 for (size_t i = 0; i < k; ++i) {
293 const auto quot = j / q;
294 const auto rem = (j % q).toInt();
295 u.set_component(i, T(rem));
313 const char*
what()
const noexcept override {
return message.c_str(); }
316 const std::string message;
319template <FieldType T>
329 if (X.get_n() !=
this->n)
throw std::invalid_argument(
"G must have " +
std::to_string(
this->n) +
" columns");
331 if (!X.is_zero() && !X.is_invertible())
332 throw std::invalid_argument(
"Cannot construct linear code: G must be a zero matrix");
333 G = ZeroMatrix<T>(1, n);
334 HT = IdentityMatrix<T>(n);
338 if (X.get_m() == k) {
341 throw std::invalid_argument(
"Cannot construct linear code: G must have full rank " +
std::to_string(k));
343 HT =
G.basis_of_nullspace().rref().transpose();
344 const auto Gp = rref(
G);
346 for (size_t j = 0; j < k; ++j) {
347 const auto u = unit_vector<T>(k, j);
348 while (Gp.get_col(i) != u) ++i;
349 infoset.push_back(i);
351 }
else if (X.get_m() ==
this->n - k) {
353 if (X.rank() !=
this->n - k)
354 throw std::invalid_argument(
"Cannot construct linear code: H must have full rank " +
355 std::to_string(
this->n - k));
356 G = X.basis_of_nullspace();
360 for (size_t j = 0; j < k; ++j) {
361 const auto u = unit_vector<T>(k, j);
362 while (
G.get_col(i) != u) ++i;
363 infoset.push_back(i);
366 throw std::invalid_argument(
"Cannot construct linear code: matrix must have " +
std::to_string(k) +
367 " rows (as G) or " +
std::to_string(
this->n - k) +
" rows (as H), got " +
368 std::to_string(X.get_m()));
371 for (
auto it = infoset.cbegin(); it != infoset.cend(); ++it) {
372 MI.set_submatrix(0, j, G.get_submatrix(0, *it, k, 1));
380 k + gamma.degree(), k,
381 ToeplitzMatrix(pad_back(pad_front(
Vector<T>(gamma), k + gamma.degree()), 2 * k + gamma.degree() - 1), k,
382 k + gamma.degree())) {
383 set_gamma(
std::move(gamma));
384 }
catch (
const std::invalid_argument& e) {
385 throw std::invalid_argument(std::string(
"Cannot construct linear code from polynomial: ") + e.what());
402#ifdef CECCO_ERASURE_SUPPORT
414 G(
std::move(other.G)),
415 HT(
std::move(other.HT)),
416 MI(
std::move(other.MI)),
425#ifdef CECCO_ERASURE_SUPPORT
435 if (
this != &other) {
436 Code<T>::operator=(other);
441 infoset = other.infoset;
443 weight_enumerator = other.weight_enumerator;
444 codewords = other.codewords;
445 standard_array = other.standard_array;
446 tainted = other.tainted;
447 tainted_burst = other.tainted_burst;
448 Meggitt_table = other.Meggitt_table;
449#ifdef CECCO_ERASURE_SUPPORT
450 punctured_codes_BD = other.punctured_codes_BD;
451 punctured_codes_ML = other.punctured_codes_ML;
453 polynomial = other.polynomial;
461 if (
this != &other) {
462 Code<T>::operator=(
std::move(other));
464 G =
std::move(other.G);
465 HT =
std::move(other.HT);
466 MI =
std::move(other.MI);
467 infoset = std::move(other.infoset);
468 dmin = std::move(other.dmin);
469 weight_enumerator = std::move(other.weight_enumerator);
470 codewords = std::move(other.codewords);
471 standard_array = std::move(other.standard_array);
472 tainted = std::move(other.tainted);
473 tainted_burst = std::move(other.tainted_burst);
474 Meggitt_table = std::move(other.Meggitt_table);
475#ifdef CECCO_ERASURE_SUPPORT
476 punctured_codes_BD = std::move(other.punctured_codes_BD);
477 punctured_codes_ML = std::move(other.punctured_codes_ML);
479 polynomial = std::move(other.polynomial);
487 double get_R()
const noexcept {
return static_cast<
double>(k) /
this->n; }
502 if (
k == 0)
throw std::
logic_error(
"Cannot calculate dmin of a dimension zero code!");
535 <<
"--> Calculating dmin, this requires finding minimal number of linearly dependent columns in H"
564 if (
k == 0)
throw std::
logic_error(
"Cannot calculate tmax of a dimension zero code!");
570 throw std::
logic_error(
"Cannot calculate weight enumerator of code over infinite field!");
577 }
else if (
k <=
this->
n -
k) {
578 std::
clog <<
"--> Calculating weight enumerator, this requires iterating through "
583 }
else if (
k ==
this->
n) {
587 std::
clog <<
"--> Using MacWilliams' identity for: " <<
std::
endl;
599 long double res = 0.0;
611 long double res = 0.0;
635 throw std::
logic_error(
"Bhattacharyya bound can only be calculated for binary codes!");
647 throw std::
logic_error(
"Cannot calculate generator polynomial of a code that is not polynomial!");
694 std::
cerr <<
"Memory allocation failed, standard array would be too large!" <<
std::
endl;
721 const auto s =
v *
HT;
833 std::
cerr <<
"Memory allocation failed, Meggitt table too large!" <<
std::
endl;
857
858
859
860
861
862
863
864
865
866
867
868
875 if (
this == &
other) {
898
899
900
901
902
903
904
905
906
907
908
909
910
911
919 if (
this == &
other) {
925 if (
this->
n -
k <
k) {
937 if (
L_ptr !=
nullptr) {
991 const auto L =
Bp *
MI;
1005 if (
L_ptr ==
nullptr &&
P_ptr ==
nullptr)
return true;
1009 if (
P_ptr !=
nullptr) {
1022 if (
used[
j])
continue;
1056 if (
k == 0)
return false;
1062 if (
k == 0)
return false;
1069 if (
k == 0)
return true;
1112 if (
k == 0)
return true;
1129 os <<
"[F_" <<
q <<
"; " <<
this->
n <<
", " <<
k <<
"]";
1140 os <<
"[Q; " <<
this->
n <<
", " <<
k <<
"]";
1153 os <<
BOLD(
"Linear code")
" with properties: { ";
1175 os <<
"polynomial(";
1250 if (
Gp(
i,
j) !=
T(0)) {
1256 if (
Gp(
i,
j) !=
T(0)) {
1339 std::
clog <<
"--> Calculating minimal trellis for code with " <<
sqm<
InfInt>(
q,
k) <<
" codewords"
1346 if (
Gp(
i,
j) !=
T(0)) {
1352 if (
Gp(
i,
j) !=
T(0)) {
1366 }
else if (
j ==
s) {
1393 if (
k == 0)
throw std::
logic_error(
"Cannot invert encoding wrt. a dimension zero code!");
1406 throw std::
logic_error(
"BD decoding only available for codes over finite fields!");
1408#ifdef CECCO_ERASURE_SUPPORT
1423 throw std::
logic_error(
"BD decoding only available for codes over finite fields!");
1425#ifdef CECCO_ERASURE_SUPPORT
1433 const auto s =
r *
HT;
1443 throw std::
logic_error(
"ML decoding only available for codes over finite fields!");
1445#ifdef CECCO_ERASURE_SUPPORT
1453 const auto s =
r *
HT;
1462 throw std::
logic_error(
"Burst decoding only available for codes over finite fields!");
1464#ifdef CECCO_ERASURE_SUPPORT
1473 const auto s =
r *
HT;
1478 "Linear code burst error decoder failed, coset of syndrome empty or tainted (ambiguous leader)!");
1487 throw std::
logic_error(
"Meggitt BD decoding only available for codes over finite fields!");
1489#ifdef CECCO_ERASURE_SUPPORT
1525 throw std::
logic_error(
"Viterbi decoding only available for codes over finite fields!");
1527#ifdef CECCO_ERASURE_SUPPORT
1532 throw std::
invalid_argument(
"Viterbi trellis TikZ export not supported for fields with size > 64!");
1546 throw std::
logic_error(
"Soft-input Viterbi decoding only available for codes over F_2!");
1562 throw std::
logic_error(
"BCJR decoding only available for codes over F_2!");
1565 if (
k == 0)
return Vector<
double>(
this->
n, 0.0);
1581 throw std::
logic_error(
"Soft-input ML decoding only available for codes over F_2!");
1623#ifdef CECCO_ERASURE_SUPPORT
1626 throw std::
logic_error(
"BD error/erasure decoding only available for codes over finite fields!");
1692 throw std::
logic_error(
"Viterbi error/erasure decoding only available for codes over finite fields!");
1696 throw std::
invalid_argument(
"Viterbi trellis TikZ export not supported for fields with size > 64!");
1710 throw std::
logic_error(
"ML error/erasure decoding only available for codes over finite fields!");
1777 throw std::
invalid_argument(
"GMD decoder: length of reliability vector must match code length");
1791 const auto trial = [&]() {
1818#ifdef CECCO_ERASURE_SUPPORT
1845#ifdef CECCO_ERASURE_SUPPORT
1854 template <
typename cost_t>
1855 Vector<T> viterbi_forward_pass_and_traceback(
const Trellis<T>& Tr,
1856 typename Trellis<T>::
template Viterbi_Workspace<cost_t>& ws,
1857 const std::string& filename =
"")
const {
1858 std::uniform_real_distribution<
double> uniform(0.0, 1.0);
1860 const size_t n =
this->n;
1861 using ws_t =
typename Trellis<T>::
template Viterbi_Workspace<cost_t>;
1864 if constexpr (T::get_size() <= 64) {
1865 if (!filename.empty()) {
1866 file.open(filename);
1867 Tr.
template tikz_header<ws_t>(file);
1871 std::fill(ws.path_costs_prev.begin(), ws.path_costs_prev.end(), ws_t::init);
1872 ws.path_costs_prev[0] = cost_t{0};
1874 for (size_t s = 0; s < n; ++s) {
1875 std::fill(ws.path_costs_curr.begin(), ws.path_costs_curr.end(), ws_t::init);
1876 std::fill(ws.tie_counts.begin(), ws.tie_counts.end(), 0);
1877 for (size_t j = 0; j < Tr.E[s].size(); ++j) {
1878 const auto& e = Tr.E[s][j];
1879 const cost_t cost = ws.path_costs_prev[e.from_id] + ws.edge_costs[s][j];
1880 if (cost < ws.path_costs_curr[e.to_id]) {
1881 ws.path_costs_curr[e.to_id] = cost;
1882 ws.backptrs[s + 1][e.to_id] = &e;
1883 ws.tie_counts[e.to_id] = 1;
1884 }
else if (cost == ws.path_costs_curr[e.to_id]) {
1885 ++ws.tie_counts[e.to_id];
1886 if (uniform(
gen()) < 1.0 / ws.tie_counts[e.to_id]) ws.backptrs[s + 1][e.to_id] = &e;
1889 std::swap(ws.path_costs_prev, ws.path_costs_curr);
1890 if constexpr (T::get_size() <= 64) {
1891 if (file.is_open()) Tr.tikz_picture(file, &ws, s + 1);
1898 cost_t best = ws.path_costs_prev[0];
1899 uint16_t sink_ties = 1;
1900 for (size_t u = 1; u < Tr.V[n].size(); ++u) {
1901 const cost_t c = ws.path_costs_prev[u];
1906 }
else if (c == best) {
1908 if (uniform(
gen()) < 1.0 / sink_ties) v = u;
1912 for (size_t s = n; s > 0; --s) {
1913 const auto* e = ws.backptrs[s][v];
1914 c_est.set_component(s - 1, e->value);
1921 Vector<
double> bcjr_forward_backward(
const Trellis<T>& Tr,
typename Trellis<T>::BCJR_Workspace& ws)
const
1927 auto max_star = [](
double a,
double b)
noexcept {
1937 const auto&
e =
Tr.
E[
s][
j];
1946 const auto&
e =
Tr.
E[
s - 1][
j];
1957 const auto&
e =
Tr.
E[
s][
j];
1970#ifdef CECCO_ERASURE_SUPPORT
1974 std::
clog <<
"--> Preparing punctured codes for BD error/erasure decoding" <<
std::
endl;
1995 std::
clog <<
"--> Preparing punctured codes for ML error/erasure decoding" <<
std::
endl;
2018 if (
tau == 0)
throw std::
invalid_argument(
"Cannot calculate punctured code index from erasure positions!");
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2078template <FiniteFieldType T>
2082 auto weight_enumerator = Polynomial<InfInt>();
2083 for (size_t i = 0; i <= n; ++i) weight_enumerator.set_coefficient(i, bin<
InfInt>(n, i));
2084 this->set_weight_enumerator(
std::move(weight_enumerator));
2088 if (
this->n !=
this->k)
throw std::invalid_argument(
"Linear code cannot be converted into universe code!");
2111 this->validate_length(r);
2112#ifdef CECCO_ERASURE_SUPPORT
2113 if (LinearCode<T>::erasures_present(r))
2114 throw decoding_failure(
"Universe code BD decoder failed, received vector contains erasures!");
2120 this->validate_length(r);
2121#ifdef CECCO_ERASURE_SUPPORT
2122 if (LinearCode<T>::erasures_present(r))
return dec_ML_EE(r);
2128 this->validate_length(r);
2129#ifdef CECCO_ERASURE_SUPPORT
2130 if (LinearCode<T>::erasures_present(r))
2131 throw decoding_failure(
"Universe code burst decoder failed, received vector contains erasures!");
2136#ifdef CECCO_ERASURE_SUPPORT
2139#ifdef CECCO_ERASURE_SUPPORT
2141 throw decoding_failure(
"Universe code BD error/erasure decoder failed, received vector contains erasures!");
2156template <FiniteFieldType T>
2162 if (
this->k != 0)
throw std::invalid_argument(
"Linear code cannot be converted into zero code!");
2181template <FiniteFieldType T>
2187 constexpr size_t q = T::get_size();
2188 Polynomial<InfInt> weight_enumerator_dual;
2189 weight_enumerator_dual.set_coefficient(0, 1);
2190 weight_enumerator_dual.set_coefficient(sqm<size_t>(q, s - 1), sqm<InfInt>(q, s) - 1);
2191 this->set_weight_enumerator(MacWilliamsIdentity<T>(weight_enumerator_dual,
this->n,
this->n -
this->k));
2195 for (size_t s_cand = 2; s_cand < std::numeric_limits<size_t>::max(); ++s_cand) {
2196 const size_t n = Hamming_n(s_cand);
2197 if (n >
this->n)
break;
2198 if (n !=
this->n || Hamming_k(s_cand) !=
this->k)
continue;
2200 std::vector<size_t> seen;
2201 seen.reserve(
this->n);
2203 for (size_t i = 0; i <
this->n && valid; ++i) {
2204 const auto h =
this->HT.get_row(i);
2206 for (size_t j = 0; j < h.get_n(); ++j)
2207 if (!h[j].is_zero()) {
2211 if (inv.is_zero()) {
2215 const size_t key = (inv * h).as_integer();
2216 if (std::ranges::find(seen, key) != seen.end()) {
2220 seen.push_back(key);
2228 throw std::invalid_argument(
"Linear code cannot be converted into Hamming code!");
2247 if (os.iword(details::index) > 0) os <<
BOLD(
"Hamming code")
" with properties: { s = " << s <<
" }";
2253#ifdef CECCO_ERASURE_SUPPORT
2254 if (LinearCode<T>::erasures_present(r))
return dec_BD_EE(r);
2256 this->validate_length(r);
2258 constexpr size_t q = T::get_size();
2259 const auto s = r *
this->HT;
2260 if (s.is_zero())
return r;
2262 for (size_t i = 0; i <
this->n; ++i) {
2263 for (size_t j = 1; j < q; ++j) {
2265 if (s == a *
this->HT.get_row(i)) {
2266 c_est.set_component(i, c_est[i] - a);
2276#ifdef CECCO_ERASURE_SUPPORT
2277 if (LinearCode<T>::erasures_present(r))
return dec_ML_EE(r);
2283#ifdef CECCO_ERASURE_SUPPORT
2311 }
else if (
tau == 2) {
2332 static size_t Hamming_n(size_t s)
noexcept {
2333 constexpr size_t q = T::get_size();
2334 return (sqm<size_t>(q, s) - 1) / (q - 1);
2337 static size_t Hamming_k(size_t s)
noexcept {
return Hamming_n(s) - s; }
2339 static Matrix<T> Hamming_H(size_t s) {
2340 const size_t n = Hamming_n(s);
2341 auto H =
Matrix<T>(n, s);
2344 for (size_t top = 0; top < s; ++top) {
2345 const auto v = IdentityMatrix<T>(s - top - 1).rowspace();
2346 for (size_t j = 0; j < v.size(); ++j) {
2347 H.set_component(n - i - 1, top, T(1));
2348 H.set_submatrix(n - i - 1, top + 1, Matrix(v[v.size() - j - 1]));
2357template <FiniteFieldType T>
2364 constexpr size_t q = T::get_size();
2365 Polynomial<InfInt> weight_enumerator;
2366 weight_enumerator.set_coefficient(0, 1);
2367 weight_enumerator.set_coefficient(sqm<size_t>(q, s - 1), sqm<InfInt>(q, s) - 1);
2368 this->set_weight_enumerator(
std::move(weight_enumerator));
2369 for (size_t i = 0; i <
this->n; ++i) cols_as_integers[i] =
this->G.get_col(i).as_integer();
2373 constexpr size_t q = T::get_size();
2374 for (size_t s_cand = 2; s_cand < std::numeric_limits<size_t>::max(); ++s_cand) {
2375 const size_t n = HammingCode<T>::Hamming_n(s_cand);
2376 if (n >
this->n)
break;
2378 if (
this->k == s_cand &&
this->get_dmin() == sqm<size_t>(q, s_cand - 1)) {
2380 for (size_t i = 0; i <
this->n; ++i) cols_as_integers[i] =
this->G.get_col(i).as_integer();
2385 throw std::invalid_argument(
"Linear code cannot be converted into Simplex code!");
2404 if (os.iword(details::index) > 0) os <<
BOLD(
"Simplex code")
" with properties: { s = " << s <<
" }";
2409#ifdef CECCO_ERASURE_SUPPORT
2410 if (LinearCode<T>::erasures_present(r))
return dec_BD_EE(r);
2412 if constexpr (T::get_size() != 2)
return LinearCode<T>::dec_BD(r);
2415 if (dH(r, c_est) >
this->get_tmax())
2416 throw decoding_failure(
"Simplex code BD decoder failed!");
2422#ifdef CECCO_ERASURE_SUPPORT
2423 if (LinearCode<T>::erasures_present(r))
return dec_ML_EE(r);
2425 if constexpr (T::get_size() != 2)
return LinearCode<T>::dec_ML(r);
2426 this->validate_length(r);
2428 Vector<
double> y(
this->n + 1, 0.0);
2429 y.set_component(0, 0.0);
2430 for (size_t i = 0; i <
this->n; ++i) {
2431 const size_t j = cols_as_integers[i];
2432 y.set_component(j, r[i].is_zero() ? 1.0 : -1.0);
2438 double best = -
std::numeric_limits<
double>::infinity();
2439 for (size_t i = 0; i < y.get_n(); ++i) {
2447 u_est.from_integer(hit,
this->k);
2449 return u_est *
this->G;
2452#ifdef CECCO_ERASURE_SUPPORT
2486 Vector<
double>
y(
this->
n + 1, 0.0);
2512 static void FWHT(Vector<
double>& a) {
2513 const size_t n = a.get_n();
2514 if (!std::has_single_bit(n))
throw std::invalid_argument(
"FWHT requires length 2^m!");
2515 for (size_t len = 1; 2 * len <= n; len *= 2) {
2516 for (size_t i = 0; i < n; i += 2 * len) {
2517 for (size_t j = 0; j < len; ++j) {
2518 const double u = a[i + j];
2519 const double v = a[i + j + len];
2520 a.set_component(i + j, u + v);
2521 a.set_component(i + j + len, u - v);
2528 std::vector<size_t> cols_as_integers;
2531template <FiniteFieldType T>
2537 Polynomial<InfInt> weight_enumerator;
2538 weight_enumerator.set_coefficient(0, 1);
2539 weight_enumerator.set_coefficient(n, T::get_size() - 1);
2540 this->set_weight_enumerator(
std::move(weight_enumerator));
2541 auto p = ZeroPolynomial<T>();
2542 p.set_coefficient(0, -T(1));
2543 p.set_coefficient(n, T(1));
2544 auto q = ZeroPolynomial<T>();
2545 q.set_coefficient(0, -T(1));
2546 q.set_coefficient(1, T(1));
2547 this->set_gamma(p / q);
2551 if (
this->k != 1 ||
this->get_dmin() !=
this->n)
2552 throw std::invalid_argument(
"Linear code cannot be converted into repetition code!");
2578#ifdef CECCO_ERASURE_SUPPORT
2579 if (LinearCode<T>::erasures_present(r))
return dec_BD_EE(r);
2583 constexpr size_t q = T::get_size();
2584 if (q != 2 ||
this->n % 2 == 0) {
2585 if (2 * dH(r, c_est) >
this->get_dmin() - 1)
throw decoding_failure(
"Repetition code BD decoder failed!");
2592#ifdef CECCO_ERASURE_SUPPORT
2593 if (LinearCode<T>::erasures_present(r))
return dec_ML_EE(r);
2595 this->validate_length(r);
2597 constexpr size_t q = T::get_size();
2598 std::array<size_t, q> counters{};
2599 for (size_t i = 0; i <
this->n; ++i) ++counters[r[i].get_label()];
2600 const auto it =
std::max_element(counters.cbegin(), counters.cend());
2601 std::size_t label =
static_cast<
std::size_t>(
std::distance(counters.cbegin(), it));
2603 return Vector<T>(
this->n, T(label));
2606#ifdef CECCO_ERASURE_SUPPORT
2632 if (
q != 2 ||
this->
n % 2 == 0) {
2634 throw decoding_failure(
"Repetition code BD error/erasure decoder failed!");
2663 static Matrix<T> Repetition_G(size_t n) {
return Matrix<T>(1, n, T(1)); }
2666template <FiniteFieldType T>
2670 Polynomial<InfInt> weight_enumerator_rep;
2671 weight_enumerator_rep.set_coefficient(0, 1);
2672 weight_enumerator_rep.set_coefficient(n, T::get_size() - 1);
2673 this->set_weight_enumerator(MacWilliamsIdentity<T>(weight_enumerator_rep, n, 1));
2674 auto q = ZeroPolynomial<T>();
2675 q.set_coefficient(0, -T(1));
2676 q.set_coefficient(1, T(1));
2681 if (
this->k !=
this->n - 1)
2682 throw std::invalid_argument(
"Linear code cannot be converted into single parity check code!");
2683 const auto& HTp =
this->get_HT();
2684 for (size_t i = 0; i <
this->n; ++i)
2685 if (HTp(i, 0).is_zero())
2686 throw std::invalid_argument(
"Linear code cannot be converted into single parity check code!");
2708 if (os.iword(
details::index) > 0) os <<
"Single parity check code";
2713#ifdef CECCO_ERASURE_SUPPORT
2714 if (LinearCode<T>::erasures_present(r))
return dec_BD_EE(r);
2716 this->validate_length(r);
2718 if (!(r *
this->HT)[0].is_zero())
throw decoding_failure(
"Single parity check code BD decoder failed!");
2724#ifdef CECCO_ERASURE_SUPPORT
2725 if (LinearCode<T>::erasures_present(r))
return dec_ML_EE(r);
2727 this->validate_length(r);
2729 const T s = (r *
this->HT)[0];
2730 if (s.is_zero())
return r;
2733 c_est.set_component(0, r[0] - s / (
this->HT)(0, 0));
2737#ifdef CECCO_ERASURE_SUPPORT
2745 if (
tau > 1)
throw decoding_failure(
"Single parity check code BD error/erasure decoder failed!");
2777template <FiniteFieldType T>
2782 if constexpr (T::get_size() == 2) {
2783 this->set_weight_enumerator(Polynomial<InfInt>(
2784 {1, 0, 0, 0, 0, 0, 0, 253, 506, 0, 0, 1288, 1288, 0, 0, 506, 253, 0, 0, 0, 0, 0, 0, 1}));
2785 this->set_gamma(Polynomial<T>({1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1}));
2787 this->set_weight_enumerator(Polynomial<InfInt>({1, 0, 0, 0, 0, 132, 132, 0, 330, 110, 0, 24}));
2788 this->set_gamma(Polynomial<T>({2, 0, 1, 2, 1, 1}));
2794 if (
this->n == Golay_n() &&
this->k == Golay_k()) {
2795 if (std::is_same_v<T, Fp<2>> &&
this->get_dmin() == 7)
2797 else if (std::is_same_v<T, Fp<3>> &&
this->get_dmin() == 5)
2800 throw std::invalid_argument(
"Linear code cannot be converted into Golay code!");
2822 os <<
"Binary Golay code";
2824 os <<
"Ternary Golay code";
2847 gamma =
Polynomial<
T>({1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1});
2858template <FieldType T>
2862 <T>(a.get_n(), k, GRS_G(a, d, k)), a(a), d(d) {
2863 const size_t n =
this->n;
2865 for (size_t i = 0; i < n; ++i) {
2866 if (d[i] == T(0))
throw std::invalid_argument(
"GRS codes must have nonzero column multipliers!");
2869 if constexpr (FiniteFieldType<T>) {
2870 constexpr size_t q = T::get_size();
2872 Polynomial<InfInt> weight_enumerator;
2873 weight_enumerator.set_coefficient(0, 1);
2874 for (size_t i = n - k + 1; i <= n; ++i) {
2876 for (size_t j = 0; j <= i - (n - k + 1); ++j) {
2877 InfInt s = j % 2 ? -1 : 1;
2878 sum += s * bin<
InfInt>(i - 1, j) * sqm<
InfInt>(q, i - j - (n - k + 1));
2880 weight_enumerator.set_coefficient(i, bin<
InfInt>(n, i) * (q - 1) * sum);
2883 this->set_weight_enumerator(
std::move(weight_enumerator));
2885 this->set_dmin(n - k + 1);
2888 catch (
const std::invalid_argument& e) {
2889 throw std::invalid_argument(std::string(
"Cannot construct GRS code: ") + e.what());
2896 G_canonical(other.G_canonical),
2897 HT_canonical(other.HT_canonical) {}
2901 a(
std::move(other.a)),
2902 d(
std::move(other.d)),
2903 G_canonical(
std::move(other.G_canonical)),
2904 HT_canonical(
std::move(other.HT_canonical)) {}
2907 if (
this != &other) {
2911 G_canonical = other.G_canonical;
2912 HT_canonical = other.HT_canonical;
2918 if (
this != &other) {
2920 a =
std::move(other.a);
2921 d =
std::move(other.d);
2922 G_canonical =
std::move(other.G_canonical);
2923 HT_canonical =
std::move(other.HT_canonical);
2935 if (
this->dmin.has_value()) res.set_dmin(*(
this->dmin));
2936 if constexpr (FiniteFieldType<T>)
2937 if (
this->weight_enumerator.has_value()) res.set_weight_enumerator(*(
this->weight_enumerator));
2942 for (size_t i = 0; i <
this->n; ++i) {
2943 if (a[i] == T(0))
return true;
2949 if constexpr (!FiniteFieldType<T>) {
2952 const size_t n =
this->n;
2953 if (n != T::get_size() - 1)
return false;
2954 for (size_t i = 0; i < n; ++i) {
2955 if (a[i] == T(0))
return false;
2962 for (size_t i = 0; i <
this->n; ++i) {
2963 if (d[i] != T(1))
return false;
2976 os <<
BOLD(
"GRS code")
" with properties: { a = " << a <<
", d = " << d;
2978 os <<
" singly-extended";
2984 os <<
" narrow-sense";
2987 os <<
" normalized";
2997#ifdef CECCO_ERASURE_SUPPORT
3011 if (a.get_n() != d.get_n())
3012 throw std::invalid_argument(
"code locators a and column multipliers d must have the same length");
3013 return VandermondeMatrix<T>(a, k) * DiagonalMatrix<T>(d);
3016 Vector<T> dec_WBA_impl(
const Vector<T>& r,
const std::vector<size_t>& X)
const {
3017 this->validate_length(r);
3019 const size_t tau = X.size();
3020 if (tau >
this->get_dmin() - 1)
3021 throw decoding_failure(
"GRS code WBA error/erasure decoder failed (too many erasures)!");
3023 const size_t n =
this->n;
3024 const size_t k =
this->k;
3026 const auto ap = delete_components(a, X);
3027 const auto dp = delete_components(d, X);
3028 const size_t np = n - tau;
3029 const size_t tmaxp = (np - k) / 2;
3030 const auto rp = delete_components(r, X);
3033 for (size_t i = 0; i < np; ++i) rp_norm.set_component(i, rp[i] / dp[i]);
3035 const auto M0 = transpose(VandermondeMatrix<T>(ap, np - tmaxp));
3036 const auto M1 = DiagonalMatrix(rp_norm) * transpose(VandermondeMatrix<T>(ap, np - tmaxp - k + 1));
3037 const auto M = horizontal_join(M0, M1);
3039 const auto B = M.basis_of_kernel();
3043 for (size_t j = 0; j <= np - tmaxp - 1; ++j, ++i) Q0.set_coefficient(j, B(0, i));
3045 for (size_t j = 0; j <= np - tmaxp - k; ++j, ++i) Q1.set_coefficient(j, B(0, i));
3047 const auto temp = poly_long_div(-Q0, Q1);
3048 const auto quotient = temp.first;
3049 const auto remainder = temp.second;
3050 if (!remainder.is_zero() || quotient.degree() >= k)
3051 throw decoding_failure(
"GRS code WBA error/erasure decoder failed (true error beyond BD radius)!");
3053 const auto u_est = pad_back(
Vector<T>(quotient), k);
3054 G_canonical.call_once([
this] {
3055 if (G_canonical.has_value())
return;
3056 G_canonical.emplace(VandermondeMatrix<T>(a,
this->k) * DiagonalMatrix<T>(d));
3058 const auto c_est = u_est * G_canonical.value();
3059 if (dH(r, c_est) > tmaxp)
3060 throw decoding_failure(
"GRS code WBA error/erasure decoder failed (identified error beyond BD radius)!");
3065 Vector<T> dec_BMA_impl(
const Vector<T>& r,
const std::vector<size_t>& X)
const {
3066 this->validate_length(r);
3068 const size_t n =
this->n;
3069 const size_t redundancy = n -
this->k;
3070 const size_t tau = X.size();
3071 if (tau > redundancy)
throw decoding_failure(
"GRS code BMA error/erasure decoder failed (too many erasures)!");
3074 for (size_t i = 0; i < tau; ++i) rp.set_component(X[i], T(0));
3076 HT_canonical.call_once([
this, n, redundancy] {
3077 if (HT_canonical.has_value())
return;
3079 auto dells = VandermondeMatrix<T>(a, n).invert().get_col(n - 1);
3080 for (size_t i = 0; i < n; ++i) dells.set_component(i, dells[i] / d[i]);
3081 const auto D = DiagonalMatrix<T>(dells);
3082 const auto V = VandermondeMatrix<T>(a, redundancy);
3083 HT_canonical.emplace(transpose(V * D));
3085 const auto& HT = HT_canonical.value();
3088 const auto s = rp * HT;
3089 if (s.is_zero() && tau == 0)
return r;
3093 auto Psi = Monomial<T>(0, T(1));
3094 for (size_t i = 0; i < tau; ++i) Psi *=
Polynomial<T>({-a[X[i]], T(1)});
3098 for (size_t i = 0; i < redundancy - tau; ++i) {
3100 for (size_t j = 0; j <= tau; ++j) coeff += Psi[j] * s[i + j];
3101 sxp.set_coefficient(i, coeff);
3105 auto Lambda_e = Monomial<T>(0, T(1));
3107 auto B_ref = Monomial<T>(0, T(1));
3109 T discrepancy_ref(1);
3110 size_t last_update = 0;
3112 for (size_t i = 0; i < redundancy - tau; ++i) {
3114 const size_t j0 = (t > i ? t - i : 0);
3115 for (size_t j = j0; j <= t; ++j) discrepancy += Lambda_e[j] * sxp[i + j - t];
3116 const auto ratio = discrepancy / discrepancy_ref;
3118 if (!discrepancy.is_zero()) {
3119 const auto B = Lambda_e;
3120 const size_t shift = i - last_update + 1;
3122 if (shift + t_ref <= t) {
3123 Lambda_e -= ratio * Monomial<T>(t - shift - t_ref, T(1)) * B_ref;
3125 const auto temp = t;
3126 Lambda_e = Monomial<T>(shift + t_ref - t, T(1)) * Lambda_e - ratio * B_ref;
3130 discrepancy_ref = discrepancy;
3131 last_update = i + 1;
3136 if (2 * t + tau > redundancy)
3137 throw decoding_failure(
"GRS code BMA error/erasure decoder failed (identified error beyond BD radius)!");
3140 auto Lambda = Psi * Lambda_e;
3143 std::vector<size_t> E;
3145 for (size_t i = 0; i < n; ++i)
3146 if (Lambda(a[i]).is_zero()) E.push_back(i);
3148 if (E.size() != tau + t)
3149 throw decoding_failure(
"GRS code BMA error/erasure decoder failed (true error beyond BD radius)!");
3153 for (size_t j = 0; j < tau + t; ++j) {
3155 for (size_t m = j + 1; m <= tau + t; ++m) coeff += Lambda[m] * sx[m - j - 1];
3156 Omega.set_coefficient(j, coeff);
3159 Lambda.differentiate(1);
3162 for (size_t i = 0; i < E.size(); ++i) {
3163 const auto locator = a[E[i]];
3164 c_est.set_component(E[i], c_est[E[i]] - Omega(locator) / (HT(E[i], 0) * Lambda(locator)));
3176template <FiniteFieldType T>
3179 RSCode(
const T& alpha, size_t b, size_t k)
try :
RSCode(RS_a_and_D(alpha, b), k, alpha, b) {
3180 }
catch (
const std::invalid_argument& e) {
3181 throw std::invalid_argument(std::string(
"Cannot construct RS code: ") + e.what());
3195 RSCode<T> res(std::make_pair(
this->get_a(),
this->get_d()),
this->k, alpha, b, std::move(Gp));
3196 if (
this->dmin.has_value()) res.set_dmin(*(
this->dmin));
3197 if (
this->weight_enumerator.has_value()) res.set_weight_enumerator(*(
this->weight_enumerator));
3202 RSCode<T> res(std::make_pair(
this->get_a(),
this->get_d()),
this->k, alpha, b,
3203 this->get_G_in_polynomial_form());
3204 if (
this->dmin.has_value()) res.set_dmin(*(
this->dmin));
3205 if (
this->weight_enumerator.has_value()) res.set_weight_enumerator(*(
this->weight_enumerator));
3206 if (
this->minimal_trellis.has_value()) res.minimal_trellis =
this->minimal_trellis;
3207 if (
this->codewords.has_value()) res.codewords =
this->codewords;
3217 os <<
"RS code: { alpha = " << alpha <<
", b = " << b;
3218 if (
this->is_primitive()) os <<
", primitive";
3219 if (
this->is_narrow_sense()) os <<
", narrow-sense";
3220 if (
this->is_normalized()) os <<
", normalized";
3226 static std::pair<
Vector<T>,
Vector<T>> RS_a_and_D(
const T& alpha, size_t b) {
3227 if (alpha == T(0))
throw std::invalid_argument(
"alpha must not be zero");
3228 const size_t n = alpha.get_multiplicative_order();
3229 const T alpha_1mb = sqm<T>(alpha, n + 1 - b % n);
3231 T a_pow = T(1), d_pow = T(1);
3232 for (size_t i = 0; i < n; ++i) {
3233 a.set_component(i, a_pow);
3234 d.set_component(i, d_pow);
3235 a_pow = a_pow * alpha;
3236 d_pow = d_pow * alpha_1mb;
3238 return {
std::move(a),
std::move(d)};
3242 const size_t n = a.get_n();
3243 const size_t start = b % n;
3244 auto gamma = ZeroPolynomial<T>();
3245 gamma.set_coefficient(0, T(1));
3246 for (size_t j = 0; j < n - k; ++j) {
3247 auto factor = ZeroPolynomial<T>();
3248 factor.set_coefficient(0, -a[(start + j) % n]);
3249 factor.set_coefficient(1, T(1));
3250 gamma = gamma * factor;
3255 RSCode(
std::pair<
Vector<T>,
Vector<T>> params, size_t k,
const T& alpha, size_t b)
3256 :
GRSCode<T>(params.first, params.second, k), alpha(alpha), b(b) {
3257 this->set_gamma(RS_gamma(params.first, b, k));
3261 :
GRSCode<T>(params.first, params.second, k,
std::move(G)), alpha(alpha), b(b) {
3262 this->set_gamma(RS_gamma(params.first, b, k));
3272 if (r < 1)
throw std::invalid_argument(
"Cordaro-Wagner codes must have r > 0!");
3273 if (m != -1 && m != 0 && m != 1)
3274 throw std::invalid_argument(
"Cordaro-Wagner codes must have m either -1, 0, or 1!");
3276 auto weight_enumerator = ZeroPolynomial<
InfInt>();
3277 weight_enumerator.add_to_coefficient(0, 1);
3278 weight_enumerator.add_to_coefficient(2 * r, 1);
3279 weight_enumerator.add_to_coefficient(2 * r + m, 2);
3280 this->set_weight_enumerator(
std::move(weight_enumerator));
3284 if (
this->k != 2)
throw std::invalid_argument(
"Linear code cannot be converted into Cordaro-Wagner code!");
3286 r = std::floor(
this->n / 3.0 + 1.0 / 2.0);
3287 m =
this->n - 3 * r;
3289 const auto c1 =
this->G.get_row(0);
3290 const auto c2 =
this->G.get_row(1);
3291 std::array<size_t, 3> actual = {c1.wH(), c2.wH(), (c1 + c2).wH()};
3292 std::array<size_t, 3> expected = {2 * r,
this->n - r,
this->n - r};
3293 std::ranges::sort(actual);
3294 std::ranges::sort(expected);
3295 if (actual != expected)
3296 throw std::invalid_argument(
"Linear code cannot be converted into Cordaro-Wagner code!");
3305 return CordaroWagnerCode(LinearCode<Fp<2>>::get_equivalent_code_in_standard_form());
3309 int8_t
get_m()
const noexcept {
return m; }
3313 LinearCode<Fp<2>>::get_info(os);
3316 if (os.iword(details::index) > 0)
3317 os <<
BOLD(
"Cordaro-Wagner code")
" with properties: { r = " << r <<
", m = " <<
static_cast<
int>(m)
3322#ifdef CECCO_ERASURE_SUPPORT
3323 if (LinearCode<Fp<2>>::erasures_present(r))
return dec_BD_EE(r);
3325 this->validate_length(r);
3327 const size_t t =
this->get_tmax();
3328 for (
auto it =
this->cbegin(); it !=
this->cend(); ++it) {
3329 if (dH(*it, r) <= t)
return *it;
3331 throw decoding_failure(
"Cordaro-Wagner code BD decoder failed!");
3335#ifdef CECCO_ERASURE_SUPPORT
3336 if (LinearCode<Fp<2>>::erasures_present(r))
return dec_ML_EE(r);
3338 this->validate_length(r);
3341 size_t best_t = std::numeric_limits<size_t>::max();
3343 for (
auto it =
this->cbegin(); it !=
this->cend(); ++it) {
3344 const size_t t = dH(*it, r);
3353#ifdef CECCO_ERASURE_SUPPORT
3375 throw decoding_failure(
"Cordaro-Wagner code BD error/erasure decoder failed!");
3408 static Matrix<Fp<2>> CordaroWagner_G(size_t r, int8_t m) {
3409 const size_t n = 3 * r + m;
3410 Matrix<Fp<2>> G(2, n);
3412 const Matrix<Fp<2>> type1_column(2, 1, {Fp<2>(1), Fp<2>(0)});
3413 for (size_t s = 0; s < r; ++s) G.set_submatrix(0, s, type1_column);
3415 const Matrix<Fp<2>> type2_column(2, 1, {Fp<2>(0), Fp<2>(1)});
3416 for (size_t s = r; s < 2 * r + m; ++s) G.set_submatrix(0, s, type2_column);
3418 const Matrix<Fp<2>> type3_column(2, 1, {Fp<2>(1), Fp<2>(1)});
3419 for (size_t s = 2 * r + m; s < 3 * r + m; ++s) G.set_submatrix(0, s, type3_column);
3431template <FieldType T>
3433 const size_t n = G_U.get_n();
3434 if (G_V.get_n() != n)
throw std::invalid_argument(
"Codes must have same length for LDC construction!");
3436 const size_t kU = G_U.get_m();
3437 const size_t kV = G_V.get_m();
3439 Matrix<T> G(kU + kV, 2 * n);
3440 G.set_submatrix(0, 0, G_U);
3441 G.set_submatrix(0, n, G_U);
3442 G.set_submatrix(kU, n, G_V);
3448template <
class BU,
class BV>
3456 LDCCode(
const BU& U,
const BV& V)
try : LinearCode
3457 <T>(2 * U.get_n(), U.get_k() + V.get_k(), details::LDC_G(U.get_G(), V.get_G())), U(U), V(V) {}
3458 catch (
const std::invalid_argument& e) {
3459 throw std::invalid_argument(std::string(
"Trying to perform invalid length-doubling construction: ") + e.what());
3471 if constexpr (std::is_same_v<T, Fp<2>>)
this->set_dmin(std::min({2 * U.get_dmin(), V.get_dmin()}));
3472 return this->LinearCode<T>::get_dmin();
3477 LinearCode<T>::get_info(os);
3482 os <<
BOLD(
"LDC code")
" with properties: { ";
3484 U.LinearCode<T>::get_info(os);
3486 V.LinearCode<T>::get_info(os);
3493#ifdef CECCO_ERASURE_SUPPORT
3494 if (LinearCode<T>::erasures_present(r))
return dec_recursive_EE(r);
3496 this->validate_length(r);
3498 auto rl = r.get_subvector(0, U.get_n());
3499 auto rr = r.get_subvector(U.get_n(), U.get_n());
3502 const Vector<T> cl_hat_1 = dec_wrapper(U, rl);
3505 const Vector<T> cr_hat = dec_wrapper(V, rr - rl);
3507 const Vector<T> cl_hat_2 = dec_wrapper(U, rr - cr_hat);
3509 const auto c_est_1 = concatenate(cl_hat_1, cl_hat_1 + cr_hat);
3510 const auto c_est_2 = concatenate(cl_hat_2, cl_hat_2 + cr_hat);
3511 if (dH(r, c_est_1) < dH(r, c_est_2))
3517#ifdef CECCO_ERASURE_SUPPORT
3563 Vector<T> dec_wrapper(
const LinearCode<T>& C,
const Vector<T>& r)
const {
return C.dec_ML(r); }
3565 Vector<T> dec_wrapper(
const LDCCode& C,
const Vector<T>& r)
const {
return C.dec_recursive(r); }
3567#ifdef CECCO_ERASURE_SUPPORT
3579 <T>(sqm(2, m), RM_k(r, m), RM_G(r, m)), r(r), m(m) {
this->set_dmin(sqm(2, m - r)); }
3580 catch (
const std::invalid_argument& e) {
3581 throw std::invalid_argument(std::string(
"Trying to construct invalid RM code: ") + e.what());
3594 LinearCode<T>::get_info(os);
3598 os <<
BOLD(
"RM code")
" with properties: { r = " << r <<
", m = " << m <<
" }";
3606 this->validate_length(r);
3607 return dec_wrapper(
this->r, m, r);
3610#ifdef CECCO_ERASURE_SUPPORT
3630 static size_t RM_k(size_t r, size_t m) {
3632 for (size_t i = 0; i <= r; ++i) k += bin<size_t>(m, i);
3636 static Matrix<T> RM_G(size_t r, size_t m) {
3637 if (r > m)
throw std::invalid_argument(
"RM codes require 0 <= r <= m");
3638 const size_t n = sqm(2, m);
3640 if (r == 0)
return Matrix<T>(1, n, T(1));
3641 if (r == m)
return IdentityMatrix<
T>(n);
3643 const auto GU = RM_G(r, m - 1);
3644 const auto GV = RM_G(r - 1, m - 1);
3645 return details::LDC_G(GU, GV);
3648 static Vector<T> dec_wrapper(size_t r, size_t m,
const Vector<T>& v) {
3649 const size_t n = sqm(2, m);
3652 if (r == m)
return v;
3656 constexpr size_t q = T::get_size();
3657 std::array<size_t, q> counters{};
3658 for (size_t i = 0; i < n; ++i) ++counters[v[i].get_label()];
3659 const auto it =
std::max_element(counters.cbegin(), counters.cend());
3660 return Vector<T>(n, T(
static_cast<size_t>(std::distance(counters.cbegin(), it))));
3663 const size_t np = n / 2;
3664 auto vl = v.get_subvector(0, np);
3665 auto vr = v.get_subvector(np, np);
3668 const Vector<T> cl_hat_1 = dec_wrapper(r, m - 1, vl);
3671 const Vector<T> cr_hat = dec_wrapper(r - 1, m - 1, vr - vl);
3673 const Vector<T> cl_hat_2 = dec_wrapper(r, m - 1, vr - cr_hat);
3675 if (dH(vl, cl_hat_1) + dH(vr, cl_hat_1 + cr_hat) < dH(vl, cl_hat_2) + dH(vr, cl_hat_2 + cr_hat))
3676 return concatenate(cl_hat_1, cl_hat_1 + cr_hat);
3678 return concatenate(cl_hat_2, cl_hat_2 + cr_hat);
3681#ifdef CECCO_ERASURE_SUPPORT
3743 std::
string(
"Trying to construct a subfield subcode from a super code that is not over a superfield: ") +
3755#ifdef CECCO_ERASURE_SUPPORT
3762#ifdef CECCO_ERASURE_SUPPORT
3768#ifdef CECCO_ERASURE_SUPPORT
3785 os <<
BOLD(
"Subfield-subcode")
" with properties: {" <<
std::
endl;
3891 os <<
BOLD(
"Alternant code")
" with properties: { delta = " <<
get_delta();
3946template <FiniteFieldType SUPER>
3953 }
catch (
const std::invalid_argument& e) {
3954 throw std::invalid_argument(std::string(
"Cannot construct Goppa code: ") + e.what());
3960 squarefree(GCD(
this->g, derivative(
this->g, 1)).degree() == 0) {
3961 }
catch (
const std::invalid_argument& e) {
3962 throw std::invalid_argument(std::string(
"Cannot construct Goppa code: ") + e.what());
3974 if constexpr (std::is_same_v<SUB, Fp<2>>)
3975 if (squarefree)
return 2 * g.degree() + 1;
3976 return Base::get_delta();
3985 os <<
BOLD(
"Goppa code")
" with properties: { g = " << g;
3986 if (squarefree) os <<
", square-free";
3999 const auto&
a =
this->
get_a();
4002 if (
t == 0)
throw std::
invalid_argument(
"Patterson decoder requires a nonconstant Goppa polynomial");
4019 throw decoding_failure(
"Patterson decoder failed (syndrome not invertible modulo g)");
4020 const auto h = (((
SUPER(1) /
d[0]) *
u) +
x) %
g;
4061 mutable details::OnceCache<std::vector<Polynomial<SUPER>>> Patterson_inv_cache;
4063 void calculate_Patterson_inv_cache()
const {
4064 Patterson_inv_cache.call_once([
this] {
4065 if (Patterson_inv_cache.has_value())
return;
4066 const size_t n =
this->get_n();
4067 const auto& a =
this->get_a();
4068 std::vector<Polynomial<SUPER>> inv(n);
4069 for (size_t i = 0; i < n; ++i) {
4070 Polynomial<SUPER> u;
4071 const auto d = GCD(Polynomial<SUPER>({a[i], SUPER(1)}), g, &u);
4072 if (d.is_zero() || d.degree() != 0)
4073 throw std::invalid_argument(
"Goppa locator a[" + std::to_string(i) +
"] is a root of g");
4074 inv[i] = ((SUPER(1) / d[0]) * u) % g;
4076 Patterson_inv_cache.emplace(std::move(inv));
4082 const size_t n = a.get_n();
4085 for (size_t i = 0; i < n; ++i) {
4086 const SUPER ha = h(a[i]);
4087 if (ha.is_zero())
throw std::invalid_argument(
"Goppa polynomial vanishes at a code locator");
4089 SUPER denominator(1);
4090 for (size_t j = 0; j < n; ++j) {
4091 if (j == i)
continue;
4092 const SUPER diff = a[i] - a[j];
4093 denominator *= diff;
4095 res.set_component(i, ha / denominator);
4101 static Polynomial<SUPER> Goppa_polynomial(size_t delta) {
4102 if (delta < 2)
throw std::invalid_argument(
"delta must be at least 2 for a nonconstant Goppa polynomial");
4103 return find_irreducible<SUPER>(delta - 1);
4115 if (v == Extended_v(
this->BaseCode.get_G())) parity =
true;
4117 catch (
const std::invalid_argument& e) {
4118 throw std::invalid_argument(std::string(
"Trying to extend a code with invalid extension parameters: ") +
4126 catch (
const std::invalid_argument& e) {
4127 throw std::invalid_argument(std::string(
"Trying to extend a code with invalid extension parameters: ") +
4148 if constexpr (!FiniteFieldType<T>) {
4149 throw std::logic_error(
"Cannot calculate weight enumerator of code over infinite field!");
4154 if constexpr (std::is_same_v<T, Fp<2>>) {
4156 auto weight_enumerator = BaseCode.get_weight_enumerator();
4157 for (size_t w = 0; w <= weight_enumerator.degree(); ++w) {
4158 if (w % 2 && weight_enumerator[w] != 0) {
4159 weight_enumerator.add_to_coefficient(w + 1, weight_enumerator[w]);
4160 weight_enumerator.set_coefficient(w, 0);
4163 this->set_weight_enumerator(
std::move(weight_enumerator));
4166 return LinearCode<T>::get_weight_enumerator();
4172 LinearCode<T>::get_info(os);
4177 os <<
BOLD(
"Extended code")
" with properties: { i = " << i;
4178 os <<
", v = " << v;
4179 if (parity) os <<
", even parity";
4181 BaseCode.LinearCode<T>::get_info(os);
4182 os <<
" " << showspecial << BaseCode;
4189#ifdef CECCO_ERASURE_SUPPORT
4190 if (LinearCode<T>::erasures_present(r))
return dec_BD_EE(r);
4192 return LinearCode<T>::dec_BD(r);
4196#ifdef CECCO_ERASURE_SUPPORT
4197 if (LinearCode<T>::erasures_present(r))
return dec_ML_EE(r);
4199 return LinearCode<T>::dec_ML(r);
4202#ifdef CECCO_ERASURE_SUPPORT
4254 static Matrix<T> Extended_G(
const Matrix<T>& Gp, size_t i,
const Vector<T>& v) {
4255 const size_t n = Gp.get_n();
4256 const size_t k = Gp.get_m();
4258 if (i > n)
throw std::invalid_argument(
"Extension index invalid");
4259 if (v.get_n() != k)
throw std::invalid_argument(std::string(
"Length of v must be ") +
std::to_string(k));
4261 Matrix<T> G(k, n + 1);
4262 for (size_t j = 0; j < i; ++j) G.set_submatrix(0, j, Gp.get_submatrix(0, j, k, 1));
4263 G.set_submatrix(0, i, transpose(Matrix<T>(v)));
4264 for (size_t j = i; j < n; ++j) G.set_submatrix(0, j + 1, Gp.get_submatrix(0, j, k, 1));
4268 static Vector<T> Extended_v(
const Matrix<T>& Gp) {
4269 const size_t n = Gp.get_n();
4270 const size_t k = Gp.get_m();
4273 for (size_t j = 0; j < n; ++j) v += Gp.get_col(j);
4289 <T>(BaseCode.get_n(), BaseCode.get_k() + 1, Augmented_G(BaseCode.get_G(), j, w)), BaseCode(BaseCode), j(j),
4291 catch (
const std::invalid_argument& e) {
4292 throw std::invalid_argument(std::string(
"Trying to augment a code by an invalid w: ") + e.what());
4296 <T>(BaseCode.get_n(), BaseCode.get_k() + 1, Augmented_G(BaseCode.get_G(), j, w)), BaseCode(std::move(BaseCode)),
4298 catch (
const std::invalid_argument& e) {
4299 throw std::invalid_argument(std::string(
"Trying to augment a code by an invalid w: ") + e.what());
4313 LinearCode<T>::get_info(os);
4318 os <<
BOLD(
"Augmented code")
" with properties: { w = " << w;
4320 BaseCode.LinearCode<T>::get_info(os);
4321 os <<
" " << showspecial << BaseCode;
4328#ifdef CECCO_ERASURE_SUPPORT
4329 if (LinearCode<T>::erasures_present(r))
return dec_BD_EE(r);
4331 if constexpr (!FiniteFieldType<T>) {
4332 return LinearCode<T>::dec_BD(r);
4334 this->validate_length(r);
4336 const size_t t =
this->get_tmax();
4338 for (size_t i = 0; i < T::get_size(); ++i) {
4339 const T alpha = T(i);
4342 Vector<T> cp_est = BaseCode.dec_BD(r - alpha * w);
4343 Vector<T> c_est = cp_est + alpha * w;
4344 if (dH(r, c_est) <= t)
return c_est;
4345 }
catch (
const decoding_failure&) {
4350 throw decoding_failure(
"Augmented code BD decoder failed!");
4355#ifdef CECCO_ERASURE_SUPPORT
4356 if (LinearCode<T>::erasures_present(r))
return dec_ML_EE(r);
4358 if constexpr (!FiniteFieldType<T>) {
4359 return LinearCode<T>::dec_ML(r);
4361 this->validate_length(r);
4363 const size_t tmax =
this->get_tmax();
4365 Vector<T> best = BaseCode.dec_ML(r);
4366 size_t best_t = dH(r, best);
4368 if (best_t <= tmax)
return best;
4370 for (size_t i = 1; i < T::get_size(); ++i) {
4371 const T alpha = T(i);
4373 Vector<T> cp_est = BaseCode.dec_ML(r - alpha * w);
4374 Vector<T> c_est = cp_est + alpha * w;
4376 const size_t t = dH(r, c_est);
4378 if (t <= tmax)
return c_est;
4382 best = std::move(c_est);
4390#ifdef CECCO_ERASURE_SUPPORT
4452 if (
t == 0)
return c_est;
4466 static Matrix<T> Augmented_G(
const Matrix<T>& Gp, size_t j,
const Vector<T>& w) {
4467 const size_t n = Gp.get_n();
4468 const size_t k = Gp.get_m();
4470 if (w.get_n() != n)
throw std::invalid_argument(std::string(
"Length of w must be ") +
std::to_string(n));
4472 if (Gp.get_m() == 1 && Gp.rank() == 0)
return Matrix<T>(w);
4475 const auto G = vertical_join(Matrix(w), Gp);
4477 }
else if (j == k) {
4478 const auto G = vertical_join(Gp, Matrix(w));
4482 vertical_join(vertical_join(Gp.get_submatrix(0, 0, j, n), Matrix(w)), Gp.get_submatrix(j, 0, k - j, n));
4492template <FieldType T>
4494 return C.get_dual();
4499 std::vector<
bool> seen(n,
false);
4500 for (
auto it = v.begin(); it != v.end(); ++it) {
4501 if (*it >= n || seen[*it])
return false;
4515auto extend(B&& base, size_t i,
const Vector<field_t<B>>& v) {
4516 using D = base_t<B>;
4517 using T = field_t<B>;
4518 return ExtendedCode<T, D>(std::forward<B>(base), i, v);
4523 using D = base_t<B>;
4524 using T = field_t<B>;
4525 return ExtendedCode<T, D>(std::forward<B>(base));
4529template <FieldType T,
class B>
4531 return C.get_BaseCode();
4535auto augment(B&& base, size_t j,
const Vector<field_t<B>>& w) {
4536 using D = base_t<B>;
4537 using T = field_t<B>;
4538 return AugmentedCode<T, D>(std::forward<B>(base), j, w);
4542template <FieldType T,
class B>
4544 return C.get_BaseCode();
4548auto lengthen(B&& base, size_t j,
const Vector<field_t<B>>& w, size_t i,
const Vector<field_t<B>>& v) {
4549 using D = base_t<B>;
4550 using T = field_t<B>;
4551 return ExtendedCode<T, AugmentedCode<T, D>>(AugmentedCode<T, D>(std::forward<B>(base), j, w), i, v);
4555auto lengthen(B&& base, size_t j,
const Vector<field_t<B>>& w) {
4556 using D = base_t<B>;
4557 using T = field_t<B>;
4558 return ExtendedCode<T, AugmentedCode<T, D>>(AugmentedCode<T, D>(std::forward<B>(base), j, w));
4562template <FieldType T,
class D>
4564 return C.get_BaseCode().get_BaseCode();
4567template <FieldType T>
4569 if (!details::validate(v, C.get_n()))
throw std::invalid_argument(
"Invalid pattern for puncturing linear code!");
4572 G.delete_columns(v);
4575 G = G.get_submatrix(0, 0, rank, G.get_n());
4576 return LinearCode<T>(C.get_n() - v.size(), rank,
std::move(G));
4579template <FieldType T>
4581 if (v.empty())
return C;
4582 throw std::invalid_argument(
"Cannot puncture an empty code!");
4585template <FieldType T>
4587 if (!details::validate(v, C.get_n()))
throw std::invalid_argument(
"Invalid pattern for puncturing zero code!");
4588 return ZeroCode<T>(C.get_n() - v.size());
4591template <FieldType T>
4593 if (!details::validate(v, C.get_n()))
throw std::invalid_argument(
"Invalid pattern for puncturing universe code!");
4597template <FieldType T>
4599 if (!details::validate(v, C.get_n()))
4600 throw std::invalid_argument(
"Invalid pattern for puncturing repetition code!");
4700#ifdef CECCO_ERASURE_SUPPORT
4710template <FieldType T>
4717 dec = [
this](
const Vector<T>& r) {
return this->C.dec_BD(r); };
4720 dec = [
this](
const Vector<T>& r) {
return this->C.dec_boosted_BD(r); };
4723 dec = [
this](
const Vector<T>& r) {
return this->C.dec_ML(r); };
4726 dec = [
this](
const Vector<T>& r) {
return this->C.dec_Viterbi(r); };
4729 dec = [
this](
const Vector<T>& r) {
return this->C.dec_recursive(r); };
4732 dec = [
this](
const Vector<T>& r) {
return this->C.dec_Meggitt(r); };
4735 dec = [
this](
const Vector<T>& r) {
return this->C.dec_WBA(r); };
4738 dec = [
this](
const Vector<T>& r) {
return this->C.dec_BMA(r); };
4744#ifdef CECCO_ERASURE_SUPPORT
4745 case method_t::WBA_EE:
4746 dec = [
this](
const Vector<T>& r) {
return this->C.dec_WBA_EE(r); };
4748 case method_t::BMA_EE:
4749 dec = [
this](
const Vector<T>& r) {
return this->C.dec_BMA_EE(r); };
4751 case method_t::BD_EE:
4752 dec = [
this](
const Vector<T>& r) {
return this->C.dec_BD_EE(r); };
4754 case method_t::ML_EE:
4755 dec = [
this](
const Vector<T>& r) {
return this->C.dec_ML_EE(r); };
4757 case method_t::Viterbi_EE:
4758 dec = [
this](
const Vector<T>& r) {
return this->C.dec_Viterbi_EE(r); };
4760 case method_t::recursive_EE:
4761 dec = [
this](
const Vector<T>& r) {
return this->C.dec_recursive_EE(r); };
4770 if (!dec)
throw std::logic_error(
"Selected decoding method does not support hard-decision input!");
4777 const auto llrs = C.dec_BCJR(in);
4778 Vector<T> c_est(llrs.get_n());
4779 for (size_t i = 0; i < llrs.get_n(); ++i)
4780 if (llrs[i] < 0.0) c_est.set_component(i, T(1));
4783 return C.dec_ML_soft(in, cache_limit);
4793template <FiniteFieldType T>
const Vector< T > & get_w() const noexcept
AugmentedCode(B &&BaseCode, size_t j, const Vector< T > &w)
AugmentedCode(AugmentedCode &&)=default
AugmentedCode & operator=(AugmentedCode &&)=default
AugmentedCode(const AugmentedCode &)=default
const B & get_BaseCode() const noexcept
virtual void get_info(std::ostream &os) const override
size_t get_j() const noexcept
AugmentedCode(const B &BaseCode, size_t j, const Vector< T > &w)
Vector< T > dec_BD(const Vector< T > &r) const override
AugmentedCode & operator=(const AugmentedCode &)=default
Vector< T > dec_ML(const Vector< T > &r) const override
virtual Vector< T > dec_WBA(const Vector< T > &r) const
virtual Vector< T > encinv(const Vector< T > &c) const
virtual Vector< T > dec_boosted_BD(const Vector< T > &r) const
Code & operator=(const Code &other)
virtual Vector< T > dec_ML_soft(const Vector< double > &llrs, size_t cache_size) const
virtual Vector< T > dec_Viterbi_soft(const Vector< double > &llrs, const std::string &filename="") const
virtual Vector< T > dec_BMA(const Vector< T > &r) const
virtual Vector< T > dec_Meggitt(const Vector< T > &r) const
virtual Vector< double > dec_BCJR(const Vector< double > &llrs, const std::string &filename="") const
virtual void get_info(std::ostream &os) const
virtual Vector< T > dec_BD(const Vector< T > &r) const
Code & operator=(Code &&)=default
virtual Vector< T > dec_recursive(const Vector< T > &r) const
virtual Vector< T > dec_burst(const Vector< T > &r) const
virtual Vector< T > dec_ML(const Vector< T > &r) const
virtual Vector< T > dec_Viterbi(const Vector< T > &r, const std::string &filename="") const
size_t get_n() const noexcept
virtual Vector< T > enc(const Vector< T > &u) const
std::forward_iterator_tag iterator_category
const Vector< T > * pointer
std::ptrdiff_t difference_type
friend bool operator==(const CodewordIterator &a, const CodewordIterator &b)
CodewordIterator & operator++()
const Vector< T > & reference
CodewordIterator(const LinearCode< T > &C, InfInt s)
friend bool operator!=(const CodewordIterator &a, const CodewordIterator &b)
const Vector< T > & operator*() const noexcept
CordaroWagnerCode(const LinearCode< Fp< 2 > > &C)
CordaroWagnerCode(const CordaroWagnerCode &)=default
CordaroWagnerCode & operator=(const CordaroWagnerCode &)=default
size_t get_r() const noexcept
virtual void get_info(std::ostream &os) const override
int8_t get_m() const noexcept
Vector< Fp< 2 > > dec_ML(const Vector< Fp< 2 > > &r) const override
CordaroWagnerCode & operator=(CordaroWagnerCode &&)=default
CordaroWagnerCode(size_t r, int8_t m)
CordaroWagnerCode get_equivalent_code_in_standard_form() const
Vector< Fp< 2 > > dec_BD(const Vector< Fp< 2 > > &r) const override
CordaroWagnerCode(CordaroWagnerCode &&)=default
Vector< T > operator()(const Vector< T > &in) const
Vector< T > operator()(const Vector< double > &in) const
Dec(const Code< T > &C, method_t method=method_t::ML, size_t cache_limit=10000)
EmptyCode(const EmptyCode &)=default
EmptyCode & operator=(EmptyCode &&)=default
void get_info(std::ostream &os) const override
EmptyCode & operator=(const EmptyCode &)=default
EmptyCode(EmptyCode &&)=default
Encinv(const Code< T > &C)
Vector< T > operator()(const Vector< T > &in) const
const Polynomial< InfInt > & get_weight_enumerator() const override
ExtendedCode & operator=(ExtendedCode &&)=default
ExtendedCode(B &&BaseCode, size_t i, const Vector< T > &v)
Vector< T > dec_BD_EE(const Vector< T > &r) const override
const B & get_BaseCode() const noexcept
ExtendedCode(const B &BaseCode)
ExtendedCode(const ExtendedCode &)=default
virtual Vector< T > dec_BD(const Vector< T > &r) const override
size_t get_i() const noexcept
ExtendedCode(ExtendedCode &&)=default
ExtendedCode & operator=(const ExtendedCode &)=default
ExtendedCode(const B &BaseCode, size_t i, const Vector< T > &v)
virtual Vector< T > dec_ML(const Vector< T > &r) const override
virtual void get_info(std::ostream &os) const override
GRSCode< T > get_equivalent_code_in_standard_form() const
const Vector< T > & get_a() const noexcept
GRSCode(const Vector< T > &a, const Vector< T > &d, size_t k, Matrix< T > G)
bool is_singly_extended() const
GRSCode(const Vector< T > &a, const Vector< T > &d, size_t k)
bool is_narrow_sense() const
Vector< T > dec_BD(const Vector< T > &r) const override
const Vector< T > & get_d() const noexcept
Vector< T > dec_WBA(const Vector< T > &r) const override
GRSCode & operator=(const GRSCode &other)
virtual void get_info(std::ostream &os) const override
bool is_normalized() const
GRSCode & operator=(GRSCode &&other)
Vector< T > dec_BMA(const Vector< T > &r) const override
GRSCode(const GRSCode &other)
bool is_primitive() const
GolayCode & operator=(GolayCode &&)=default
GolayCode(const GolayCode &)=default
GolayCode & operator=(const GolayCode &)=default
GolayCode(const LinearCode< T > &C)
GolayCode(GolayCode &&)=default
GoppaCode(const Vector< SUPER > &a, Polynomial< SUPER > g)
GoppaCode(const GoppaCode &)=default
size_t get_delta() const noexcept override
Vector< SUB > dec_Patterson(const Vector< SUB > &r) const
GoppaCode(GoppaCode &&)=default
GoppaCode & operator=(const GoppaCode &)=default
bool is_squarefree() const noexcept
GoppaCode & operator=(GoppaCode &&)=default
const Polynomial< SUPER > & get_g() const noexcept
void get_info(std::ostream &os) const override
GoppaCode(const Vector< SUPER > &a, size_t delta)
void get_info(std::ostream &os) const override
HammingCode(HammingCode &&)=default
HammingCode(const HammingCode &)=default
Vector< T > dec_BD(const Vector< T > &r) const override
HammingCode< T > get_equivalent_code_in_standard_form() const
HammingCode & operator=(const HammingCode &)=default
HammingCode & operator=(HammingCode &&)=default
Vector< T > dec_ML(const Vector< T > &r) const override
HammingCode(const LinearCode< T > &C)
size_t get_s() const noexcept
SimplexCode< T > get_dual() const noexcept
LDCCode & operator=(LDCCode &&)=default
const BU & get_U() const noexcept
LDCCode(LDCCode &&)=default
virtual size_t get_dmin() const override
virtual void get_info(std::ostream &os) const override
const BV & get_V() const noexcept
LDCCode(const BU &U, const BV &V)
LDCCode & operator=(const LDCCode &)=default
Vector< T > dec_recursive(const Vector< T > &r) const override
LDCCode(const LDCCode &)=default
double get_R() const noexcept
LinearCode(const LinearCode &other)
LinearCode(size_t n, size_t k, const Matrix< T > &X)
details::OnceCache< bool > polynomial
LinearCode(size_t k, Polynomial< T > gamma)
std::vector< size_t > infoset
size_t get_k() const noexcept
LinearCode & operator=(const LinearCode &other)
details::OnceCache< Polynomial< InfInt > > weight_enumerator
details::OnceCache< std::vector< bool > > tainted_burst
LinearCode(LinearCode &&other)
details::OnceCache< Trellis< T > > minimal_trellis
details::OnceCache< std::vector< bool > > tainted
details::OnceCache< std::vector< Vector< T > > > standard_array
details::OnceCache< size_t > dmin
details::OnceCache< std::vector< Vector< T > > > codewords
LinearCode & operator=(LinearCode &&other)
details::OnceCache< Polynomial< T > > gamma
Dense m × n matrix over a CECCO::ComponentType.
Univariate polynomial p(x) = a₀ + a₁x + … + aₙxⁿ over a CECCO::ComponentType.
void get_info(std::ostream &os) const override
RMCode & operator=(const RMCode &)=default
RMCode(RMCode &&)=default
size_t get_r() const noexcept
size_t get_m() const noexcept
RMCode & operator=(RMCode &&)=default
RMCode(const RMCode &)=default
RMCode(size_t r, size_t m)
Vector< T > dec_recursive(const Vector< T > &r) const override
RSCode(const T &alpha, size_t b, size_t k)
RSCode< T > get_identical_code_in_polynomial_form() const
RSCode & operator=(RSCode &&)=default
T get_alpha() const noexcept
void get_info(std::ostream &os) const override
RSCode(RSCode &&)=default
RSCode< T > get_equivalent_code_in_standard_form() const
RSCode(const RSCode &)=default
size_t get_b() const noexcept
RSCode & operator=(const RSCode &)=default
RepetitionCode< T > get_equivalent_code_in_standard_form() const
RepetitionCode< T > get_identical_code_in_polynomial_form() const
RepetitionCode & operator=(RepetitionCode &&)=default
RepetitionCode & operator=(const RepetitionCode &)=default
RepetitionCode(const RepetitionCode &)=default
Vector< T > encinv(const Vector< T > &c) const override
Vector< T > dec_ML(const Vector< T > &r) const override
SingleParityCheckCode< T > get_dual() const noexcept
void get_info(std::ostream &os) const override
RepetitionCode(RepetitionCode &&)=default
Vector< T > enc(const Vector< T > &u) const override
RepetitionCode(const LinearCode< T > &C)
Vector< T > dec_BD(const Vector< T > &r) const override
Vector< T > dec_ML(const Vector< T > &r) const override
SimplexCode(const LinearCode< T > &C)
size_t get_s() const noexcept
SimplexCode(SimplexCode &&)=default
SimplexCode(const SimplexCode &)=default
SimplexCode & operator=(const SimplexCode &)=default
SimplexCode< T > get_equivalent_code_in_standard_form() const
void get_info(std::ostream &os) const override
HammingCode< T > get_dual() const noexcept
Vector< T > dec_BD(const Vector< T > &r) const override
SimplexCode & operator=(SimplexCode &&)=default
SingleParityCheckCode(SingleParityCheckCode &&)=default
SingleParityCheckCode(const SingleParityCheckCode &)=default
SingleParityCheckCode & operator=(const SingleParityCheckCode &)=default
SingleParityCheckCode & operator=(SingleParityCheckCode &&)=default
void get_info(std::ostream &os) const override
Vector< T > dec_BD(const Vector< T > &r) const override
Vector< T > dec_ML(const Vector< T > &r) const override
SingleParityCheckCode(const LinearCode< T > &C)
SingleParityCheckCode< T > get_identical_code_in_polynomial_form() const
SingleParityCheckCode(size_t n)
RepetitionCode< T > get_dual() const noexcept
SingleParityCheckCode< T > get_equivalent_code_in_standard_form() const
UniverseCode< T > get_equivalent_code_in_standard_form() const
Vector< T > dec_burst(const Vector< T > &r) const override
UniverseCode & operator=(const UniverseCode &)=default
UniverseCode(const UniverseCode &)=default
Vector< T > encinv(const Vector< T > &c) const override
Vector< T > dec_ML(const Vector< T > &r) const override
void get_info(std::ostream &os) const override
UniverseCode(const LinearCode< T > &C)
UniverseCode & operator=(UniverseCode &&)=default
Vector< T > enc(const Vector< T > &u) const override
UniverseCode(UniverseCode &&)=default
Vector< T > dec_BD(const Vector< T > &r) const override
ZeroCode< T > get_dual() const noexcept
Vector v = (v₀, v₁, …, vₙ₋₁) over a CECCO::ComponentType.
ZeroCode(const LinearCode< T > &C)
ZeroCode & operator=(const ZeroCode &)=default
ZeroCode(ZeroCode &&)=default
void get_info(std::ostream &os) const override
ZeroCode & operator=(ZeroCode &&)=default
ZeroCode< T > get_equivalent_code_in_standard_form() const
ZeroCode(const ZeroCode &)=default
const char * what() const noexcept override
decoding_failure(const std::string &message)
Thread-safe single-value cache.
Contains implementation details not to be exposed to the user. Functions and classes here may change ...
Matrix< T > LDC_G(const Matrix< T > &G_U, const Matrix< T > &G_V)
bool validate(const std::vector< size_t > &v, std::size_t n)
Provides a framework for error correcting codes.
std::ostream & showall(std::ostream &os)
std::mt19937 & gen()
Current thread's random number generator.
auto unlengthen(const ExtendedCode< T, AugmentedCode< T, D > > &C)
auto puncture(const EmptyCode< T > &C, const std::vector< size_t > &v)
std::ostream & showspecial(std::ostream &os)
auto lengthen(B &&base, size_t j, const Vector< field_t< B > > &w)
SubfieldSubcode(const B &) -> SubfieldSubcode< B >
std::ostream & showmost(std::ostream &os)
std::ostream & showbasic(std::ostream &os)
auto puncture(const ZeroCode< T > &C, const std::vector< size_t > &v)
auto augment(B &&base, size_t j, const Vector< field_t< B > > &w)
Polynomial< InfInt > MacWilliamsIdentity(const Polynomial< InfInt > &A, size_t n, size_t k)
LinearCode< T > puncture(const LinearCode< T > &C, const std::vector< size_t > &v)
SubfieldSubcode(B &&) -> SubfieldSubcode< B >
auto extend(B &&base, size_t i, const Vector< field_t< B > > &v)
auto puncture(const UniverseCode< T > &C, const std::vector< size_t > &v)
B unextend(const ExtendedCode< T, B > &C)
B unaugment(const AugmentedCode< T, B > &C)
auto lengthen(B &&base, size_t j, const Vector< field_t< B > > &w, size_t i, const Vector< field_t< B > > &v)
auto puncture(const RepetitionCode< T > &C, const std::vector< size_t > &v)
Trellis with field-labelled edges between consecutive layers.