diff --git a/src/core/functions.h b/src/core/functions.h index bb9c03a..44010be 100644 --- a/src/core/functions.h +++ b/src/core/functions.h @@ -13,6 +13,7 @@ #include #include "gf2.h" +#include "sparse.h" #define TIME_PROF(log, exec, unit) \ do \ diff --git a/src/core/sparse.h b/src/core/sparse.h new file mode 100644 index 0000000..f2e9bbb --- /dev/null +++ b/src/core/sparse.h @@ -0,0 +1,147 @@ +#pragma once + +#include +#include +#include + +namespace ldpc +{ + template + struct edge + { + int rowIndex; + int colIndex; + T value; + }; + + struct node + { + int nodeIndex; + int edgeIndex; + }; + + /** + * @brief Sparse matrix with minimal functionality required for encoding/decoding + * LDPC codes and other linear block codes. + * + * @tparam T finite field + */ + template + class sparse_csr + { + public: + sparse_csr() = default; + sparse_csr(const int m, const int n) + : numCols(n), + numRows(m), + colN(numCols, std::vector()), + rowN(numRows, std::vector()) + { + } + + void read_from_file(const std::string &filename, int skipLines); + + std::vector multiply_left(const std::vector &left); // for encoding + std::vector multiply_right(const std::vector &right); // for syndrome + + const int num_cols() const { return numCols; } + const int num_rows() const { return numRows; } + const std::vector> &col_neighbor() const { return colN; } + const std::vector> &row_neighbor() const { return rowN; } + const std::vector> &nz_entry() const { return nonZeroVals; } + + private: + int numCols; // number of columns + int numRows; // number of rows + std::vector> colN; // column neighbors, with row and edge index + std::vector> rowN; // row neigbors, with col and edge index + std::vector> nonZeroVals; // edges, i.e. non-zero entries with row and col index + }; + + template + void sparse_csr::read_from_file(const std::string &filename, int skipLines) + { + int index = 0; + + std::ifstream infile(filename); + std::string line; + + // skip lines at beginning of file + while (skipLines-- > 0) + { + std::getline(infile, line); + } + + while (getline(infile, line)) + { + edge entry; + + std::istringstream record(line); + record >> entry.rowIndex; + record >> entry.colIndex; + + // no value is given + if (record) + { + record >> entry.value; + } + else + { + entry.value = T(1); + } + + nonZeroVals.push_back(entry); + + colN[entry.colIndex].push_back(node({entry.rowIndex, index})); + rowN[entry.rowIndex].push_back(node({entry.colIndex, index})); + + ++index; + } + } + + /** + * @brief Multiply vector from left handside with matrix over field T + * + * @tparam T finite field + * @param left Row vector + * @return std::vector + */ + template + std::vector sparse_csr::multiply_left(const std::vector &left) + { + std::vector result(numCols); + + for (int j = 0; j < numCols; ++j) + { + for (const auto &n : colN[j]) + { + result[j] += left[n.nodeIndex] * nonZeroVals[n.edgeIndex].value; + } + } + + return result; + } + + /** + * @brief Multiply vector from right handside with matrix over field T + * + * @tparam T finite field + * @param right Column vector + * @return std::vector + */ + template + std::vector sparse_csr::multiply_right(const std::vector &right) + { + std::vector result(numRows); + + for (int i = 0; i < numRows; ++i) + { + for (const auto &n : rowN[i]) + { + result[i] += right[n.nodeIndex] * nonZeroVals[n.edgeIndex].value; + } + } + + return result; + } +} // namespace ldpc diff --git a/src/sim_cpu.cpp b/src/sim_cpu.cpp index 504ee9e..43f3887 100644 --- a/src/sim_cpu.cpp +++ b/src/sim_cpu.cpp @@ -5,7 +5,7 @@ int main(int argc, char *argv[]) { argparse::ArgumentParser parser("ldpc_sim"); - parser.add_argument("codefile").help("LDPC codefile containing all non-zero entries, column major ordering."); + parser.add_argument("codefile").help("LDPC codefile containing all non-zero entries, compressed sparse row (CSR) format."); parser.add_argument("output-file").help("Results output file."); parser.add_argument("snr-range").help("{MIN} {MAX} {STEP}").nargs(3).action([](const std::string &s) { return std::stod(s); });