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.0
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 <iostream>
26#include <limits>
27#include <stdexcept>
28
29#include "InfInt.hpp"
30#include "helpers.hpp"
31*/
32
33namespace CECCO {
34
35template <FiniteFieldType T>
36long double HammingUpperBound(size_t n, size_t dmin) {
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");
40
41 constexpr size_t q = T::get_size();
42 try {
43 const size_t tmax = (dmin - 1) / 2;
44 InfInt h = 0;
45 for (size_t i = 0; i <= tmax; ++i) h += bin<InfInt>(n, i) * sqm<InfInt>(q - 1, i);
46
47 return n -
48 std::log2l(static_cast<long double>(h.toUnsignedLongLong())) / std::log2l(static_cast<long double>(q));
49 } catch (const InfIntException& e) {
50 std::cerr << " [Hamming bound overflow]";
51 return std::numeric_limits<long double>::infinity();
52 }
53}
54
55namespace details {
56
57template <FiniteFieldType T>
58InfInt A(size_t n, size_t d, InfInt w) {
59 const InfInt e = (d + 1) / 2;
60 if (w < e) return 1;
61
62 constexpr size_t q = T::get_size();
63 const InfInt Q = q, N = n;
64 InfInt res = 1;
65 for (InfInt i = e; i <= w; ++i) res = res * ((N - w + i) * (Q - 1)) / i;
66
67 return res;
68}
69
70} // namespace details
71
72template <FiniteFieldType T>
73long double JohnsonUpperBound(size_t n, size_t dmin) {
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");
77
78 constexpr size_t q = T::get_size();
79 try {
80 const size_t tmax = (dmin - 1) / 2;
81 const InfInt s = dmin % 2;
82 InfInt h = 0;
83 for (size_t i = 0; i <= tmax; ++i) h += bin<InfInt>(n, i) * sqm<InfInt>(q - 1, i);
84
85 const InfInt numerator = bin<InfInt>(n, tmax + 1) * sqm<InfInt>(q - 1, tmax + 1) -
86 s * bin<InfInt>(dmin, tmax) * details::A<T>(n, dmin, dmin);
87
88 const InfInt denominator = details::A<T>(n, dmin, tmax + 1);
89
90 return n - std::log2l(static_cast<long double>(h.toUnsignedLongLong()) +
91 static_cast<long double>(numerator.toUnsignedLongLong()) /
92 static_cast<long double>(denominator.toUnsignedLongLong())) /
93 std::log2l(static_cast<long double>(q));
94 } catch (const InfIntException& e) {
95 std::cerr << " [Johnson bound overflow]";
96 return std::numeric_limits<long double>::infinity();
97 }
98}
99
100template <FiniteFieldType T>
101long double PlotkinUpperBound(size_t n, size_t dmin) {
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");
105
106 constexpr size_t q = T::get_size();
107 try {
108 const InfInt Q = q, N = n, D = dmin;
109 if (Q * D > N * (Q - 1)) { // conventional
110 return std::log2l(static_cast<long double>((Q * D).toUnsignedLongLong()) /
111 static_cast<long double>((Q * D - N * (Q - 1)).toUnsignedLongLong())) /
112 std::log2l(static_cast<long double>(q));
113 } else { // improved
114 const InfInt Delta = N - Q * D / (Q - 1) + 1;
115 const InfInt M = sqm<InfInt>(q, Delta.toUnsignedLongLong() + 1) * D / (Q * D - (N - Delta) * (Q - 1));
116
117 return std::log2l(static_cast<long double>(M.toUnsignedLongLong())) /
118 std::log2l(static_cast<long double>(q));
119 }
120 } catch (const InfIntException& e) {
121 std::cerr << " [Plotkin bound overflow]";
122 return std::numeric_limits<long double>::infinity();
123 }
124}
125
126template <FiniteFieldType T>
127long double EliasUpperBound(size_t n, size_t dmin) {
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");
131
132 constexpr size_t q = T::get_size();
133 try {
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) {
139 InfInt h = 0;
140 for (size_t i = 0; i <= w; ++i) h += bin<InfInt>(N, i) * sqm<InfInt>(Q - 1, i);
141
142 long double temp = static_cast<long double>(((Q - 1) * N * D).toUnsignedLongLong()) /
143 static_cast<long double>(denominator.toUnsignedLongLong());
144
145 temp /= static_cast<long double>(h.toUnsignedLongLong());
146
147 minimum = std::min(minimum, temp);
148 }
149 }
150
151 return n + std::log2l(minimum) / std::log2l(static_cast<long double>(q));
152 } catch (const InfIntException& e) {
153 std::cerr << " [Elias bound overflow]";
154 return std::numeric_limits<long double>::infinity();
155 }
156}
157
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");
162 return n - dmin + 1;
163}
164
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");
170
171 constexpr size_t q = T::get_size();
172 size_t k = 0;
173 for (size_t kp = 1; kp <= n; ++kp) {
174 size_t sum = 0;
175 size_t qi = 1;
176 for (size_t i = 0; i < kp; ++i) {
177 sum += qi >= dmin ? 1 : (dmin + qi - 1) / qi;
178 if (sum > n) break;
179 if (qi < dmin) {
180 if (qi > dmin / q)
181 qi = dmin;
182 else
183 qi *= q;
184 }
185 }
186 if (sum <= n)
187 k = kp;
188 else
189 break;
190 }
191
192 return k;
193}
194
195template <FiniteFieldType T>
196long double UpperBound(size_t n, size_t dmin) {
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");
200
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});
210 }
211 return minimum;
212}
213
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;
220
221 constexpr size_t q = T::get_size();
222 try {
223 InfInt sum = 0;
224 for (size_t i = 0; i <= dmin - 2; ++i) sum += bin<InfInt>(n - 1, i) * sqm<InfInt>(q - 1, i);
225 size_t r = 0;
226 for (InfInt qr = 1; qr <= sum; qr *= q) ++r;
227
228 return r <= n ? n - r : 0;
229 } catch (const InfIntException& e) {
230 std::cerr << " [Gilbert-Varshamov bound overflow]";
231 return 0;
232 }
233}
234
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));
240}
241
243 if (2 * ell > n) return 0;
244 return n - 2 * ell;
245}
246
247} // namespace CECCO
248
249#endif
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
unsigned long long toUnsignedLongLong() const
Definition InfInt.hpp:989
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)
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)