2
3
4
5
6
7
8
9
10
11
12
13
14
16#ifndef CODE_BOUNDS_HPP
17#define CODE_BOUNDS_HPP
21
22
23
24
25
26
27
28
29
30
31
35template <FiniteFieldType T>
37 if (n == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with n=0!");
38 if (dmin == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin=0!");
39 if (dmin > n)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin>n");
41 constexpr size_t q = T::get_size();
43 const size_t tmax = (dmin - 1) / 2;
45 for (size_t i = 0; i <= tmax; ++i) h += bin<
InfInt>(n, i) * sqm<
InfInt>(q - 1, i);
50 std::cerr <<
" [Hamming bound overflow]";
51 return std::numeric_limits<
long double>::infinity();
57template <FiniteFieldType T>
59 const InfInt e = (d + 1) / 2;
62 constexpr size_t q = T::get_size();
65 for (
InfInt i = e; i
<= w;
++i) res = res * ((N
- w
+ i) * (Q - 1)) / i;
72template <FiniteFieldType T>
74 if (n == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with n=0!");
75 if (dmin == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin=0!");
76 if (dmin > n)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin>n");
78 constexpr size_t q = T::get_size();
80 const size_t tmax = (dmin - 1) / 2;
83 for (size_t i = 0; i <= tmax; ++i) h += bin<
InfInt>(n, i) * sqm<
InfInt>(q - 1, i);
93 std::log2l(
static_cast<
long double>(q));
95 std::cerr <<
" [Johnson bound overflow]";
96 return std::numeric_limits<
long double>::infinity();
100template <FiniteFieldType T>
102 if (n == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with n=0!");
103 if (dmin == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin=0!");
104 if (dmin > n)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin>n");
106 constexpr size_t q = T::get_size();
108 const InfInt Q = q, N = n, D = dmin;
109 if (Q
* D > N * (Q - 1)) {
111 static_cast<
long double>((Q
* D - N * (Q - 1)).toUnsignedLongLong())) /
112 std::log2l(
static_cast<
long double>(q));
114 const InfInt Delta = N - Q
* D / (Q - 1) + 1;
118 std::log2l(
static_cast<
long double>(q));
121 std::cerr <<
" [Plotkin bound overflow]";
122 return std::numeric_limits<
long double>::infinity();
126template <FiniteFieldType T>
128 if (n == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with n=0!");
129 if (dmin == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin=0!");
130 if (dmin > n)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin>n");
132 constexpr size_t q = T::get_size();
134 long double minimum =
std::numeric_limits<
long double>::infinity();
135 const InfInt Q = q, N = n, D = dmin;
136 for (size_t w = 0; Q * w <= (Q - 1) * N; ++w) {
137 const InfInt denominator = Q * w * w - InfInt(2) * (Q - 1) * N * w + (Q - 1) * N * D;
138 if (denominator > 0) {
140 for (size_t i = 0; i <= w; ++i) h += bin<
InfInt>(N, i) * sqm<
InfInt>(Q - 1, i);
142 long double temp =
static_cast<
long double>(((Q - 1) * N * D).toUnsignedLongLong()) /
147 minimum =
std::min(minimum, temp);
151 return n +
std::log2l(minimum) /
std::log2l(
static_cast<
long double>(q));
153 std::cerr <<
" [Elias bound overflow]";
154 return std::numeric_limits<
long double>::infinity();
159 if (n == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with n=0!");
160 if (dmin == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin=0!");
161 if (dmin > n)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin>n");
165template <FiniteFieldType T>
167 if (n == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with n=0!");
168 if (dmin == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin=0!");
169 if (dmin > n)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin>n");
171 constexpr size_t q = T::get_size();
173 for (size_t kp = 1; kp <= n; ++kp) {
176 for (size_t i = 0; i < kp; ++i) {
177 sum += qi >= dmin ? 1 : (dmin + qi - 1) / qi;
195template <FiniteFieldType T>
197 if (n == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with n=0!");
198 if (dmin == 0)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin=0!");
199 if (dmin > n)
throw std::invalid_argument(
"Cannot calculate upper bounds with dmin>n");
201 long double minimum =
std::numeric_limits<
long double>::infinity();
202 for (size_t delta = 0; delta <
std::min(n, dmin); ++delta) {
203 const long double hamming = HammingUpperBound<T>(n - delta, dmin - delta);
204 const long double johnson = JohnsonUpperBound<T>(n - delta, dmin - delta);
205 const long double plotkin = PlotkinUpperBound<T>(n - delta, dmin - delta);
206 const long double elias = EliasUpperBound<T>(n - delta, dmin - delta);
207 const long double singleton = SingletonUpperBound(n - delta, dmin - delta);
208 const long double griesmer = GriesmerUpperBound<T>(n - delta, dmin - delta);
209 minimum =
std::min({minimum, hamming, johnson, plotkin, elias, singleton, griesmer});
214template <FiniteFieldType T>
216 if (n == 0)
throw std::invalid_argument(
"Cannot calculate lower bound with n=0!");
217 if (dmin == 0)
throw std::invalid_argument(
"Cannot calculate lower bound with dmin=0!");
218 if (dmin > n)
throw std::invalid_argument(
"Cannot calculate lower bound with dmin>n");
219 if (dmin == 1)
return n;
221 constexpr size_t q = T::get_size();
224 for (size_t i = 0; i <= dmin - 2; ++i) sum += bin<
InfInt>(n - 1, i) * sqm<
InfInt>(q - 1, i);
226 for (
InfInt qr = 1; qr
<= sum; qr *= q) ++r;
228 return r <= n ? n - r : 0;
230 std::cerr <<
" [Gilbert-Varshamov bound overflow]";
235template <FiniteFieldType T>
237 if (ell > n)
throw std::invalid_argument(
"Burst bound: burst length ell must be at most n");
238 constexpr size_t q = T::get_size();
239 return std::floor(n - ell -
std::log2(1 + (q - 1) * (n - ell) / q) /
std::log2(q));
243 if (2 * ell > n)
return 0;
bool operator<(const InfInt &rhs) const
InfInt operator*(const InfInt &rhs) const
bool operator<=(const InfInt &rhs) const
unsigned long long toUnsignedLongLong() const
const InfInt & operator++()
InfInt operator-(const InfInt &rhs) const
InfInt operator+(const InfInt &rhs) const
Contains implementation details not to be exposed to the user. Functions and classes here may change ...
InfInt A(size_t n, size_t d, InfInt w)
Provides a framework for error correcting codes.
long double EliasUpperBound(size_t n, size_t dmin)
size_t ReigerBurstUpperBound(size_t n, size_t ell)
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)
size_t GriesmerUpperBound(size_t n, size_t dmin)
long double UpperBound(size_t n, size_t dmin)
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)