ldpc_toolbox/decoder/
flooding.rs

1//! LDPC decoder with flooding schedule.
2//!
3//! This module implements a generice belief propagation LDPC decoder with a
4//! flooding message passing schedule.
5
6use super::{
7    DecoderOutput, LdpcDecoder, Messages, arithmetic::DecoderArithmetic, check_llrs, hard_decisions,
8};
9use crate::sparse::SparseMatrix;
10
11/// LDPC belief propagation flooding decoder.
12#[derive(Debug, Clone, PartialEq)]
13pub struct Decoder<A: DecoderArithmetic> {
14    arithmetic: A,
15    h: SparseMatrix,
16    input_llrs: Box<[A::Llr]>,
17    output_llrs: Box<[A::Llr]>,
18    check_messages: Messages<A::CheckMessage>,
19    variable_messages: Messages<A::VarMessage>,
20}
21
22impl<A: DecoderArithmetic> Decoder<A> {
23    /// Creates a new flooding LDPC decoder.
24    ///
25    /// The parameter `h` indicates the parity check matrix.
26    pub fn new(h: SparseMatrix, arithmetic: A) -> Self {
27        let input_llrs = vec![Default::default(); h.num_cols()].into_boxed_slice();
28        let output_llrs = input_llrs.clone();
29        let check_messages = Messages::from_iter((0..h.num_cols()).map(|c| h.iter_col(c)));
30        let variable_messages = Messages::from_iter((0..h.num_rows()).map(|r| h.iter_row(r)));
31        Decoder {
32            arithmetic,
33            h,
34            input_llrs,
35            output_llrs,
36            check_messages,
37            variable_messages,
38        }
39    }
40
41    /// Decodes a codeword.
42    ///
43    /// The parameters are the LLRs for the received codeword and the maximum
44    /// number of iterations to perform. If decoding is successful, the function
45    /// returns an `Ok` containing the (hard decision) on the decoded codeword
46    /// and the number of iterations used in decoding. If decoding is not
47    /// successful, the function returns an `Err` containing the hard decision
48    /// on the final decoder LLRs (which still has some bit errors) and the
49    /// number of iterations used in decoding (which is equal to
50    /// `max_iterations`).
51    pub fn decode(
52        &mut self,
53        llrs: &[f64],
54        max_iterations: usize,
55    ) -> Result<DecoderOutput, DecoderOutput> {
56        assert_eq!(llrs.len(), self.input_llrs.len());
57        let input_llrs_hard_decision = |x| x <= 0.0;
58        if check_llrs(&self.h, llrs, input_llrs_hard_decision) {
59            // No bit errors case
60            return Ok(DecoderOutput {
61                codeword: hard_decisions(llrs, input_llrs_hard_decision),
62                iterations: 0,
63            });
64        }
65        self.initialize(llrs);
66        for iteration in 1..=max_iterations {
67            self.process_check_nodes();
68            self.process_variable_nodes();
69            if check_llrs(&self.h, &self.output_llrs, |x| {
70                self.arithmetic.llr_hard_decision(x)
71            }) {
72                // Decode succeeded
73                return Ok(DecoderOutput {
74                    codeword: hard_decisions(&self.output_llrs, |x| {
75                        self.arithmetic.llr_hard_decision(x)
76                    }),
77                    iterations: iteration,
78                });
79            }
80        }
81        // Decode failed
82        Err(DecoderOutput {
83            codeword: hard_decisions(&self.output_llrs, |x| self.arithmetic.llr_hard_decision(x)),
84            iterations: max_iterations,
85        })
86    }
87
88    fn initialize(&mut self, llrs: &[f64]) {
89        for (x, &y) in self.input_llrs.iter_mut().zip(llrs.iter()) {
90            *x = self.arithmetic.input_llr_quantize(y)
91        }
92
93        // First variable messages use only input LLRs
94        for (v, &llr) in self.input_llrs.iter().enumerate() {
95            for &c in self.h.iter_col(v) {
96                self.variable_messages
97                    .send(v, c, self.arithmetic.llr_to_var_message(llr));
98            }
99        }
100    }
101
102    fn process_check_nodes(&mut self) {
103        for (c, messages) in self.variable_messages.per_destination.iter().enumerate() {
104            self.arithmetic.send_check_messages(messages, {
105                let check_messages = &mut self.check_messages;
106                move |msg| check_messages.send(c, msg.dest, msg.value)
107            });
108        }
109    }
110
111    fn process_variable_nodes(&mut self) {
112        for (((v, messages), output_llr), &input_llr) in self
113            .check_messages
114            .per_destination
115            .iter()
116            .enumerate()
117            .zip(self.output_llrs.iter_mut())
118            .zip(self.input_llrs.iter())
119        {
120            *output_llr = self.arithmetic.send_var_messages(input_llr, messages, {
121                let var_messages = &mut self.variable_messages;
122                move |msg| var_messages.send(v, msg.dest, msg.value)
123            });
124        }
125    }
126}
127
128impl<A: DecoderArithmetic> LdpcDecoder for Decoder<A> {
129    fn decode(
130        &mut self,
131        llrs: &[f64],
132        max_iterations: usize,
133    ) -> Result<DecoderOutput, DecoderOutput> {
134        Decoder::decode(self, llrs, max_iterations)
135    }
136}
137
138#[cfg(test)]
139mod test {
140    use super::super::arithmetic::Phif64;
141    use super::*;
142
143    fn test_decoder() -> Decoder<Phif64> {
144        // Example 2.5 in Sarah J. Johnson - Iterative Error Correction
145        let mut h = SparseMatrix::new(4, 6);
146        h.insert_row(0, [0, 1, 3].iter());
147        h.insert_row(1, [1, 2, 4].iter());
148        h.insert_row(2, [0, 4, 5].iter());
149        h.insert_row(3, [2, 3, 5].iter());
150        Decoder::new(h, Phif64::new())
151    }
152
153    // These are based on example 2.23 in Sarah J. Johnson - Iterative Error Correction
154
155    fn to_llrs(bits: &[u8]) -> Vec<f64> {
156        bits.iter()
157            .map(|&b| if b == 0 { 1.3863 } else { -1.3863 })
158            .collect()
159    }
160
161    #[test]
162    fn no_errors() {
163        let mut decoder = test_decoder();
164        let codeword = [0, 0, 1, 0, 1, 1];
165        let max_iter = 100;
166        let DecoderOutput {
167            codeword: decoded,
168            iterations,
169        } = decoder.decode(&to_llrs(&codeword), max_iter).unwrap();
170        assert_eq!(&decoded, &codeword);
171        assert_eq!(iterations, 0);
172    }
173
174    #[test]
175    fn single_error() {
176        let mut decoder = test_decoder();
177        let codeword_good = [0, 0, 1, 0, 1, 1];
178        for j in 0..codeword_good.len() {
179            let mut codeword_bad = codeword_good;
180            codeword_bad[j] ^= 1;
181            let max_iter = 100;
182            let DecoderOutput {
183                codeword: decoded,
184                iterations,
185            } = decoder.decode(&to_llrs(&codeword_bad), max_iter).unwrap();
186            assert_eq!(&decoded, &codeword_good);
187            assert_eq!(iterations, 1);
188        }
189    }
190}