From 066d9d85d2e315235312296580f3c9ad64d404eb Mon Sep 17 00:00:00 2001 From: Andreas Tsouchlos Date: Fri, 25 Nov 2022 14:00:19 +0100 Subject: [PATCH] Finished cpp proximal decoder implementation --- .gitignore | 2 ++ sw/cpp/CMakeLists.txt | 21 ++++++++++++-- sw/cpp/src/cpp_decoders.cpp | 58 ++++++++----------------------------- 3 files changed, 33 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 987729f..29c1db1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ latex/build/ latex/tmp/ sw/cpp_modules sw/cpp/build +sw/cpp/cmake-build-debug +sw/cpp/cmake-build-release sw/sim_saves/ .idea __pycache__ diff --git a/sw/cpp/CMakeLists.txt b/sw/cpp/CMakeLists.txt index 95869fc..f1ef167 100644 --- a/sw/cpp/CMakeLists.txt +++ b/sw/cpp/CMakeLists.txt @@ -1,14 +1,31 @@ cmake_minimum_required (VERSION 3.0) project(cpp_decoders) - + + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE + Release + CACHE STRING "Choose the type of build." FORCE) + set_property( + CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release") +endif() + +set(CMAKE_CXX_STANDARD 23) + find_package(Eigen3 3.3 REQUIRED NO_MODULE) find_package(pybind11 CONFIG REQUIRED) include_directories(${pybind11_INCLUDE_DIRS}) +find_package(OpenMP REQUIRED) + pybind11_add_module(cpp_decoders src/cpp_decoders.cpp) -target_link_libraries(cpp_decoders PRIVATE Eigen3::Eigen) +target_link_libraries(cpp_decoders PRIVATE Eigen3::Eigen OpenMP::OpenMP_CXX) set(INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cpp_modules) diff --git a/sw/cpp/src/cpp_decoders.cpp b/sw/cpp/src/cpp_decoders.cpp index e7f102e..bb519bf 100644 --- a/sw/cpp/src/cpp_decoders.cpp +++ b/sw/cpp/src/cpp_decoders.cpp @@ -1,53 +1,14 @@ -#include +#include #include + #include #include #include #include +#include -/* - - import numpy as np - - -class ProximalDecoder: - """Class implementing the Proximal Decoding algorithm. See "Proximal - Decoding for LDPC Codes" - by Tadashi Wadayama, and Satoshi Takabe. - """ - - def decode(self, y: np.array) -> np.array: - """Decode a received signal. The algorithm is detailed in 3.2, p.3. - - This function assumes a BPSK modulated signal and an AWGN channel. - - :param y: Vector of received values. (y = x + w, where 'x' is - element of [-1, 1]^n and 'w' is noise) - :return: Most probably sent codeword (element of [0, 1]^n). If - decoding fails, the returned value is 'None' - """ - s = np.zeros(self._n) - x_hat = np.zeros(self._n) - for k in range(self._K): - r = s - self._step_size * self._L_awgn(s, y) - - s = r - self._gamma * self._grad_h(r) - s = self._projection(s) # Equation (15) - - x_hat = np.sign(s) - - # Map the codeword from [ -1, 1]^n to [0, 1]^n - x_hat = (x_hat == -1) * 1 - - if self._check_parity(x_hat): - return x_hat - - return None - - - * */ namespace py11 = pybind11; using namespace pybind11::literals; @@ -66,6 +27,8 @@ public: double gamma, double eta) : mN(H.cols()), mK(K), mOmega(omega), mGamma(gamma), mEta(eta), mH(H), mH_zero_indices(find_zero(H)) { + + Eigen::setNbThreads(8); } const std::optional @@ -76,10 +39,14 @@ public: for (std::size_t i = 0; i < mK; ++i) { r = s - mOmega * L_awgn(s, y); + s = projection(r - mGamma * grad_H(r)); - x_hat = s.cast().cwiseSign(); - x_hat = (x_hat.array() - 1).matrix() / (-2); + x_hat = s.unaryExpr([](double d) { + uint64_t bits = std::bit_cast(d); + // Return the sign bit: 1 for negative, 0 for positive + return (bits >> 63); + }).cast(); if (check_parity(x_hat)) { return x_hat; @@ -96,8 +63,7 @@ private: const double mGamma; const double mEta; - const MatrixXiR mH; - + const MatrixXiR mH; const std::vector mH_zero_indices;