1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
//! LDPC belief propagation decoders.
//!
//! This module provides several implementations of a LDPC decoders using belief
//! propagation (the sum-product algorithm). The implementations differ in
//! details about their numerical algorithms, data types and message passing
//! schedules.
use crate::sparse::SparseMatrix;
pub mod arithmetic;
pub mod factory;
pub mod flooding;
pub mod horizontal_layered;
/// Generic LDPC decoder.
///
/// This trait is used to form LDPC decoder trait objects, abstracting over the
/// internal implementation decoder.
pub trait LdpcDecoder: std::fmt::Debug + Send {
/// Decodes a codeword.
///
/// The parameters are the LLRs for the received codeword and the maximum
/// number of iterations to perform. If decoding is successful, the function
/// returns an `Ok` containing the (hard decision) on the decoded codeword
/// and the number of iterations used in decoding. If decoding is not
/// successful, the function returns an `Err` containing the hard decision
/// on the final decoder LLRs (which still has some bit errors) and the
/// number of iterations used in decoding (which is equal to
/// `max_iterations`).
fn decode(
&mut self,
llrs: &[f64],
max_iterations: usize,
) -> Result<DecoderOutput, DecoderOutput>;
}
/// LDPC decoder output.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct DecoderOutput {
/// Decoded codeword.
///
/// Contains the hard decision bits of the decoded codeword.
pub codeword: Vec<u8>,
/// Number of iterations.
///
/// Number of iterations used in decoding.
pub iterations: usize,
}
/// LDPC decoder message.
///
/// This represents a message used by the flooding belief propagation
/// decoder. It is used for messages received by the nodes.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
pub struct Message<T> {
/// Message source.
///
/// Contains the index of the variable node or check node that sent the
/// message.
pub source: usize,
/// Value.
///
/// Contains the value of the message.
pub value: T,
}
/// LDPC decoder outgoing message.
///
/// This represents a message used by the flooding belief propagation
/// decoder. It is used for messages sent by the nodes.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
pub struct SentMessage<T> {
/// Message destination.
///
/// Contains the index of the variable node or check node to which the
/// message is addressed.
pub dest: usize,
/// Value.
///
/// Contains the value of the message.
pub value: T,
}
#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
struct Messages<T> {
per_destination: Box<[Box<[Message<T>]>]>,
}
impl<T: Default> Messages<T> {
fn from_iter<I, J, B>(iter: I) -> Messages<T>
where
I: Iterator<Item = J>,
J: Iterator<Item = B>,
B: core::borrow::Borrow<usize>,
{
Messages {
per_destination: iter
.map(|i| {
i.map(|j| Message {
source: *j.borrow(),
value: T::default(),
})
.collect::<Vec<_>>()
.into_boxed_slice()
})
.collect::<Vec<_>>()
.into_boxed_slice(),
}
}
fn send(&mut self, source: usize, destination: usize, value: T) {
let message = self.per_destination[destination]
.iter_mut()
.find(|m| m.source == source)
.expect("message for source not found");
message.value = value;
}
}
#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
struct SentMessages<T> {
per_source: Box<[Box<[SentMessage<T>]>]>,
}
impl<T: Default> SentMessages<T> {
fn from_iter<I, J, B>(iter: I) -> SentMessages<T>
where
I: Iterator<Item = J>,
J: Iterator<Item = B>,
B: core::borrow::Borrow<usize>,
{
SentMessages {
per_source: iter
.map(|i| {
i.map(|j| SentMessage {
dest: *j.borrow(),
value: T::default(),
})
.collect::<Vec<_>>()
.into_boxed_slice()
})
.collect::<Vec<_>>()
.into_boxed_slice(),
}
}
#[allow(dead_code)]
fn send(&mut self, source: usize, destination: usize, value: T) {
let message = self.per_source[source]
.iter_mut()
.find(|m| m.dest == destination)
.expect("message for destination not found");
message.value = value;
}
}
fn check_llrs<T, F>(h: &SparseMatrix, llrs: &[T], hard_decision: F) -> bool
where
T: Copy,
F: Fn(T) -> bool,
{
// Check if hard decision on LLRs satisfies the parity check equations
!(0..h.num_rows()).any(|r| h.iter_row(r).filter(|&&c| hard_decision(llrs[c])).count() % 2 == 1)
}
fn hard_decisions<T, F>(llrs: &[T], hard_decision: F) -> Vec<u8>
where
T: Copy,
F: Fn(T) -> bool,
{
llrs.iter()
.map(|&llr| u8::from(hard_decision(llr)))
.collect()
}