C(++)ECCO
C++ Error Control COding: a header-only library for ECC simulations and experiments, modeling complete coding systems across arbitrary finite fields and complex inter-field relationships - Christian Senger <senger@inue.uni-stuttgart.de>
Loading...
Searching...
No Matches
code_bounds.hpp
Go to the documentation of this file.
1/**
2 * @file code_bounds.hpp
3 * @brief Bounds on code parameters
4 * @author Christian Senger <senger@inue.uni-stuttgart.de>
5 * @version 1.0.1
6 * @date 2026
7 *
8 * @copyright
9 * Copyright (c) 2026, Christian Senger <senger@inue.uni-stuttgart.de>
10 *
11 * Licensed for noncommercial use only, including academic teaching, research, and personal non-profit purposes.
12 * Commercial use is prohibited without a separate commercial license. See the [LICENSE](../../LICENSE) file in the
13 * repository root for full terms and how to request a commercial license.
14 */
15
16#ifndef CODE_BOUNDS_HPP
17#define CODE_BOUNDS_HPP
18
20/*
21// transitive
22#include <algorithm>
23#include <cmath>
24#include <cstddef>
25#include <limits>
26#include <stdexcept>
27
28#include "InfInt.hpp"
29#include "helpers.hpp"
30*/
31
32namespace CECCO {
33
34template <FiniteFieldType T>
35long double HammingUpperBound(size_t n, size_t dmin) {
36 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
37 if (dmin == 0) throw std::invalid_argument("Cannot calculate upper bounds with dmin=0!");
38 if (dmin > n) throw std::invalid_argument("Cannot calculate upper bounds with dmin>n");
39
40 constexpr size_t q = T::get_size();
41 const size_t tmax = (dmin - 1) / 2;
42 const InfInt N = n, Q = q;
43 InfInt h = 0;
44 InfInt term = 1;
45 for (size_t i = 0; i <= tmax; ++i) {
46 if (i > 0) term = term * (N - i + 1) / i * (Q - 1);
47 h += term;
48 }
49
50 return n - log2(h) / std::log2(static_cast<long double>(q));
51}
52
53namespace details {
54
55template <FiniteFieldType T>
56InfInt A(size_t n, size_t d, InfInt w) {
57 const InfInt e = (d + 1) / 2;
58 if (w < e) return 1;
59
60 constexpr size_t q = T::get_size();
61 const InfInt Q = q, N = n;
62 InfInt res = 1;
63 for (InfInt i = e; i <= w; ++i) res = res * ((N - w + i) * (Q - 1)) / i;
64
65 return res;
66}
67
68} // namespace details
69
70template <FiniteFieldType T>
71long double JohnsonUpperBound(size_t n, size_t dmin) {
72 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
73 if (dmin == 0) throw std::invalid_argument("Cannot calculate upper bounds with dmin=0!");
74 if (dmin > n) throw std::invalid_argument("Cannot calculate upper bounds with dmin>n");
75
76 constexpr size_t q = T::get_size();
77 const size_t tmax = (dmin - 1) / 2;
78 const InfInt s = dmin % 2;
79 const InfInt N = n, Q = q;
80 InfInt h = 0;
81 InfInt term = 1;
82 for (size_t i = 0; i <= tmax; ++i) {
83 if (i > 0) term = term * (N - i + 1) / i * (Q - 1);
84 h += term;
85 }
86 term = term * (N - tmax) / (tmax + 1) * (Q - 1);
87
88 const InfInt numerator = term - s * bin<InfInt>(dmin, tmax) * details::A<T>(n, dmin, dmin);
89
90 const InfInt denominator = details::A<T>(n, dmin, tmax + 1);
91
92 // exact form of h + numerator/denominator, scaled by the (positive) denominator
93 const InfInt bracket = h * denominator + numerator;
94 if (bracket <= 0) return std::numeric_limits<long double>::infinity();
95
96 return n - (log2(bracket) - log2(denominator)) / std::log2(static_cast<long double>(q));
97}
98
99template <FiniteFieldType T>
100long double PlotkinUpperBound(size_t n, size_t dmin) {
101 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
102 if (dmin == 0) throw std::invalid_argument("Cannot calculate upper bounds with dmin=0!");
103 if (dmin > n) throw std::invalid_argument("Cannot calculate upper bounds with dmin>n");
104
105 constexpr size_t q = T::get_size();
106 const InfInt Q = q, N = n, D = dmin;
107 if (Q * D > N * (Q - 1)) { // conventional
108 return (log2(Q * D) - log2(Q * D - N * (Q - 1))) / std::log2(static_cast<long double>(q));
109 } else { // improved
110 const InfInt temp = (Q * D + (Q - 2)) / (Q - 1);
111 const InfInt denominator = Q * D - (temp - 1) * (Q - 1);
112
113 // N - temp + 2 >= 1 in this branch, so the conversion cannot overflow
114 return static_cast<long double>((N - temp + 2).toUnsignedLongLong()) +
115 (log2(D) - log2(denominator)) / std::log2(static_cast<long double>(q));
116 }
117}
118
119template <FiniteFieldType T>
120long double EliasUpperBound(size_t n, size_t dmin) {
121 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
122 if (dmin == 0) throw std::invalid_argument("Cannot calculate upper bounds with dmin=0!");
123 if (dmin > n) throw std::invalid_argument("Cannot calculate upper bounds with dmin>n");
124
125 constexpr size_t q = T::get_size();
126 long double minimum = std::numeric_limits<long double>::infinity();
127 const InfInt Q = q, N = n, D = dmin;
128 InfInt h = 0;
129 InfInt term = 1;
130 for (size_t w = 0; Q * w <= (Q - 1) * N; ++w) {
131 if (w > 0) term = term * (N - w + 1) / w * (Q - 1);
132 h += term;
133 const InfInt denominator = Q * w * w - InfInt(2) * (Q - 1) * N * w + (Q - 1) * N * D;
134 if (denominator > 0) {
135 const long double temp = log2((Q - 1) * N * D) - log2(denominator) - log2(h);
136 minimum = std::min(minimum, temp);
137 }
138 }
139
140 return n + minimum / std::log2(static_cast<long double>(q));
141}
142
144 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
145 if (dmin == 0) throw std::invalid_argument("Cannot calculate upper bounds with dmin=0!");
146 if (dmin > n) throw std::invalid_argument("Cannot calculate upper bounds with dmin>n");
147 return n - dmin + 1;
148}
149
150template <FiniteFieldType T>
152 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
153 if (dmin == 0) throw std::invalid_argument("Cannot calculate upper bounds with dmin=0!");
154 if (dmin > n) throw std::invalid_argument("Cannot calculate upper bounds with dmin>n");
155
156 constexpr size_t q = T::get_size();
157 size_t k = 0;
158 for (size_t kp = 1; kp <= n; ++kp) {
159 size_t sum = 0;
160 size_t qi = 1;
161 for (size_t i = 0; i < kp; ++i) {
162 sum += qi >= dmin ? 1 : (dmin + qi - 1) / qi;
163 if (sum > n) break;
164 if (qi < dmin) {
165 if (qi > dmin / q)
166 qi = dmin;
167 else
168 qi *= q;
169 }
170 }
171 if (sum <= n)
172 k = kp;
173 else
174 break;
175 }
176
177 return k;
178}
179
180template <FiniteFieldType T>
181long double UpperBound(size_t n, size_t dmin) {
182 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
183 if (dmin == 0) throw std::invalid_argument("Cannot calculate upper bounds with dmin=0!");
184 if (dmin > n) throw std::invalid_argument("Cannot calculate upper bounds with dmin>n");
185
186 long double minimum = std::numeric_limits<long double>::infinity();
187 for (size_t delta = 0; delta < std::min(n, dmin); ++delta) {
188 const long double hamming = HammingUpperBound<T>(n - delta, dmin - delta);
189 const long double johnson = JohnsonUpperBound<T>(n - delta, dmin - delta);
190 const long double plotkin = PlotkinUpperBound<T>(n - delta, dmin - delta);
191 const long double elias = EliasUpperBound<T>(n - delta, dmin - delta);
192 const long double singleton = SingletonUpperBound(n - delta, dmin - delta);
193 const long double griesmer = GriesmerUpperBound<T>(n - delta, dmin - delta);
194 minimum = std::min({minimum, hamming, johnson, plotkin, elias, singleton, griesmer});
195 }
196 return minimum;
197}
198
199template <FiniteFieldType T>
201 if (n == 0) throw std::invalid_argument("Cannot calculate lower bound with n=0!");
202 if (dmin == 0) throw std::invalid_argument("Cannot calculate lower bound with dmin=0!");
203 if (dmin > n) throw std::invalid_argument("Cannot calculate lower bound with dmin>n");
204 if (dmin == 1) return n;
205
206 constexpr size_t q = T::get_size();
207 InfInt sum = 0;
208 for (size_t i = 0; i <= dmin - 2; ++i) sum += bin<InfInt>(n - 1, i) * sqm<InfInt>(q - 1, i);
209 size_t r = 0;
210 for (InfInt qr = 1; qr <= sum; qr *= q) ++r;
211
212 return r <= n ? n - r : 0;
213}
214
215template <FiniteFieldType T>
217 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
218 if (ell > n) throw std::invalid_argument("Burst bound: burst length ell must be at most n");
219 constexpr size_t q = T::get_size();
220 const long double x = 1.0L + static_cast<long double>(q - 1) * static_cast<long double>(n - ell) / q;
221 return static_cast<size_t>(std::floor(n - ell - std::log2(x) / std::log2(static_cast<long double>(q))));
222}
223
225 if (n == 0) throw std::invalid_argument("Cannot calculate upper bounds with n=0!");
226 if (ell > n) throw std::invalid_argument("Burst bound: burst length ell must be at most n");
227 return ell > n / 2 ? 0 : n - 2 * ell;
228}
229
230} // namespace CECCO
231
232#endif
const InfInt & operator+=(const InfInt &rhs)
Definition InfInt.hpp:466
bool operator<(const InfInt &rhs) const
Definition InfInt.hpp:718
InfInt operator*(const InfInt &rhs) const
Definition InfInt.hpp:595
bool operator<=(const InfInt &rhs) const
Definition InfInt.hpp:743
const InfInt & operator++()
Definition InfInt.hpp:436
InfInt operator-(const InfInt &rhs) const
Definition InfInt.hpp:583
InfInt operator+(const InfInt &rhs) const
Definition InfInt.hpp:571
Contains implementation details not to be exposed to the user. Functions and classes here may change ...
Definition blocks.hpp:59
InfInt A(size_t n, size_t d, InfInt w)
Provides a framework for error correcting codes.
Definition blocks.hpp:57
long double EliasUpperBound(size_t n, size_t dmin)
long double HammingUpperBound(size_t n, size_t dmin)
long double JohnsonUpperBound(size_t n, size_t dmin)
size_t BurstUpperBound(size_t n, size_t ell)
constexpr size_t ReigerBurstUpperBound(size_t n, size_t ell)
size_t GriesmerUpperBound(size_t n, size_t dmin)
long double UpperBound(size_t n, size_t dmin)
long double log2(const InfInt &v)
Base-2 logarithm of a positive InfInt of arbitrary magnitude.
Definition helpers.hpp:304
size_t SingletonUpperBound(size_t n, size_t dmin)
long double PlotkinUpperBound(size_t n, size_t dmin)
size_t GilbertVarshamovLowerBound(size_t n, size_t dmin)