forked from zxing-cpp/zxing-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathReedSolomonDecoder.cpp
More file actions
150 lines (117 loc) · 4.05 KB
/
Copy pathReedSolomonDecoder.cpp
File metadata and controls
150 lines (117 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
* Copyright 2017 Axel Waggershauser
*/
// SPDX-License-Identifier: Apache-2.0
#include "ReedSolomonDecoder.h"
#include "GenericGF.h"
#include "ZXConfig.h"
#include <algorithm>
#include <stdexcept>
#include <utility>
namespace ZXing {
static bool
RunEuclideanAlgorithm(const GenericGF& field, std::vector<int>&& rCoefs, GenericGFPoly& sigma, GenericGFPoly& omega)
{
int R = Size(rCoefs); // == numECCodeWords
GenericGFPoly r(field, std::move(rCoefs));
GenericGFPoly& tLast = omega.setField(field);
GenericGFPoly& t = sigma.setField(field);
ZX_THREAD_LOCAL GenericGFPoly q, rLast;
rLast.setField(field);
q.setField(field);
rLast.setMonomial(1, R);
tLast.setMonomial(0);
t.setMonomial(1);
// Assume r's degree is < rLast's
if (r.degree() >= rLast.degree())
swap(r, rLast);
// Run Euclidean algorithm until r's degree is less than R/2
while (r.degree() >= R / 2) {
swap(tLast, t);
swap(rLast, r);
// Divide rLastLast by rLast, with quotient in q and remainder in r
if (rLast.isZero())
return false; // Oops, Euclidean algorithm already terminated?
r.divide(rLast, q);
q.multiply(tLast);
q.addOrSubtract(t);
swap(t, q); // t = q
if (r.degree() >= rLast.degree())
throw std::runtime_error("Division algorithm failed to reduce polynomial?");
}
int sigmaTildeAtZero = t.constant();
if (sigmaTildeAtZero == 0)
return false;
int inverse = field.inverse(sigmaTildeAtZero);
t.multiplyByMonomial(inverse);
r.multiplyByMonomial(inverse);
// sigma is t
omega = std::move(r);
return true;
}
static std::vector<int>
FindErrorLocations(const GenericGF& field, const GenericGFPoly& errorLocator)
{
// This is a brute force search for roots of errorLocator (not Chien's search)
int numErrors = errorLocator.degree();
std::vector<int> res;
res.reserve(numErrors);
for (int i = 1; i < field.size() && Size(res) < numErrors; i++)
if (errorLocator.evaluateAt(i) == 0)
res.push_back(field.inverse(i));
return res;
}
static std::vector<int>
FindErrorMagnitudes(const GenericGF& field, const GenericGFPoly& errorEvaluator, const std::vector<int>& errorLocations)
{
// This is directly applying Forney's Formula
int s = Size(errorLocations);
std::vector<int> res(s);
for (int i = 0; i < s; ++i) {
int xiInverse = field.inverse(errorLocations[i]);
int denom = 1;
for (int j = 0; j < s; ++j)
if (i != j)
denom = field.multiply(denom, 1 ^ field.multiply(errorLocations[j], xiInverse));
res[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denom));
if (field.generatorBase() != 0)
res[i] = field.multiply(res[i], xiInverse);
}
return res;
}
bool
ReedSolomonDecode(const GenericGF& field, std::vector<int>& message, int numECCodeWords)
{
GenericGFPoly poly(field, message);
std::vector<int> syndromes(numECCodeWords);
for (int i = 0; i < numECCodeWords; i++)
syndromes[numECCodeWords - 1 - i] = poly.evaluateAt(field.exp(i + field.generatorBase()));
// if all syndromes are 0 there is no error to correct
if (std::all_of(syndromes.begin(), syndromes.end(), [](int c) { return c == 0; }))
return true;
ZX_THREAD_LOCAL GenericGFPoly sigma, omega;
if (!RunEuclideanAlgorithm(field, std::move(syndromes), sigma, omega))
return false;
auto errorLocations = FindErrorLocations(field, sigma);
if (Size(errorLocations) != sigma.degree())
return false; // Error locator degree does not match number of roots, most likely there are more errors than can be recovered
auto errorMagnitudes = FindErrorMagnitudes(field, omega, errorLocations);
int msgLen = Size(message);
for (int i = 0; i < Size(errorLocations); ++i) {
int position = msgLen - 1 - field.log(errorLocations[i]);
if (position < 0)
return false;
message[position] ^= errorMagnitudes[i];
}
#if 1
// re-evaluate the syndromes of the recovered message to make sure it is a valid (see #940)
poly = GenericGFPoly(field, message);
for (int i = 0; i < numECCodeWords; i++)
if (poly.evaluateAt(field.exp(i + field.generatorBase())) != 0)
return false;
#endif
return true;
}
} // namespace ZXing