Finished cpp proximal decoder implementation
This commit is contained in:
parent
9818193386
commit
066d9d85d2
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,6 +2,8 @@ latex/build/
|
|||||||
latex/tmp/
|
latex/tmp/
|
||||||
sw/cpp_modules
|
sw/cpp_modules
|
||||||
sw/cpp/build
|
sw/cpp/build
|
||||||
|
sw/cpp/cmake-build-debug
|
||||||
|
sw/cpp/cmake-build-release
|
||||||
sw/sim_saves/
|
sw/sim_saves/
|
||||||
.idea
|
.idea
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|||||||
@ -1,14 +1,31 @@
|
|||||||
cmake_minimum_required (VERSION 3.0)
|
cmake_minimum_required (VERSION 3.0)
|
||||||
project(cpp_decoders)
|
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(Eigen3 3.3 REQUIRED NO_MODULE)
|
||||||
find_package(pybind11 CONFIG REQUIRED)
|
find_package(pybind11 CONFIG REQUIRED)
|
||||||
|
|
||||||
include_directories(${pybind11_INCLUDE_DIRS})
|
include_directories(${pybind11_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
|
||||||
|
find_package(OpenMP REQUIRED)
|
||||||
|
|
||||||
pybind11_add_module(cpp_decoders src/cpp_decoders.cpp)
|
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)
|
set(INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cpp_modules)
|
||||||
|
|
||||||
|
|||||||
@ -1,53 +1,14 @@
|
|||||||
#include <Eigen/Cholesky>
|
#include <Eigen/Dense>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <pybind11/numpy.h>
|
#include <pybind11/numpy.h>
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
#include <pybind11/eigen.h>
|
#include <pybind11/eigen.h>
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
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;
|
namespace py11 = pybind11;
|
||||||
using namespace pybind11::literals;
|
using namespace pybind11::literals;
|
||||||
@ -66,6 +27,8 @@ public:
|
|||||||
double gamma, double eta)
|
double gamma, double eta)
|
||||||
: mN(H.cols()), mK(K), mOmega(omega), mGamma(gamma), mEta(eta), mH(H),
|
: mN(H.cols()), mK(K), mOmega(omega), mGamma(gamma), mEta(eta), mH(H),
|
||||||
mH_zero_indices(find_zero(H)) {
|
mH_zero_indices(find_zero(H)) {
|
||||||
|
|
||||||
|
Eigen::setNbThreads(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::optional<Eigen::RowVectorXi>
|
const std::optional<Eigen::RowVectorXi>
|
||||||
@ -76,10 +39,14 @@ public:
|
|||||||
|
|
||||||
for (std::size_t i = 0; i < mK; ++i) {
|
for (std::size_t i = 0; i < mK; ++i) {
|
||||||
r = s - mOmega * L_awgn(s, y);
|
r = s - mOmega * L_awgn(s, y);
|
||||||
|
|
||||||
s = projection(r - mGamma * grad_H(r));
|
s = projection(r - mGamma * grad_H(r));
|
||||||
|
|
||||||
x_hat = s.cast<int>().cwiseSign();
|
x_hat = s.unaryExpr([](double d) {
|
||||||
x_hat = (x_hat.array() - 1).matrix() / (-2);
|
uint64_t bits = std::bit_cast<uint64_t>(d);
|
||||||
|
// Return the sign bit: 1 for negative, 0 for positive
|
||||||
|
return (bits >> 63);
|
||||||
|
}).cast<int>();
|
||||||
|
|
||||||
if (check_parity(x_hat)) {
|
if (check_parity(x_hat)) {
|
||||||
return x_hat;
|
return x_hat;
|
||||||
@ -97,7 +64,6 @@ private:
|
|||||||
const double mEta;
|
const double mEta;
|
||||||
|
|
||||||
const MatrixXiR mH;
|
const MatrixXiR mH;
|
||||||
|
|
||||||
const std::vector<Eigen::Index> mH_zero_indices;
|
const std::vector<Eigen::Index> mH_zero_indices;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user