mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
114
tdfec/td/fec/algebra/BeliefPropagationDecoding.cpp
Normal file
114
tdfec/td/fec/algebra/BeliefPropagationDecoding.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/fec/algebra/BeliefPropagationDecoding.h"
|
||||
|
||||
namespace td {
|
||||
BeliefPropagationDecoding::BeliefPropagationDecoding(size_t symbols_count, size_t symbol_size)
|
||||
: max_equation_count_{static_cast<size_t>(static_cast<double>(symbols_count) * 1.1 + 5)}
|
||||
, C_{symbols_count, symbol_size}
|
||||
, D_{max_equation_count_, symbol_size} {
|
||||
equations_.reserve(max_equation_count_);
|
||||
symbols_.resize(symbols_count);
|
||||
|
||||
edges_.resize(1);
|
||||
}
|
||||
|
||||
Slice BeliefPropagationDecoding::get_symbol(uint32 symbol_id) const {
|
||||
CHECK(symbols_[symbol_id].is_ready);
|
||||
return C_.row(symbol_id);
|
||||
}
|
||||
|
||||
void BeliefPropagationDecoding::add_equation(Span<uint32> symbol_ids, Slice data) {
|
||||
if (equations_.size() >= D_.rows()) {
|
||||
MatrixGF256 new_D(D_.rows() * 2, D_.cols());
|
||||
new_D.set_from(D_, 0, 0);
|
||||
D_ = std::move(new_D);
|
||||
}
|
||||
CHECK(symbol_ids.size() != 0);
|
||||
|
||||
uint32 equation_id = static_cast<uint32>(equations_.size());
|
||||
D_.row_set(equation_id, data);
|
||||
|
||||
EquationInfo equation;
|
||||
for (auto symbol_id : symbol_ids) {
|
||||
CHECK(symbol_id < symbols_.size());
|
||||
auto &symbol = symbols_[symbol_id];
|
||||
if (symbol.is_ready) {
|
||||
D_.row_add(equation_id, C_.row(symbol_id));
|
||||
} else {
|
||||
equation.symbols_xor ^= symbol_id;
|
||||
equation.symbols_count++;
|
||||
|
||||
edges_.push_back({equation_id, symbol.head_});
|
||||
symbol.head_ = uint32(edges_.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (equation.symbols_count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
equations_.push_back(equation);
|
||||
if (equation.symbols_count == 1) {
|
||||
ready_equations_.push_back(equation_id);
|
||||
loop();
|
||||
}
|
||||
}
|
||||
bool BeliefPropagationDecoding::is_ready() const {
|
||||
return ready_symbols().size() == C_.rows();
|
||||
}
|
||||
|
||||
Span<uint32> BeliefPropagationDecoding::ready_symbols() const {
|
||||
return ready_symbols_;
|
||||
}
|
||||
|
||||
void BeliefPropagationDecoding::loop() {
|
||||
while (!is_ready() && !ready_equations_.empty()) {
|
||||
auto equation_id = ready_equations_.back();
|
||||
ready_equations_.pop_back();
|
||||
auto &equation = equations_[equation_id];
|
||||
LOG_CHECK(equation.symbols_count <= 1) << equation.symbols_count;
|
||||
if (equation.symbols_count == 0) {
|
||||
continue;
|
||||
}
|
||||
auto symbol_id = equation.symbols_xor;
|
||||
auto &symbol = symbols_[symbol_id];
|
||||
LOG_CHECK(symbol_id < symbols_.size())
|
||||
<< equation.symbols_xor << " " << equation.symbols_count << " " << equation_id;
|
||||
if (symbol.is_ready) {
|
||||
continue;
|
||||
}
|
||||
C_.row_set(symbol_id, D_.row(equation_id));
|
||||
symbol.is_ready = true;
|
||||
ready_symbols_.push_back(symbol_id);
|
||||
for (auto i = symbol.head_; i != 0;) {
|
||||
auto &edge = edges_[i];
|
||||
auto next_equation_id = edge.value;
|
||||
i = edge.next;
|
||||
D_.row_add(next_equation_id, C_.row(symbol_id));
|
||||
auto &next_equation = equations_[next_equation_id];
|
||||
next_equation.symbols_xor ^= symbol_id;
|
||||
next_equation.symbols_count--;
|
||||
if (next_equation.symbols_count == 1) {
|
||||
ready_equations_.push_back(next_equation_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace td
|
62
tdfec/td/fec/algebra/BeliefPropagationDecoding.h
Normal file
62
tdfec/td/fec/algebra/BeliefPropagationDecoding.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/Span.h"
|
||||
#include "td/fec/algebra/MatrixGF256.h"
|
||||
|
||||
namespace td {
|
||||
class BeliefPropagationDecoding {
|
||||
public:
|
||||
explicit BeliefPropagationDecoding(size_t symbols_count, size_t symbol_size);
|
||||
|
||||
void add_equation(Span<uint32> symbol_ids, Slice data);
|
||||
|
||||
bool is_ready() const;
|
||||
Span<uint32> ready_symbols() const;
|
||||
Slice get_symbol(uint32 symbol_id) const;
|
||||
|
||||
private:
|
||||
struct SymbolInfo {
|
||||
bool is_ready{false};
|
||||
uint32 head_ = 0;
|
||||
};
|
||||
|
||||
struct EquationInfo {
|
||||
uint32 symbols_xor{0};
|
||||
uint32 symbols_count{0};
|
||||
};
|
||||
|
||||
size_t max_equation_count_;
|
||||
MatrixGF256 C_;
|
||||
MatrixGF256 D_;
|
||||
std::vector<SymbolInfo> symbols_;
|
||||
std::vector<EquationInfo> equations_;
|
||||
std::vector<uint32> ready_equations_;
|
||||
std::vector<uint32> ready_symbols_;
|
||||
|
||||
struct Edge {
|
||||
uint32 value;
|
||||
uint32 next;
|
||||
};
|
||||
std::vector<Edge> edges_;
|
||||
|
||||
void loop();
|
||||
};
|
||||
} // namespace td
|
59
tdfec/td/fec/algebra/GaussianElimination.cpp
Normal file
59
tdfec/td/fec/algebra/GaussianElimination.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/fec/algebra/GaussianElimination.h"
|
||||
namespace td {
|
||||
Result<MatrixGF256> GaussianElimination::run(MatrixGF256 A, MatrixGF256 D) {
|
||||
const size_t cols = A.cols();
|
||||
const size_t rows = A.rows();
|
||||
|
||||
CHECK(cols <= rows);
|
||||
|
||||
std::vector<uint32> row_perm(rows);
|
||||
for (uint32 i = 0; i < rows; i++) {
|
||||
row_perm[i] = i;
|
||||
}
|
||||
for (size_t row = 0; row < cols; row++) {
|
||||
size_t non_zero_row = row;
|
||||
for (; non_zero_row < rows && A.get(row_perm[non_zero_row], row).is_zero(); non_zero_row++) {
|
||||
}
|
||||
if (non_zero_row == rows) {
|
||||
return Status::Error("Non solvable");
|
||||
}
|
||||
if (non_zero_row != row) {
|
||||
std::swap(row_perm[non_zero_row], row_perm[row]);
|
||||
}
|
||||
auto mul = A.get(row_perm[row], row).inverse();
|
||||
A.row_multiply(row_perm[row], mul);
|
||||
D.row_multiply(row_perm[row], mul);
|
||||
CHECK(A.get(row_perm[row], row).value() == 1);
|
||||
for (size_t zero_row = 0; zero_row < rows; zero_row++) {
|
||||
if (zero_row == row) {
|
||||
continue;
|
||||
}
|
||||
auto x = A.get(row_perm[zero_row], row);
|
||||
if (!x.is_zero()) {
|
||||
A.row_add_mul(row_perm[zero_row], row_perm[row], x);
|
||||
D.row_add_mul(row_perm[zero_row], row_perm[row], x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return D.apply_row_permutation(row_perm);
|
||||
}
|
||||
} // namespace td
|
28
tdfec/td/fec/algebra/GaussianElimination.h
Normal file
28
tdfec/td/fec/algebra/GaussianElimination.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/fec/algebra/MatrixGF256.h"
|
||||
|
||||
namespace td {
|
||||
class GaussianElimination {
|
||||
public:
|
||||
static Result<MatrixGF256> run(MatrixGF256 A, MatrixGF256 D);
|
||||
};
|
||||
} // namespace td
|
186
tdfec/td/fec/algebra/InactivationDecoding.cpp
Normal file
186
tdfec/td/fec/algebra/InactivationDecoding.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/fec/algebra/InactivationDecoding.h"
|
||||
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace td {
|
||||
InactivationDecodingResult InactivationDecoding::run() {
|
||||
init();
|
||||
loop();
|
||||
|
||||
LOG(DEBUG) << tag("A_small.cols", L_.cols() - p_rows_.size()) << tag("Total columns", L_.cols()) << tag("PI", PI_)
|
||||
<< tag("A_small.cols - PI", L_.cols() - PI_ - p_rows_.size());
|
||||
for (uint32 row = 0; row < rows_; row++) {
|
||||
if (!was_row_[row]) {
|
||||
p_rows_.push_back(row);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 side = narrow_cast<uint32>(p_cols_.size());
|
||||
std::reverse(inactive_cols_.begin(), inactive_cols_.end());
|
||||
for (auto col : inactive_cols_) {
|
||||
p_cols_.push_back(col);
|
||||
}
|
||||
for (uint32 i = 0; i < PI_; i++) {
|
||||
p_cols_.push_back(cols_ + i);
|
||||
}
|
||||
check(side);
|
||||
return {side, std::move(p_rows_), std::move(p_cols_)};
|
||||
}
|
||||
|
||||
void InactivationDecoding::init() {
|
||||
was_row_ = vector<bool>(rows_, false);
|
||||
was_col_ = vector<bool>(cols_, false);
|
||||
|
||||
col_cnt_ = vector<uint32>(cols_, 0);
|
||||
row_cnt_ = vector<uint32>(rows_, 0);
|
||||
row_xor_ = vector<uint32>(rows_, 0);
|
||||
L_.generate([&](auto row, auto col) {
|
||||
if (col >= cols_) {
|
||||
return;
|
||||
}
|
||||
col_cnt_[col]++;
|
||||
row_cnt_[row]++;
|
||||
row_xor_[row] ^= col;
|
||||
});
|
||||
|
||||
sort_rows();
|
||||
}
|
||||
|
||||
void InactivationDecoding::loop() {
|
||||
while (row_cnt_offset_[1] != rows_) {
|
||||
auto row = sorted_rows_[row_cnt_offset_[1]];
|
||||
uint32 col = choose_col(row);
|
||||
LOG_CHECK(col_cnt_[col] >= 1) << col;
|
||||
|
||||
auto cnt = row_cnt_[row];
|
||||
CHECK(row_cnt_offset_[cnt] == row_cnt_offset_[1]);
|
||||
CHECK(row_pos_[row] == row_cnt_offset_[1]);
|
||||
p_cols_.push_back(col);
|
||||
p_rows_.push_back(row);
|
||||
|
||||
if (cnt == 1) {
|
||||
inactivate_col(col);
|
||||
} else {
|
||||
for (auto x : L_rows_.col(row)) {
|
||||
if (x >= cols_ || was_col_[x]) {
|
||||
continue;
|
||||
}
|
||||
if (x != col) {
|
||||
inactive_cols_.push_back(x);
|
||||
}
|
||||
inactivate_col(x);
|
||||
}
|
||||
}
|
||||
was_row_[row] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void InactivationDecoding::check_sorted() {
|
||||
for (size_t i = 0; i < rows_; i++) {
|
||||
CHECK(sorted_rows_[row_pos_[i]] == i);
|
||||
}
|
||||
for (size_t i = 1; i < rows_; i++) {
|
||||
CHECK(row_cnt_[sorted_rows_[i - 1]] <= row_cnt_[sorted_rows_[i]]);
|
||||
}
|
||||
for (size_t i = 1; i <= cols_ + 1; i++) {
|
||||
CHECK(row_cnt_offset_[i - 1] <= row_cnt_offset_[i]);
|
||||
}
|
||||
for (size_t i = 0; i < rows_; i++) {
|
||||
auto pos = row_pos_[i];
|
||||
auto cnt = row_cnt_[i];
|
||||
CHECK(pos >= row_cnt_offset_[cnt]);
|
||||
CHECK(pos < row_cnt_offset_[cnt + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 InactivationDecoding::choose_col(uint32 row) {
|
||||
auto cnt = row_cnt_[row];
|
||||
if (cnt == 1) {
|
||||
return row_xor_[row];
|
||||
}
|
||||
uint32 best_col = uint32(-1);
|
||||
for (auto col : L_rows_.col(row)) {
|
||||
if (col >= cols_ || was_col_[col]) {
|
||||
continue;
|
||||
}
|
||||
DCHECK(col_cnt_[col] >= 1);
|
||||
if (best_col == uint32(-1) || col_cnt_[col] < col_cnt_[best_col]) {
|
||||
best_col = col;
|
||||
}
|
||||
}
|
||||
DCHECK(best_col != uint32(-1));
|
||||
return best_col;
|
||||
}
|
||||
|
||||
void InactivationDecoding::inactivate_col(uint32 col) {
|
||||
was_col_[col] = true;
|
||||
for (auto row : L_.col(col)) {
|
||||
if (was_row_[row]) {
|
||||
continue;
|
||||
}
|
||||
auto pos = row_pos_[row];
|
||||
DCHECK(sorted_rows_[pos] == row);
|
||||
auto cnt = row_cnt_[row];
|
||||
LOG_DCHECK(cnt >= 1) << row << " " << col;
|
||||
auto offset = row_cnt_offset_[cnt];
|
||||
std::swap(sorted_rows_[pos], sorted_rows_[offset]);
|
||||
row_pos_[sorted_rows_[pos]] = pos;
|
||||
row_pos_[sorted_rows_[offset]] = offset;
|
||||
row_cnt_offset_[cnt]++;
|
||||
row_cnt_[row]--;
|
||||
row_xor_[row] ^= col;
|
||||
}
|
||||
}
|
||||
|
||||
void InactivationDecoding::sort_rows() {
|
||||
vector<uint32> offset(cols_ + 2, 0);
|
||||
for (size_t i = 0; i < rows_; i++) {
|
||||
offset[row_cnt_[i] + 1]++;
|
||||
}
|
||||
for (size_t i = 1; i <= cols_ + 1; i++) {
|
||||
offset[i] += offset[i - 1];
|
||||
}
|
||||
row_cnt_offset_ = offset;
|
||||
|
||||
sorted_rows_.resize(rows_);
|
||||
row_pos_.resize(rows_);
|
||||
for (uint32 i = 0; i < rows_; i++) {
|
||||
auto pos = offset[row_cnt_[i]]++;
|
||||
sorted_rows_[pos] = i;
|
||||
row_pos_[i] = pos;
|
||||
}
|
||||
}
|
||||
|
||||
void InactivationDecoding::check(uint32 side) {
|
||||
auto inv_p_cols = inverse_permutation(p_cols_);
|
||||
auto inv_p_rows = inverse_permutation(p_rows_);
|
||||
for (uint32 i = 0; i < side; i++) {
|
||||
CHECK(inv_p_cols[p_cols_[i]] == i);
|
||||
auto col = L_.col(p_cols_[i]);
|
||||
CHECK(col.size() >= 1);
|
||||
for (auto x : col) {
|
||||
CHECK(inv_p_rows[x] >= i);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace td
|
73
tdfec/td/fec/algebra/InactivationDecoding.h
Normal file
73
tdfec/td/fec/algebra/InactivationDecoding.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/fec/algebra/SparseMatrixGF2.h"
|
||||
|
||||
namespace td {
|
||||
struct InactivationDecodingResult {
|
||||
uint32 size;
|
||||
vector<uint32> p_rows;
|
||||
vector<uint32> p_cols;
|
||||
};
|
||||
|
||||
class InactivationDecoding {
|
||||
public:
|
||||
InactivationDecoding(const SparseMatrixGF2 &L, uint32 PI) : L_(L), PI_(PI) {
|
||||
}
|
||||
InactivationDecodingResult run();
|
||||
|
||||
private:
|
||||
const SparseMatrixGF2 &L_;
|
||||
uint32 PI_;
|
||||
|
||||
const SparseMatrixGF2 L_rows_{L_.transpose()};
|
||||
const uint32 cols_ = L_.cols() - PI_;
|
||||
const uint32 rows_ = L_.rows();
|
||||
vector<bool> was_row_;
|
||||
vector<bool> was_col_;
|
||||
|
||||
vector<uint32> col_cnt_;
|
||||
vector<uint32> row_cnt_;
|
||||
vector<uint32> row_xor_;
|
||||
|
||||
vector<uint32> sorted_rows_;
|
||||
vector<uint32> row_cnt_offset_;
|
||||
vector<uint32> row_pos_;
|
||||
|
||||
vector<uint32> p_rows_;
|
||||
vector<uint32> p_cols_;
|
||||
vector<uint32> inactive_cols_;
|
||||
|
||||
void init();
|
||||
|
||||
void loop();
|
||||
|
||||
void check_sorted();
|
||||
|
||||
uint32 choose_col(uint32 row);
|
||||
|
||||
void inactivate_col(uint32 col);
|
||||
|
||||
void sort_rows();
|
||||
|
||||
void check(uint32 side);
|
||||
};
|
||||
} // namespace td
|
20
tdfec/td/fec/algebra/MatrixGF2.cpp
Normal file
20
tdfec/td/fec/algebra/MatrixGF2.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/fec/algebra/MatrixGF2.h"
|
||||
char disable_linker_warning_about_empty_file_matrixgf2_cpp TD_UNUSED;
|
103
tdfec/td/fec/algebra/MatrixGF2.h
Normal file
103
tdfec/td/fec/algebra/MatrixGF2.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/fec/algebra/MatrixGF256.h"
|
||||
|
||||
namespace td {
|
||||
class MatrixGF2 {
|
||||
public:
|
||||
MatrixGF2(size_t rows, size_t cols) : rows_(rows), cols_(cols) {
|
||||
CHECK(Simd::alignment() % 8 == 0);
|
||||
stride_ = ((cols_ + 7) / 8 + Simd::alignment() - 1) / Simd::alignment() * Simd::alignment();
|
||||
CHECK(stride_ * 8 >= cols_);
|
||||
storage_ = std::make_unique<uint8[]>(stride_ * rows + Simd::alignment() - 1);
|
||||
matrix_ = storage_.get();
|
||||
while (!Simd::is_aligned_pointer(matrix_)) {
|
||||
matrix_++;
|
||||
}
|
||||
CHECK(Simd::is_aligned_pointer(matrix_));
|
||||
CHECK(Simd::is_aligned_pointer(matrix_ + stride_));
|
||||
CHECK(static_cast<size_t>(matrix_ - storage_.get()) < Simd::alignment());
|
||||
}
|
||||
void set_zero() {
|
||||
std::fill(matrix_, matrix_ + stride_ * rows_, 0);
|
||||
}
|
||||
size_t rows() const {
|
||||
return rows_;
|
||||
}
|
||||
size_t cols() const {
|
||||
return cols_;
|
||||
}
|
||||
|
||||
void set_one(size_t row, size_t col) {
|
||||
DCHECK(row < rows_ && col < cols_);
|
||||
matrix_[row * stride_ + col / 8] |= uint8(1 << (col % 8));
|
||||
}
|
||||
bool get(size_t row, size_t col) const {
|
||||
DCHECK(row < rows_ && col < cols_);
|
||||
return (matrix_[row * stride_ + col / 8] & (uint8(1) << (col % 8))) != 0;
|
||||
}
|
||||
|
||||
// row(a) += row(b)
|
||||
void row_add(size_t a, size_t b) {
|
||||
row_add(row_ptr(a), row_ptr(b));
|
||||
}
|
||||
|
||||
void row_add(size_t a, Slice b) {
|
||||
DCHECK(b.size() == stride_);
|
||||
row_add(row_ptr(a), b.ubegin());
|
||||
}
|
||||
|
||||
Slice row(size_t a) const {
|
||||
return Slice(row_ptr(a), stride_);
|
||||
}
|
||||
MutableSlice row(size_t a) {
|
||||
return MutableSlice(row_ptr(a), stride_);
|
||||
}
|
||||
void row_set(size_t a, Slice b) {
|
||||
row(a).copy_from(b);
|
||||
}
|
||||
|
||||
MatrixGF256 to_gf256() const {
|
||||
MatrixGF256 res(rows(), cols());
|
||||
for (size_t i = 0; i < rows(); i++) {
|
||||
Simd::gf256_from_gf2(res.row(i).data(), row(i).data(), ((cols_ + 7) / 8 + 3) / 4 * 4);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8* matrix_;
|
||||
size_t rows_;
|
||||
size_t cols_;
|
||||
size_t stride_;
|
||||
std::unique_ptr<uint8[]> storage_;
|
||||
|
||||
uint8* row_ptr(size_t row) {
|
||||
return matrix_ + stride_ * row;
|
||||
}
|
||||
const uint8* row_ptr(size_t row) const {
|
||||
return matrix_ + stride_ * row;
|
||||
}
|
||||
void row_add(uint8* pa, const uint8* pb) {
|
||||
Simd::gf256_add(pa, pb, stride_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace td
|
20
tdfec/td/fec/algebra/MatrixGF256.cpp
Normal file
20
tdfec/td/fec/algebra/MatrixGF256.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/fec/algebra/MatrixGF256.h"
|
||||
char disable_linker_warning_about_empty_file_matrixgf256_cpp TD_UNUSED;
|
199
tdfec/td/fec/algebra/MatrixGF256.h
Normal file
199
tdfec/td/fec/algebra/MatrixGF256.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/fec/algebra/Octet.h"
|
||||
#include "td/fec/algebra/Simd.h"
|
||||
|
||||
#include "td/utils/Span.h"
|
||||
#include "td/utils/format.h"
|
||||
|
||||
namespace td {
|
||||
class MatrixGF256 {
|
||||
public:
|
||||
MatrixGF256(size_t rows, size_t cols) : rows_(rows), cols_(cols) {
|
||||
stride_ = (cols_ + Simd::alignment() - 1) / Simd::alignment() * Simd::alignment();
|
||||
storage_ = std::make_unique<uint8[]>(stride_ * rows + Simd::alignment() - 1);
|
||||
matrix_ = storage_.get();
|
||||
while (!Simd::is_aligned_pointer(matrix_)) {
|
||||
matrix_++;
|
||||
}
|
||||
CHECK(Simd::is_aligned_pointer(matrix_));
|
||||
CHECK(Simd::is_aligned_pointer(matrix_ + stride_));
|
||||
CHECK(static_cast<size_t>(matrix_ - storage_.get()) < Simd::alignment());
|
||||
}
|
||||
void set_zero() {
|
||||
std::fill(matrix_, matrix_ + stride_ * rows_, 0);
|
||||
}
|
||||
size_t rows() const {
|
||||
return rows_;
|
||||
}
|
||||
size_t cols() const {
|
||||
return cols_;
|
||||
}
|
||||
|
||||
MatrixGF256 apply_row_permutation(Span<uint32> permutation) {
|
||||
MatrixGF256 res(rows_, cols_);
|
||||
for (size_t row = 0; row < rows_; row++) {
|
||||
res.row(row).copy_from(this->row(permutation[row]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Octet get(size_t row, size_t col) const {
|
||||
DCHECK(row < rows_ && col < cols_);
|
||||
return Octet(matrix_[row * stride_ + col]);
|
||||
}
|
||||
|
||||
void set(size_t row, size_t col, Octet o) {
|
||||
DCHECK(row < rows_ && col < cols_);
|
||||
matrix_[row * stride_ + col] = o.value();
|
||||
}
|
||||
|
||||
void row_multiply(size_t row, Octet o) {
|
||||
uint8* p = row_ptr(row);
|
||||
Simd::gf256_mul(p, o.value(), stride_);
|
||||
}
|
||||
|
||||
Slice row(size_t row) const {
|
||||
return Slice(row_ptr(row), cols());
|
||||
}
|
||||
MutableSlice row(size_t row) {
|
||||
return MutableSlice(row_ptr(row), cols());
|
||||
}
|
||||
|
||||
template <class M>
|
||||
void set_from(const M& m, size_t row_offset, size_t col_offset) {
|
||||
auto to = block_view(row_offset, col_offset, rows() - row_offset, cols() - col_offset);
|
||||
for (size_t i = 0; i < m.rows(); i++) {
|
||||
to.row(i).copy_from(m.row(i));
|
||||
}
|
||||
}
|
||||
|
||||
MatrixGF256 copy() {
|
||||
MatrixGF256 res(rows(), cols());
|
||||
res.set_from(*this, 0, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
void add(const MatrixGF256& m) {
|
||||
CHECK(m.rows() == rows());
|
||||
CHECK(m.cols() == cols());
|
||||
for (size_t i = 0; i < m.rows(); i++) {
|
||||
auto* to = row_ptr(i);
|
||||
auto* from = m.row_ptr(i);
|
||||
row_add(to, from);
|
||||
}
|
||||
}
|
||||
|
||||
// row(a) += row(b) * m
|
||||
void row_add_mul(size_t a, size_t b, Octet m) {
|
||||
row_add_mul(row_ptr(a), row_ptr(b), m);
|
||||
}
|
||||
void row_add_mul(size_t a, Slice b, Octet m) {
|
||||
row_add_mul(row_ptr(a), b.ubegin(), m);
|
||||
}
|
||||
|
||||
// row(a) += row(b)
|
||||
void row_add(size_t a, size_t b) {
|
||||
row_add(row_ptr(a), row_ptr(b));
|
||||
}
|
||||
|
||||
void row_add(size_t a, Slice b) {
|
||||
row_add(row_ptr(a), b.ubegin());
|
||||
}
|
||||
|
||||
void row_set(size_t a, Slice b) {
|
||||
row(a).copy_from(b);
|
||||
}
|
||||
|
||||
class BlockView {
|
||||
public:
|
||||
BlockView(size_t row_offset, size_t col_offset, size_t row_size, size_t col_size, MatrixGF256& m)
|
||||
: row_offset_(row_offset), col_offset_(col_offset), row_size_(row_size), col_size_(col_size), m_(m) {
|
||||
}
|
||||
size_t cols() const {
|
||||
return col_size_;
|
||||
}
|
||||
size_t rows() const {
|
||||
return row_size_;
|
||||
}
|
||||
Slice row(size_t row) const {
|
||||
return m_.row(row_offset_ + row).remove_prefix(col_offset_);
|
||||
}
|
||||
MutableSlice row(size_t row) {
|
||||
return m_.row(row_offset_ + row).remove_prefix(col_offset_);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t row_offset_;
|
||||
size_t col_offset_;
|
||||
size_t row_size_;
|
||||
size_t col_size_;
|
||||
MatrixGF256& m_;
|
||||
};
|
||||
|
||||
BlockView block_view(size_t row_offset, size_t col_offset, size_t row_size, size_t col_size) {
|
||||
return BlockView(row_offset, col_offset, row_size, col_size, *this);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8* matrix_;
|
||||
size_t rows_;
|
||||
size_t cols_;
|
||||
size_t stride_;
|
||||
std::unique_ptr<uint8[]> storage_;
|
||||
|
||||
uint8* row_ptr(size_t row) {
|
||||
return matrix_ + stride_ * row;
|
||||
}
|
||||
const uint8* row_ptr(size_t row) const {
|
||||
return matrix_ + stride_ * row;
|
||||
}
|
||||
|
||||
void row_add_mul(uint8* ap, const uint8* bp, Octet m) {
|
||||
uint8 u = m.value();
|
||||
if (u == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (u == 1) {
|
||||
return row_add(ap, bp);
|
||||
}
|
||||
|
||||
Simd::gf256_add_mul(ap, bp, u, stride_);
|
||||
}
|
||||
|
||||
void row_add(uint8* ap, const uint8* bp) {
|
||||
Simd::gf256_add(ap, bp, stride_);
|
||||
}
|
||||
};
|
||||
|
||||
inline StringBuilder& operator<<(StringBuilder& sb, const MatrixGF256& m) {
|
||||
sb << "\n";
|
||||
for (uint32 i = 0; i < m.rows(); i++) {
|
||||
auto row = m.row(i);
|
||||
for (uint32 j = 0; j < m.cols(); j++) {
|
||||
uint8 x = row[j];
|
||||
sb << " " << format::hex_digit(x / 16) << format::hex_digit(x % 16);
|
||||
}
|
||||
sb << "\n";
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
} // namespace td
|
9242
tdfec/td/fec/algebra/Octet.cpp
Normal file
9242
tdfec/td/fec/algebra/Octet.cpp
Normal file
File diff suppressed because it is too large
Load diff
152
tdfec/td/fec/algebra/Octet.h
Normal file
152
tdfec/td/fec/algebra/Octet.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
#include <array>
|
||||
#include <iomanip>
|
||||
|
||||
namespace td {
|
||||
|
||||
class Octet {
|
||||
public:
|
||||
Octet() = default;
|
||||
|
||||
explicit Octet(const uint8 val) : data_(val) {
|
||||
}
|
||||
|
||||
uint8 value() const {
|
||||
return data_;
|
||||
}
|
||||
Octet& operator+=(const Octet a) {
|
||||
data_ ^= a.data_;
|
||||
return *this;
|
||||
}
|
||||
friend Octet operator+(Octet lhs, const Octet rhs) {
|
||||
return lhs += rhs;
|
||||
}
|
||||
|
||||
Octet& operator-=(const Octet a) {
|
||||
return *this += a;
|
||||
}
|
||||
friend Octet operator-(Octet lhs, const Octet rhs) {
|
||||
return lhs + rhs;
|
||||
}
|
||||
|
||||
Octet& operator*=(const Octet a) {
|
||||
if (data_ != 0 && a.data_ != 0) {
|
||||
data_ = oct_exp(oct_log(uint8(data_ - 1)) + oct_log(uint8(a.data_ - 1)));
|
||||
} else {
|
||||
data_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
friend Octet operator*(Octet lhs, const Octet rhs) {
|
||||
return lhs *= rhs;
|
||||
}
|
||||
|
||||
Octet& operator/=(const Octet a) {
|
||||
if (a.data_ != 0 && data_ != 0) {
|
||||
data_ = oct_exp(oct_log(uint8(data_ - 1)) - oct_log(uint8(a.data_ - 1)) + 255);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend Octet operator/(Octet lhs, const Octet rhs) {
|
||||
return lhs /= rhs;
|
||||
}
|
||||
|
||||
Octet inverse() const {
|
||||
return Octet(oct_exp(255 - oct_log(uint8(data_ - 1))));
|
||||
}
|
||||
|
||||
bool operator==(const Octet a) const {
|
||||
return data_ == a.data_;
|
||||
}
|
||||
bool operator!=(const Octet a) const {
|
||||
return data_ != a.data_;
|
||||
}
|
||||
bool operator<(const Octet a) const {
|
||||
return data_ < a.data_;
|
||||
}
|
||||
bool operator>(const Octet a) const {
|
||||
return data_ > a.data_;
|
||||
}
|
||||
bool is_zero() const {
|
||||
return data_ == 0;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Octet m) {
|
||||
os << std::hex << static_cast<uint32>(m.data_);
|
||||
return os;
|
||||
}
|
||||
static constexpr uint8 oct_exp(uint32 data) {
|
||||
constexpr std::array<uint8, 510> precalc = {
|
||||
{1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117,
|
||||
234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119,
|
||||
238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190,
|
||||
97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127,
|
||||
254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189,
|
||||
103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92,
|
||||
184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146,
|
||||
57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255,
|
||||
227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141,
|
||||
7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86,
|
||||
172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88,
|
||||
176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4, 8, 16, 32, 64, 128, 29,
|
||||
58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96,
|
||||
192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20,
|
||||
40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137,
|
||||
15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217,
|
||||
175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199,
|
||||
147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132,
|
||||
21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191,
|
||||
99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149,
|
||||
55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83,
|
||||
166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61,
|
||||
122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108,
|
||||
216, 173, 71, 142}};
|
||||
return precalc[data];
|
||||
}
|
||||
|
||||
static constexpr uint8 oct_log(uint8 data) {
|
||||
constexpr std::array<uint8, 255> precalc = {
|
||||
{0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239,
|
||||
129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240,
|
||||
18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139,
|
||||
98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241,
|
||||
210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186,
|
||||
61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140,
|
||||
128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146,
|
||||
217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242,
|
||||
86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164,
|
||||
118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187,
|
||||
204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213,
|
||||
233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175}};
|
||||
return precalc[data];
|
||||
}
|
||||
|
||||
static const uint8 OctMulLo[256][16];
|
||||
static const uint8 OctMulHi[256][16];
|
||||
|
||||
private:
|
||||
uint8 data_;
|
||||
};
|
||||
|
||||
} // namespace td
|
266
tdfec/td/fec/algebra/Simd.h
Normal file
266
tdfec/td/fec/algebra/Simd.h
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
#include "td/fec/algebra/Octet.h"
|
||||
|
||||
#if __SSSE3__
|
||||
#define TD_SSE3 1
|
||||
#endif
|
||||
|
||||
#if __AVX2__
|
||||
#define TD_AVX2 1
|
||||
#define TD_SSE3 1
|
||||
#endif
|
||||
|
||||
#if TD_AVX2
|
||||
#include <immintrin.h> /* avx2 */
|
||||
#elif TD_SSE3
|
||||
#include <tmmintrin.h> /* ssse3 */
|
||||
#endif
|
||||
|
||||
namespace td {
|
||||
class Simd_null {
|
||||
public:
|
||||
static constexpr size_t alignment() {
|
||||
return 32; // gf256_from_gf2 relies on 32 alignment
|
||||
}
|
||||
|
||||
static std::string get_name() {
|
||||
return "Without simd";
|
||||
}
|
||||
static bool is_aligned_pointer(const void *ptr) {
|
||||
return ::td::is_aligned_pointer<alignment()>(ptr);
|
||||
}
|
||||
|
||||
static void gf256_add(void *a, const void *b, size_t size) {
|
||||
DCHECK(is_aligned_pointer(a));
|
||||
DCHECK(is_aligned_pointer(b));
|
||||
uint8 *ap = reinterpret_cast<uint8 *>(a);
|
||||
const uint8 *bp = reinterpret_cast<const uint8 *>(b);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
ap[i] ^= bp[i];
|
||||
}
|
||||
}
|
||||
static void gf256_mul(void *a, uint8 u, size_t size) {
|
||||
DCHECK(is_aligned_pointer(a));
|
||||
uint8 *ap = reinterpret_cast<uint8 *>(a);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
ap[i] = (Octet(ap[i]) * Octet(u)).value();
|
||||
}
|
||||
}
|
||||
static void gf256_add_mul(void *a, const void *b, uint8 u, size_t size) {
|
||||
DCHECK(is_aligned_pointer(a));
|
||||
DCHECK(is_aligned_pointer(b));
|
||||
uint8 *ap = reinterpret_cast<uint8 *>(a);
|
||||
const uint8 *bp = reinterpret_cast<const uint8 *>(b);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
ap[i] = (Octet(ap[i]) + Octet(bp[i]) * Octet(u)).value();
|
||||
}
|
||||
}
|
||||
|
||||
static void gf256_from_gf2(void *a, const void *b, size_t size) {
|
||||
uint8 *ap = reinterpret_cast<uint8 *>(a);
|
||||
const uint8 *bp = reinterpret_cast<const uint8 *>(b);
|
||||
size *= 8;
|
||||
for (size_t i = 0; i < size; i++, ap++) {
|
||||
*ap = (bp[i / 8] >> (i % 8)) & 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if TD_SSE3
|
||||
class Simd_sse : public Simd_null {
|
||||
public:
|
||||
static constexpr size_t alignment() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
static std::string get_name() {
|
||||
return "With SSE";
|
||||
}
|
||||
|
||||
static bool is_aligned_pointer(const void *ptr) {
|
||||
return ::td::is_aligned_pointer<alignment()>(ptr);
|
||||
}
|
||||
|
||||
static void gf256_add(void *a, const void *b, size_t size) {
|
||||
DCHECK(is_aligned_pointer(a));
|
||||
DCHECK(is_aligned_pointer(b));
|
||||
uint8 *ap = reinterpret_cast<uint8 *>(a);
|
||||
const uint8 *bp = reinterpret_cast<const uint8 *>(b);
|
||||
__m128i *ap128 = reinterpret_cast<__m128i *>(ap);
|
||||
const __m128i *bp128 = reinterpret_cast<const __m128i *>(bp);
|
||||
for (size_t idx = 0; idx < size; idx += 16) {
|
||||
_mm_storeu_si128(ap128, _mm_xor_si128(_mm_loadu_si128(ap128), _mm_loadu_si128(bp128)));
|
||||
ap128++;
|
||||
bp128++;
|
||||
}
|
||||
}
|
||||
static void gf256_mul(void *a, uint8 u, size_t size) {
|
||||
DCHECK(is_aligned_pointer(a));
|
||||
uint8 *ap = reinterpret_cast<uint8 *>(a);
|
||||
|
||||
const __m128i mask = _mm_set1_epi8(0x0f);
|
||||
const __m128i urow_hi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(Octet::OctMulHi[u]));
|
||||
const __m128i urow_lo = _mm_loadu_si128(reinterpret_cast<const __m128i *>(Octet::OctMulLo[u]));
|
||||
|
||||
__m128i *ap128 = reinterpret_cast<__m128i *>(ap);
|
||||
for (size_t idx = 0; idx < size; idx += 16) {
|
||||
__m128i ax = _mm_loadu_si128(ap128);
|
||||
__m128i lo = _mm_and_si128(ax, mask);
|
||||
ax = _mm_srli_epi64(ax, 4);
|
||||
__m128i hi = _mm_and_si128(ax, mask);
|
||||
lo = _mm_shuffle_epi8(urow_lo, lo);
|
||||
hi = _mm_shuffle_epi8(urow_hi, hi);
|
||||
|
||||
_mm_storeu_si128(ap128, _mm_xor_si128(lo, hi));
|
||||
ap128++;
|
||||
}
|
||||
}
|
||||
static void gf256_add_mul(void *a, const void *b, uint8 u, size_t size) {
|
||||
DCHECK(is_aligned_pointer(a));
|
||||
DCHECK(is_aligned_pointer(b));
|
||||
uint8 *ap = reinterpret_cast<uint8 *>(a);
|
||||
const uint8 *bp = reinterpret_cast<const uint8 *>(b);
|
||||
|
||||
const __m128i mask = _mm_set1_epi8(0x0f);
|
||||
const __m128i urow_hi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(Octet::OctMulHi[u]));
|
||||
const __m128i urow_lo = _mm_loadu_si128(reinterpret_cast<const __m128i *>(Octet::OctMulLo[u]));
|
||||
|
||||
__m128i *ap128 = reinterpret_cast<__m128i *>(ap);
|
||||
const __m128i *bp128 = reinterpret_cast<const __m128i *>(bp);
|
||||
for (size_t idx = 0; idx < size; idx += 16) {
|
||||
__m128i bx = _mm_loadu_si128(bp128++);
|
||||
__m128i lo = _mm_and_si128(bx, mask);
|
||||
bx = _mm_srli_epi64(bx, 4);
|
||||
__m128i hi = _mm_and_si128(bx, mask);
|
||||
lo = _mm_shuffle_epi8(urow_lo, lo);
|
||||
hi = _mm_shuffle_epi8(urow_hi, hi);
|
||||
|
||||
_mm_storeu_si128(ap128, _mm_xor_si128(_mm_loadu_si128(ap128), _mm_xor_si128(lo, hi)));
|
||||
ap128++;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // SSSE3
|
||||
|
||||
#ifdef TD_AVX2
|
||||
class Simd_avx : public Simd_sse {
|
||||
public:
|
||||
static std::string get_name() {
|
||||
return "With AVX";
|
||||
}
|
||||
|
||||
static void gf256_add(void *a, const void *b, size_t size) {
|
||||
DCHECK(is_aligned_pointer(a));
|
||||
DCHECK(is_aligned_pointer(b));
|
||||
uint8 *ap = reinterpret_cast<uint8 *>(a);
|
||||
const uint8 *bp = reinterpret_cast<const uint8 *>(b);
|
||||
__m256i *ap256 = reinterpret_cast<__m256i *>(ap);
|
||||
const __m256i *bp256 = reinterpret_cast<const __m256i *>(bp);
|
||||
for (size_t idx = 0; idx < size; idx += 32) {
|
||||
_mm256_storeu_si256(ap256, _mm256_xor_si256(_mm256_loadu_si256(ap256), _mm256_loadu_si256(bp256)));
|
||||
ap256++;
|
||||
bp256++;
|
||||
}
|
||||
}
|
||||
|
||||
static __m256i get_mask(const uint32 mask) {
|
||||
// abcd -> abcd * 8
|
||||
__m256i vmask(_mm256_set1_epi32(mask));
|
||||
|
||||
// abcd * 8 -> aaaaaaaabbbbbbbbccccccccdddddddd
|
||||
const __m256i shuffle(
|
||||
_mm256_setr_epi64x(0x0000000000000000, 0x0101010101010101, 0x0202020202020202, 0x0303030303030303));
|
||||
vmask = _mm256_shuffle_epi8(vmask, shuffle);
|
||||
|
||||
const __m256i bit_mask(_mm256_set1_epi64x(0x7fbfdfeff7fbfdfe));
|
||||
vmask = _mm256_or_si256(vmask, bit_mask);
|
||||
return _mm256_and_si256(_mm256_cmpeq_epi8(vmask, _mm256_set1_epi64x(-1)), _mm256_set1_epi8(1));
|
||||
}
|
||||
|
||||
static void gf256_from_gf2(void *a, const void *b, size_t size) {
|
||||
DCHECK(is_aligned_pointer(a));
|
||||
DCHECK(size % 4 == 0);
|
||||
__m256i *ap256 = reinterpret_cast<__m256i *>(a);
|
||||
const uint32 *bp = reinterpret_cast<const uint32 *>(b);
|
||||
size /= 4;
|
||||
for (size_t i = 0; i < size; i++, bp++, ap256++) {
|
||||
*ap256 = get_mask(*bp);
|
||||
}
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) void gf256_mul(void *a, uint8 u, size_t size) {
|
||||
const __m128i urow_hi_small = _mm_load_si128(reinterpret_cast<const __m128i *>(Octet::OctMulHi[u]));
|
||||
const __m256i urow_hi = _mm256_broadcastsi128_si256(urow_hi_small);
|
||||
const __m128i urow_lo_small = _mm_load_si128(reinterpret_cast<const __m128i *>(Octet::OctMulLo[u]));
|
||||
const __m256i urow_lo = _mm256_broadcastsi128_si256(urow_lo_small);
|
||||
|
||||
const __m256i mask = _mm256_set1_epi8(0x0f);
|
||||
__m256i *ap256 = (__m256i *)a;
|
||||
for (size_t idx = 0; idx < size; idx += 32) {
|
||||
__m256i ax = _mm256_load_si256(ap256);
|
||||
__m256i lo = _mm256_and_si256(ax, mask);
|
||||
ax = _mm256_srli_epi64(ax, 4);
|
||||
__m256i hi = _mm256_and_si256(ax, mask);
|
||||
lo = _mm256_shuffle_epi8(urow_lo, lo);
|
||||
hi = _mm256_shuffle_epi8(urow_hi, hi);
|
||||
|
||||
_mm256_store_si256(ap256, _mm256_xor_si256(lo, hi));
|
||||
ap256++;
|
||||
}
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) void gf256_add_mul(void *a, const void *b, uint8 u, size_t size) {
|
||||
const __m128i urow_hi_small = _mm_load_si128(reinterpret_cast<const __m128i *>(Octet::OctMulHi[u]));
|
||||
const __m256i urow_hi = _mm256_broadcastsi128_si256(urow_hi_small);
|
||||
const __m128i urow_lo_small = _mm_load_si128(reinterpret_cast<const __m128i *>(Octet::OctMulLo[u]));
|
||||
const __m256i urow_lo = _mm256_broadcastsi128_si256(urow_lo_small);
|
||||
|
||||
const __m256i mask = _mm256_set1_epi8(0x0f);
|
||||
__m256i *ap256 = (__m256i *)a;
|
||||
const __m256i *bp256 = (const __m256i *)b;
|
||||
for (size_t idx = 0; idx < size; idx += 32) {
|
||||
__m256i bx = _mm256_load_si256(bp256++);
|
||||
__m256i lo = _mm256_and_si256(bx, mask);
|
||||
bx = _mm256_srli_epi64(bx, 4);
|
||||
__m256i hi = _mm256_and_si256(bx, mask);
|
||||
lo = _mm256_shuffle_epi8(urow_lo, lo);
|
||||
hi = _mm256_shuffle_epi8(urow_hi, hi);
|
||||
|
||||
_mm256_store_si256(ap256, _mm256_xor_si256(_mm256_load_si256(ap256), _mm256_xor_si256(lo, hi)));
|
||||
ap256++;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // AVX2
|
||||
|
||||
#if TD_AVX2
|
||||
using Simd = Simd_avx;
|
||||
#elif TD_SSE3
|
||||
using Simd = Simd_sse;
|
||||
#else
|
||||
using Simd = Simd_null;
|
||||
#endif
|
||||
|
||||
} // namespace td
|
20
tdfec/td/fec/algebra/SparseMatrixGF2.cpp
Normal file
20
tdfec/td/fec/algebra/SparseMatrixGF2.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/fec/algebra/SparseMatrixGF2.h"
|
||||
char disable_linker_warning_about_empty_file_sparsematrixgf2_cpp TD_UNUSED;
|
277
tdfec/td/fec/algebra/SparseMatrixGF2.h
Normal file
277
tdfec/td/fec/algebra/SparseMatrixGF2.h
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/fec/algebra/MatrixGF2.h"
|
||||
|
||||
namespace td {
|
||||
inline std::vector<uint32> inverse_permutation(Span<uint32> p) {
|
||||
std::vector<uint32> res(p.size());
|
||||
for (size_t i = 0; i < p.size(); i++) {
|
||||
res[p[i]] = narrow_cast<uint32>(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
class IdentityGenerator {
|
||||
public:
|
||||
IdentityGenerator(uint32 N) : N(N) {
|
||||
}
|
||||
template <class F>
|
||||
void generate(F&& f) const {
|
||||
for (uint32 col = 0; col < N; col++) {
|
||||
f(col, col);
|
||||
}
|
||||
}
|
||||
uint32 non_zeroes() const {
|
||||
return N;
|
||||
}
|
||||
|
||||
uint32 cols() const {
|
||||
return N;
|
||||
}
|
||||
uint32 rows() const {
|
||||
return N;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 N;
|
||||
};
|
||||
|
||||
template <class GeneratorT>
|
||||
class PermutationGenerator {
|
||||
public:
|
||||
PermutationGenerator(const GeneratorT& m, Span<uint32> p) : m_(m), p_(inverse_permutation(p)) {
|
||||
}
|
||||
uint32 non_zeroes() const {
|
||||
return m_.non_zeroes();
|
||||
}
|
||||
uint32 rows() const {
|
||||
return m_.rows();
|
||||
}
|
||||
uint32 cols() const {
|
||||
return m_.cols();
|
||||
}
|
||||
template <class F>
|
||||
void generate(F&& f) const {
|
||||
m_.generate([&f, this](auto row, auto col) { f(row, p_[col]); });
|
||||
}
|
||||
|
||||
private:
|
||||
const GeneratorT& m_;
|
||||
std::vector<uint32> p_;
|
||||
};
|
||||
|
||||
template <class GeneratorT>
|
||||
class TransposeGenerator {
|
||||
public:
|
||||
explicit TransposeGenerator(const GeneratorT& m) : m_(m) {
|
||||
}
|
||||
uint32 non_zeroes() const {
|
||||
return m_.non_zeroes();
|
||||
}
|
||||
uint32 rows() const {
|
||||
return m_.cols();
|
||||
}
|
||||
uint32 cols() const {
|
||||
return m_.rows();
|
||||
}
|
||||
template <class F>
|
||||
void generate(F&& f) const {
|
||||
m_.generate([&f](auto row, auto col) { f(col, row); });
|
||||
}
|
||||
|
||||
private:
|
||||
const GeneratorT& m_;
|
||||
std::vector<uint32> p_;
|
||||
};
|
||||
class SparseMatrixGF2 {
|
||||
public:
|
||||
uint32 non_zeroes() const {
|
||||
return narrow_cast<uint32>(data_.size());
|
||||
}
|
||||
Span<uint32> col(uint32 i) const {
|
||||
return Span<uint32>(data_.data() + col_offset_[i], col_size(i));
|
||||
}
|
||||
uint32 col_size(uint32 i) const {
|
||||
return col_offset_[i + 1] - col_offset_[i];
|
||||
}
|
||||
uint32 cols() const {
|
||||
return cols_;
|
||||
}
|
||||
uint32 rows() const {
|
||||
return rows_;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void generate(F&& f) const {
|
||||
return block_for_each(0, 0, rows_, cols_, f);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void block_for_each(uint32 row_from, uint32 col_from, uint32 row_size, uint32 col_size, F&& f) const {
|
||||
auto col_till = col_from + col_size;
|
||||
auto row_till = row_from + row_size;
|
||||
for (uint32 col_i = col_from; col_i < col_till; col_i++) {
|
||||
auto col_span = col(col_i);
|
||||
auto* it = row_from == 0 ? col_span.begin() : std::lower_bound(col_span.begin(), col_span.end(), row_from);
|
||||
while (it != col_span.end() && *it < row_till) {
|
||||
f(*it - row_from, col_i - col_from);
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MatrixGF2 block_dense(uint32 row_from, uint32 col_from, uint32 row_size, uint32 col_size) const {
|
||||
MatrixGF2 res(row_size, col_size);
|
||||
res.set_zero();
|
||||
block_for_each(row_from, col_from, row_size, col_size, [&](auto row, auto col) { res.set_one(row, col); });
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class GeneratorT>
|
||||
explicit SparseMatrixGF2(GeneratorT&& generator) : rows_(generator.rows()), cols_(generator.cols()) {
|
||||
data_.resize(generator.non_zeroes());
|
||||
col_offset_.resize(cols_ + 1, 0);
|
||||
generator.generate([&](uint32 row, uint32 col) {
|
||||
LOG_DCHECK(row < rows_ && col < cols_) << "(" << row << "," << col << ") (" << rows_ << "," << cols_ << ")";
|
||||
col_offset_[col + 1]++;
|
||||
});
|
||||
for (uint32 i = 1; i < col_offset_.size(); i++) {
|
||||
col_offset_[i] += col_offset_[i - 1];
|
||||
}
|
||||
auto col_pos = col_offset_;
|
||||
generator.generate([&](uint32 row, uint32 col) { data_[col_pos[col]++] = row; });
|
||||
|
||||
for (uint32 col_i = 0; col_i < cols_; col_i++) {
|
||||
auto c = col(col_i);
|
||||
for (size_t j = 1; j < c.size(); j++) {
|
||||
LOG_DCHECK(c[j] > c[j - 1]) << c[j] << " > " << c[j - 1] << tag("row", col_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BlockView {
|
||||
public:
|
||||
BlockView(uint32 row_offset, uint32 col_offset, uint32 row_size, uint32 col_size, const SparseMatrixGF2& m)
|
||||
: row_offset_(row_offset), col_offset_(col_offset), row_size_(row_size), col_size_(col_size), m_(m) {
|
||||
}
|
||||
uint32 cols() const {
|
||||
return col_size_;
|
||||
}
|
||||
uint32 rows() const {
|
||||
return row_size_;
|
||||
}
|
||||
uint32 non_zeroes() const {
|
||||
uint32 res = 0;
|
||||
m_.block_for_each(row_offset_, col_offset_, row_size_, col_size_, [&res](auto row, auto col) { res++; });
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void generate(F&& f) const {
|
||||
m_.block_for_each(row_offset_, col_offset_, row_size_, col_size_, [&f](auto row, auto col) { f(row, col); });
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 row_offset_;
|
||||
uint32 col_offset_;
|
||||
uint32 row_size_;
|
||||
uint32 col_size_;
|
||||
const SparseMatrixGF2& m_;
|
||||
};
|
||||
|
||||
SparseMatrixGF2 block_sparse(uint32 row_from, uint32 col_from, uint32 row_size, uint32 col_size) const {
|
||||
return SparseMatrixGF2(BlockView(row_from, col_from, row_size, col_size, *this));
|
||||
}
|
||||
SparseMatrixGF2 transpose() const {
|
||||
return SparseMatrixGF2(TransposeGenerator<SparseMatrixGF2>(*this));
|
||||
}
|
||||
|
||||
SparseMatrixGF2 apply_col_permutation(Span<uint32> p) const {
|
||||
return SparseMatrixGF2(PermutationGenerator<SparseMatrixGF2>(*this, p));
|
||||
}
|
||||
SparseMatrixGF2 apply_row_permutation(Span<uint32> p) const {
|
||||
return transpose().apply_col_permutation(p).transpose();
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 rows_{0};
|
||||
uint32 cols_{0};
|
||||
std::vector<uint32> data_;
|
||||
std::vector<uint32> col_offset_;
|
||||
};
|
||||
|
||||
template <class M>
|
||||
M operator*(const SparseMatrixGF2& a, const M& b) {
|
||||
M res(a.rows(), b.cols());
|
||||
res.set_zero();
|
||||
a.generate([&](auto row, auto col) { res.row_add(row, b.row(col)); });
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class... ArgsT>
|
||||
class BlockGenerator {
|
||||
public:
|
||||
BlockGenerator(uint32 rows, uint32 cols, ArgsT&&... args)
|
||||
: rows_(rows), cols_(cols), tuple_(std::forward_as_tuple(std::forward<ArgsT>(args)...)) {
|
||||
}
|
||||
template <class F>
|
||||
void generate(F&& f) const {
|
||||
uint32 row_offset = 0;
|
||||
uint32 next_row_offset = 0;
|
||||
uint32 col_offset = 0;
|
||||
tuple_for_each(tuple_, [&](auto& g) {
|
||||
if (col_offset == 0) {
|
||||
next_row_offset = row_offset + g.rows();
|
||||
} else {
|
||||
CHECK(next_row_offset == row_offset + g.rows());
|
||||
}
|
||||
g.generate([&](auto row, auto col) { f(row_offset + row, col_offset + col); });
|
||||
col_offset += g.cols();
|
||||
if (col_offset >= cols_) {
|
||||
CHECK(col_offset == cols_);
|
||||
col_offset = 0;
|
||||
row_offset = next_row_offset;
|
||||
}
|
||||
});
|
||||
}
|
||||
uint32 non_zeroes() const {
|
||||
uint32 res = 0;
|
||||
tuple_for_each(tuple_, [&](auto& g) { res += g.non_zeroes(); });
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32 cols() const {
|
||||
return cols_;
|
||||
}
|
||||
uint32 rows() const {
|
||||
return rows_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 rows_;
|
||||
uint32 cols_;
|
||||
std::tuple<ArgsT...> tuple_;
|
||||
};
|
||||
|
||||
template <class... ArgsT>
|
||||
auto block_generator(uint32 rows, uint32 cols, ArgsT&&... args) {
|
||||
return BlockGenerator<ArgsT...>(rows, cols, std::forward<ArgsT>(args)...);
|
||||
}
|
||||
} // namespace td
|
Loading…
Add table
Add a link
Reference in a new issue