aicodix___code/bose_chaudhuri_hocquenghem_decoder.hh

166 lines
4.5 KiB
C++

/*
Bose Chaudhuri Hocquenghem Decoder
Copyright 2018 Ahmet Inan <inan@aicodix.de>
*/
#ifndef BOSE_CHAUDHURI_HOCQUENGHEM_DECODER_HH
#define BOSE_CHAUDHURI_HOCQUENGHEM_DECODER_HH
#include "reed_solomon_error_correction.hh"
#include "bitman.hh"
namespace CODE {
template <int NR, int FCR, int MSG, typename GF>
class BoseChaudhuriHocquenghemDecoder
{
public:
typedef typename GF::value_type value_type;
typedef typename GF::ValueType ValueType;
typedef typename GF::IndexType IndexType;
static const int N = GF::N, K = MSG, NP = N - K;
private:
ReedSolomonErrorCorrection<NR, FCR, GF> algorithm;
void update_syndromes(uint8_t *poly, ValueType *syndromes, int begin, int end)
{
for (int j = begin; j < end; ++j) {
ValueType coeff(get_be_bit(poly, j));
IndexType root(FCR), pe(1);
for (int i = 0; i < NR; ++i) {
syndromes[i] = fma(root, syndromes[i], coeff);
root *= pe;
}
}
}
public:
int compute_syndromes(uint8_t *data, uint8_t *parity, ValueType *syndromes)
{
// $syndromes_i = code(pe^{FCR+i})$
ValueType coeff(get_be_bit(data, 0));
for (int i = 0; i < NR; ++i)
syndromes[i] = coeff;
update_syndromes(data, syndromes, 1, K);
update_syndromes(parity, syndromes, 0, NP);
int nonzero = 0;
for (int i = 0; i < NR; ++i)
nonzero += !!syndromes[i];
return nonzero;
}
int compute_syndromes(uint8_t *data, uint8_t *parity, value_type *syndromes)
{
return compute_syndromes(data, parity, reinterpret_cast<ValueType *>(syndromes));
}
int operator()(uint8_t *data, uint8_t *parity, value_type *erasures = 0, int erasures_count = 0)
{
assert(0 <= erasures_count && erasures_count <= NR);
if (0) {
for (int i = 0; i < erasures_count; ++i) {
int idx = (int)erasures[i];
if (idx < K)
set_be_bit(data, idx, 0);
else
set_be_bit(parity, idx-K, 0);
}
}
ValueType syndromes[NR];
if (!compute_syndromes(data, parity, syndromes))
return 0;
IndexType locations[NR];
ValueType magnitudes[NR];
int count = algorithm(syndromes, locations, magnitudes, reinterpret_cast<IndexType *>(erasures), erasures_count);
if (count <= 0)
return count;
for (int i = 0; i < count; ++i)
if (1 < (int)magnitudes[i])
return -1;
for (int i = 0; i < count; ++i) {
int idx = (int)locations[i];
bool err = (bool)magnitudes[i];
if (idx < K)
xor_be_bit(data, idx, err);
else
xor_be_bit(parity, idx-K, err);
}
int corrections_count = 0;
for (int i = 0; i < count; ++i)
corrections_count += !!magnitudes[i];
return corrections_count;
}
};
template <int NR, int FCR, int MSG, typename GF>
class BoseChaudhuriHocquenghemDecoderReference
{
public:
typedef typename GF::value_type value_type;
typedef typename GF::ValueType ValueType;
typedef typename GF::IndexType IndexType;
static const int N = GF::N, K = MSG, NP = N - K;
private:
ReedSolomonErrorCorrection<NR, FCR, GF> algorithm;
void update_syndromes(ValueType *poly, ValueType *syndromes, int begin, int end)
{
for (int j = begin; j < end; ++j) {
ValueType coeff(poly[j]);
IndexType root(FCR), pe(1);
for (int i = 0; i < NR; ++i) {
syndromes[i] = fma(root, syndromes[i], coeff);
root *= pe;
}
}
}
public:
int compute_syndromes(ValueType *data, ValueType *parity, ValueType *syndromes)
{
// $syndromes_i = code(pe^{FCR+i})$
ValueType coeff(data[0]);
for (int i = 0; i < NR; ++i)
syndromes[i] = coeff;
update_syndromes(data, syndromes, 1, K);
update_syndromes(parity, syndromes, 0, NP);
int nonzero = 0;
for (int i = 0; i < NR; ++i)
nonzero += !!syndromes[i];
return nonzero;
}
int operator()(ValueType *data, ValueType *parity, IndexType *erasures = 0, int erasures_count = 0)
{
assert(0 <= erasures_count && erasures_count <= NR);
if (0) {
for (int i = 0; i < erasures_count; ++i) {
int idx = (int)erasures[i];
if (idx < K)
data[idx] = ValueType(0);
else
parity[idx-K] = ValueType(0);
}
}
ValueType syndromes[NR];
if (!compute_syndromes(data, parity, syndromes))
return 0;
IndexType locations[NR];
ValueType magnitudes[NR];
int count = algorithm(syndromes, locations, magnitudes, erasures, erasures_count);
if (count <= 0)
return count;
for (int i = 0; i < count; ++i)
if (1 < (int)magnitudes[i])
return -1;
for (int i = 0; i < count; ++i) {
int idx = (int)locations[i];
if (idx < K)
data[idx] += magnitudes[i];
else
parity[idx-K] += magnitudes[i];
}
int corrections_count = 0;
for (int i = 0; i < count; ++i)
corrections_count += !!magnitudes[i];
return corrections_count;
}
};
}
#endif