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
34template <FiniteFieldType T>
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");
40 constexpr size_t q = T::get_size();
41 const size_t tmax = (dmin - 1) / 2;
45 for (size_t i = 0; i <= tmax; ++i) {
46 if (i > 0) term = term * (N - i + 1) / i * (Q - 1);
50 return n -
log2(h
) /
std::log2(
static_cast<
long double>(q));
55template <FiniteFieldType T>
57 const InfInt e = (d + 1) / 2;
60 constexpr size_t q = T::get_size();
63 for (
InfInt i = e; i
<= w;
++i) res = res * ((N
- w
+ i) * (Q - 1)) / i;
70template <FiniteFieldType T>
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");
76 constexpr size_t q = T::get_size();
77 const size_t tmax = (dmin - 1) / 2;
82 for (size_t i = 0; i <= tmax; ++i) {
83 if (i > 0) term = term * (N - i + 1) / i * (Q - 1);
86 term = term * (N - tmax) / (tmax + 1) * (Q - 1);
93 const InfInt bracket = h
* denominator
+ numerator;
94 if (bracket <= 0)
return std::numeric_limits<
long double>::infinity();
96 return n - (
log2(bracket
) -
log2(denominator
)) /
std::log2(
static_cast<
long double>(q));
99template <FiniteFieldType T>
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");
105 constexpr size_t q = T::get_size();
106 const InfInt Q = q, N = n, D = dmin;
107 if (Q
* D > N * (Q - 1)) {
108 return (
log2(Q
* D
) - log2(Q
* D - N * (Q - 1))) /
std::log2(
static_cast<
long double>(q));
110 const InfInt temp = (Q
* D + (Q - 2)) / (Q - 1);
111 const InfInt denominator = Q
* D - (temp - 1) * (Q - 1);
114 return static_cast<
long double>((N
- temp + 2).toUnsignedLongLong()) +
115 (
log2(D
) -
log2(denominator
)) /
std::log2(
static_cast<
long double>(q));
119template <FiniteFieldType T>
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");
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;
130 for (size_t w = 0; Q * w <= (Q - 1) * N; ++w) {
131 if (w > 0) term = term * (N - w + 1) / w * (Q - 1);
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);
140 return n + minimum /
std::log2(
static_cast<
long double>(q));
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");
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");
156 constexpr size_t q = T::get_size();
158 for (size_t kp = 1; kp <= n; ++kp) {
161 for (size_t i = 0; i < kp; ++i) {
162 sum += qi >= dmin ? 1 : (dmin + qi - 1) / qi;
180template <FiniteFieldType T>
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");
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});
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;
206 constexpr size_t q = T::get_size();
208 for (size_t i = 0; i <= dmin - 2; ++i) sum += bin<
InfInt>(n - 1, i) * sqm<
InfInt>(q - 1, i);
210 for (
InfInt qr = 1; qr
<= sum; qr *= q) ++r;
212 return r <= n ? n - r : 0;
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))));
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;
const InfInt & operator+=(const InfInt &rhs)
bool operator<(const InfInt &rhs) const
InfInt operator*(const InfInt &rhs) const
bool operator<=(const InfInt &rhs) 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)
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.
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)