2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
59
60
61
62
63
67 explicit Vertex(uint32_t id)
noexcept;
74
75
76
77
81
82
83
84
85
86
87 Edge(uint32_t from_id, uint32_t to_id, T value);
101template <FieldType T>
102std::ostream& operator<<(
std::ostream& os,
const Trellis<T>& Tr);
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129template <FieldType T>
132
133
139
140
141
142
143
144
145
146
147
148 void add_edge(size_t segment, uint32_t id_from, uint32_t id_to, T value);
151
152
153
154
155
156
162
163
171
172
175
176
177
178
179
180
181
182 template <
typename cost_t>
192
193
194
195
199
200
201
202
203
204
205
206
211
212
213
214
215
216
235
236
237
238
239
245
246
247
248
252
253
254
255
256
257
274
275
278
279
280
281
282
283
284 template <
typename WS>
285 std::ostream&
print(
std::ostream& os,
const WS* ws)
const;
288
289
290
291
292
296 friend std::ostream& operator<< <>(
std::ostream& os,
const Trellis& Tr);
299
300
301
302
303 template <
typename WS>
307
308
309
310
311
312
313
314
315 template <
typename WS>
316 void tikz_picture(
std::ostream& file,
const WS* ws, size_t frontier)
const
320
321
322
323
324
325
326
327 template <
typename WS>
332
333
334
335
336
337
344
345
348
349
350
351
352
353
354
355
370template <FieldType T>
373template <FieldType T>
378template <FieldType T>
380 V[0].emplace_back(details::Vertex<T>(0));
383template <FieldType T>
385 if (segment >= E.size()) {
386 V.resize(segment + 2);
387 E.resize(segment + 1);
390 auto& Vf = V[segment];
391 if (std::ranges::find_if(Vf, [id_from](
const auto& v) {
return v.id == id_from; }) == Vf.cend())
392 throw std::invalid_argument(
"Start node id " + std::to_string(id_from) +
" not found in V[" +
393 std::to_string(segment) +
"]!");
395 auto& Vt = V[segment + 1];
396 if (std::ranges::find_if(Vt, [id_to](
const auto& v) {
return v.id == id_to; }) == Vt.cend()) {
397 if (id_to != Vt.size())
398 throw std::invalid_argument(
"New sink id " + std::to_string(id_to) +
" in V[" +
399 std::to_string(segment + 1) +
400 "] must equal its position (id==index invariant)!");
401 Vt.emplace_back(id_to);
404 auto& Es = E[segment];
405 if (std::ranges::any_of(Es, [&](
const auto& e) {
return e.from_id == id_from && e.to_id == id_to; }))
406 throw std::invalid_argument(
"Edge (" + std::to_string(id_from) +
" -> " + std::to_string(id_to) +
407 ") already exists in E[" + std::to_string(segment) +
"]!");
408 Es.emplace_back(id_from, id_to, value);
411template <FieldType T>
413 if (E.size() != other.E.size())
throw std::invalid_argument(
"Trellises must have the same number of segments!");
415 const size_t num_segments = E.size();
416 std::vector<std::unordered_map<uint64_t, uint32_t>> vmap(num_segments + 1);
418 auto get_or_add = [&](size_t s, uint32_t a, uint32_t b) -> uint32_t {
419 const uint64_t key = (
static_cast<uint64_t>(a) << 32) | b;
420 auto [it, inserted] = vmap[s].try_emplace(key,
static_cast<uint32_t>(vmap[s].size()));
428 for (size_t s = 0; s < num_segments; ++s) {
429 for (
const auto& e1 : E[s]) {
430 for (
const auto& e2 : other.E[s]) {
431 result.add_edge(s, get_or_add(s, e1.from_id, e2.from_id), get_or_add(s + 1, e1.to_id, e2.to_id),
432 e1.value + e2.value);
440template <FieldType T>
443 for (
const auto& seg : V)
444 if (seg.size() > max) max = seg.size();
449template <
typename cost_t>
472#ifdef CECCO_ERASURE_SUPPORT
493template <FieldType T>
495 alpha.reserve(tr.V.size());
496 beta.reserve(tr.V.size());
497 for (size_t s = 0; s < tr.V.size(); ++s) {
498 alpha.emplace_back(tr.V[s].size(), -std::numeric_limits<
double>::infinity());
499 beta.emplace_back(tr.V[s].size(), -std::numeric_limits<
double>::infinity());
501 edge_costs.reserve(tr.E.size());
502 for (size_t s = 0; s < tr.E.size(); ++s) edge_costs.emplace_back(tr.E[s].size());
505template <FieldType T>
507 requires
std::is_same_v<
T,
Fp<2>>
516template <
typename WS>
543template <
typename WS>
548 file << R"(% required in preamble:
549% \usepackage{amsfonts}
550% \usepackage{bm}
551% \usepackage{tikz}
552% \usetikzlibrary{arrows.meta, backgrounds, calc, positioning}
553
554\tikzset{>={Stealth[scale=)"
556\tikzstyle{trellisvertex}=[circle, draw=black, outer sep=0pt, inner sep=0pt, minimum size=)"
557 <<
vertex_size << R"(pt, left color=gray!80, right color=gray!20])";
561\tikzstyle{trellisvertexprev}=[trellisvertex, inner sep=1pt, left color=blue!80, right color=blue!20, text width=4ex, align=center]
562\tikzstyle{trellisvertexcurr}=[trellisvertex, inner sep=1pt, left color=green!80, right color=green!20, text width=4ex, align=center])";
565\tikzstyle{trellisvertexprev}=[trellisvertex, inner sep=2pt, left color=blue!80, right color=blue!20]
566\tikzstyle{trellisvertexcurr}=[trellisvertex, inner sep=2pt, left color=green!80, right color=green!20])";
570\tikzstyle{trellisarrow}=[draw, ->, fill=black]
571\tikzstyle{trellisarrowone}=[trellisarrow, fill=red, draw=red]
572\tikzstyle{trellisarrowzero}=[trellisarrow, densely dashed, fill=black, draw=black]
573\tikzstyle{trellisedgelabel}=[below, sloped]
574\tikzstyle{trellispath}=[double distance=.075cm, thick, line join=round, cap=round])";
578template <
typename WS>
582 file <<
"\n\n\\begin{tikzpicture}[x=\\linewidth/" <<
E.
size() <<
", y=1cm]";
586 const char*
style =
"trellisvertex";
590 style =
"trellisvertexprev";
594 style =
"trellisvertexcurr";
597 style =
"trellisvertexprev";
602 file <<
"\n \\node[" <<
style <<
"] (" <<
s <<
"_" <<
V[
s][
i].
id <<
") at (" <<
s <<
", "
603 << -
static_cast<
int>(
V[
s][
i].
id) <<
") {\\tiny$";
622 const auto&
e =
E[
s][
j];
625 file <<
"\n \\path[trellisarrowzero]";
627 file <<
"\n \\path[trellisarrowone]";
633 file <<
"\n \\definecolor{color}{RGB}{" <<
static_cast<
int>(
r) <<
", " <<
static_cast<
int>(
g) <<
", "
634 <<
static_cast<
int>(
b) <<
"}\\path[trellisarrow, draw=color, fill=color]";
638 file <<
" edge[trellisedgelabel] node[black] {\\tiny$";
648 file <<
"\n \\begin{scope}[on background layer]";
651 file <<
"\n \\draw [dotted, shorten >=-5mm] (" <<
s <<
"_0) to (" <<
s <<
", "
652 << -
static_cast<
int>(
maxdepth) + 1 <<
");";
667 file <<
"\n \\draw[trellispath, green, double=green!15] (" <<
frontier - 1 <<
"_" <<
path[1]
670 file <<
"\n \\draw[trellispath, blue, double=blue!15]";
681 file <<
"\n \\end{scope}"
682 <<
"\n \\node[node distance=.0cm, below left=of 0_0] {$\\mathfrak{s}$};"
683 <<
"\n \\node[node distance=.0cm, below right=of " <<
E.
size() <<
"_0] {$\\mathfrak{t}$};";
687 file <<
"\n \\node[anchor=east] at ($(0_0)+(0,.5)$) {\\small$\\bm{v}=$};";
689 file <<
"\n \\node at ($(" <<
s <<
"_0)!0.5!(" <<
s + 1 <<
"_0)+(0,.5)$) {\\small$";
690 if (
s == 0)
file <<
"(";
692 file << (
s + 1 ==
E.
size() ?
")" :
",") <<
"$};";
697 file <<
"\n\\end{tikzpicture}\n";
701template <
typename WS>
738 for (
const auto&
e :
E[
g *
m +
step])
756 for (
const auto&
e :
E[
s]) {
Contains implementation details not to be exposed to the user. Functions and classes here may change ...
Provides a framework for error correcting codes.
Workspace for binary BCJR forward-backward decoding.
std::vector< std::vector< double > > alpha
Forward metrics by layer and vertex id.
std::vector< std::vector< double > > beta
Backward metrics by layer and vertex id.
BCJR_Workspace(const Trellis &tr)
Allocate metric arrays for tr.
void calculate_edge_costs(const Trellis &tr, const Vector< double > &llrs)
Set BCJR edge costs from binary LLRs.
std::vector< std::vector< double > > edge_costs
Edge cost for each segment and edge index.
static constexpr bool is_soft
BCJR uses floating-point soft metrics.
Trellis with field-labelled edges between consecutive layers.
std::vector< std::vector< details::Edge< T > > > E
Edges by segment; E[s] connects V[s] to V[s + 1].
void tikz_header(std::ostream &file) const
Write TikZ style definitions.
void add_edge(size_t segment, uint32_t id_from, uint32_t id_to, T value)
Add one edge in segment segment.
std::vector< std::vector< details::Vertex< T > > > V
Vertices by layer; V[s][i].id == i.
Trellis operator*(const Trellis &other) const
Product trellis with componentwise added edge labels.
std::ostream & print(std::ostream &os, const WS *ws) const
Write a segment-by-segment text representation.
Trellis()
Construct the one-vertex source trellis.
size_t get_maximum_depth() const noexcept
Maximum number of vertices in any layer.
std::ostream & print(std::ostream &os) const
Write a segment-by-segment text representation without edge costs.
void export_as_tikz(const std::string &filename) const
Export a standalone TikZ fragment without workspace metrics.
void export_as_tikz(const std::string &filename, const WS *ws) const
Export a standalone TikZ fragment with workspace metrics.
void tikz_picture(std::ostream &file, const WS *ws, size_t frontier) const
Write one TikZ picture of the trellis.
Edge between two adjacent trellis layers.
uint32_t from_id
Source vertex id.
Edge(uint32_t from_id, uint32_t to_id, T value)
Construct an edge from_id --value--> to_id.
uint32_t to_id
Target vertex id.
Vertex in one trellis layer.
uint32_t id
Layer-local vertex id.
Vertex(uint32_t id) noexcept
Construct a vertex with layer-local id id.