merged encoder and decoder

This commit is contained in:
Ahmet Inan 2023-05-08 08:12:17 +02:00
commit 078ae40d83
2 changed files with 31 additions and 40 deletions

View file

@ -9,7 +9,7 @@ Copyright 2023 Ahmet Inan <inan@aicodix.de>
namespace CODE {
template <typename GF>
struct CauchyReedSolomonEncoder
struct CauchyReedSolomonErasureCoding
{
typedef typename GF::value_type value_type;
typedef typename GF::ValueType ValueType;
@ -20,36 +20,6 @@ struct CauchyReedSolomonEncoder
ValueType row(i), col(ValueType::N - j);
return rcp(index(row + col));
}
void operator()(const ValueType *data, ValueType *block, int block_num, int block_len, int block_cnt)
{
assert(block_num <= ValueType::N - block_cnt);
for (int k = 0; k < block_cnt; k++) {
IndexType a_ik = cauchy_matrix(block_num, k);
for (int j = 0; j < block_len; j++) {
if (k)
block[j] = fma(a_ik, data[block_len*k+j], block[j]);
else
block[j] = a_ik * data[block_len*k+j];
}
}
}
void operator()(const value_type *data, value_type *block, int block_num, int block_len, int block_cnt)
{
(*this)(reinterpret_cast<const ValueType *>(data), reinterpret_cast<ValueType *>(block), block_num, block_len, block_cnt);
}
void operator()(const void *data, void *block, int block_number, int block_bytes, int block_count)
{
assert(block_bytes % sizeof(value_type) == 0);
(*this)(reinterpret_cast<const value_type *>(data), reinterpret_cast<value_type *>(block), block_number, block_bytes / sizeof(value_type), block_count);
}
};
template <typename GF>
struct CauchyReedSolomonDecoder
{
typedef typename GF::value_type value_type;
typedef typename GF::ValueType ValueType;
typedef typename GF::IndexType IndexType;
// $b_{ij} = \frac{\prod_{k=1}^{n}{(x_j + y_k)(x_k + y_i)}}{(x_j + y_i)\prod_{k \ne j}^{n}{(x_j - x_k)}\prod_{k \ne i}^{n}{(y_i - y_k)}}$
IndexType inverse_cauchy_matrix(const ValueType *rows, int i, int j, int n)
{
@ -65,7 +35,20 @@ struct CauchyReedSolomonDecoder
}
return prod_xy / (index(rows[j] + col_i) * prod_x * prod_y);
}
void operator()(ValueType *data, const ValueType *blocks, const ValueType *block_nums, int block_num, int block_len, int block_cnt)
void encode(const ValueType *data, ValueType *block, int block_num, int block_len, int block_cnt)
{
assert(block_num <= ValueType::N - block_cnt);
for (int k = 0; k < block_cnt; k++) {
IndexType a_ik = cauchy_matrix(block_num, k);
for (int j = 0; j < block_len; j++) {
if (k)
block[j] = fma(a_ik, data[block_len*k+j], block[j]);
else
block[j] = a_ik * data[block_len*k+j];
}
}
}
void decode(ValueType *data, const ValueType *blocks, const ValueType *block_nums, int block_num, int block_len, int block_cnt)
{
for (int k = 0; k < block_cnt; k++) {
IndexType b_ik = inverse_cauchy_matrix(block_nums, block_num, k, block_cnt);
@ -77,14 +60,23 @@ struct CauchyReedSolomonDecoder
}
}
}
void operator()(value_type *data, const value_type *blocks, const value_type *block_nums, int block_num, int block_len, int block_cnt)
void encode(const value_type *data, value_type *block, int block_num, int block_len, int block_cnt)
{
(*this)(reinterpret_cast<ValueType *>(data), reinterpret_cast<const ValueType *>(blocks), reinterpret_cast<const ValueType *>(block_nums), block_num, block_len, block_cnt);
encode(reinterpret_cast<const ValueType *>(data), reinterpret_cast<ValueType *>(block), block_num, block_len, block_cnt);
}
void operator()(void *data, const void *blocks, const value_type *block_numbers, int block_number, int block_bytes, int block_count)
void decode(value_type *data, const value_type *blocks, const value_type *block_nums, int block_num, int block_len, int block_cnt)
{
decode(reinterpret_cast<ValueType *>(data), reinterpret_cast<const ValueType *>(blocks), reinterpret_cast<const ValueType *>(block_nums), block_num, block_len, block_cnt);
}
void encode(const void *data, void *block, int block_number, int block_bytes, int block_count)
{
assert(block_bytes % sizeof(value_type) == 0);
(*this)(reinterpret_cast<value_type *>(data), reinterpret_cast<const value_type *>(blocks), block_numbers, block_number, block_bytes / sizeof(value_type), block_count);
encode(reinterpret_cast<const value_type *>(data), reinterpret_cast<value_type *>(block), block_number, block_bytes / sizeof(value_type), block_count);
}
void decode(void *data, const void *blocks, const value_type *block_numbers, int block_number, int block_bytes, int block_count)
{
assert(block_bytes % sizeof(value_type) == 0);
decode(reinterpret_cast<value_type *>(data), reinterpret_cast<const value_type *>(blocks), block_numbers, block_number, block_bytes / sizeof(value_type), block_count);
}
};

View file

@ -15,8 +15,7 @@ Copyright 2023 Ahmet Inan <inan@aicodix.de>
template <typename GF>
void crs_test(int trials)
{
CODE::CauchyReedSolomonEncoder<GF> encode;
CODE::CauchyReedSolomonDecoder<GF> decode;
CODE::CauchyReedSolomonErasureCoding<GF> crs;
std::random_device rd;
std::default_random_engine generator(rd());
typedef std::uniform_int_distribution<int> distribution;
@ -41,14 +40,14 @@ void crs_test(int trials)
}
auto enc_start = std::chrono::system_clock::now();
for (int i = 0; i < block_count; ++i)
encode(orig, blocks + block_bytes * i, numbers[i], block_bytes, block_count);
crs.encode(orig, blocks + block_bytes * i, numbers[i], block_bytes, block_count);
auto enc_end = std::chrono::system_clock::now();
auto enc_usec = std::chrono::duration_cast<std::chrono::microseconds>(enc_end - enc_start);
double enc_mbs = double(data_bytes) / enc_usec.count();
uint8_t *data = new uint8_t[data_bytes];
auto dec_start = std::chrono::system_clock::now();
for (int i = 0; i < block_count; ++i)
decode(data + block_bytes * i, blocks, numbers, i, block_bytes, block_count);
crs.decode(data + block_bytes * i, blocks, numbers, i, block_bytes, block_count);
auto dec_end = std::chrono::system_clock::now();
auto dec_usec = std::chrono::duration_cast<std::chrono::microseconds>(dec_end - dec_start);
double dec_mbs = double(data_bytes) / dec_usec.count();