labrador_ldpc/
decoder.rs

1// Copyright 2017 Adam Greig
2// Licensed under the MIT license, see LICENSE for details.
3
4//! This module provides decoding functions for turning codewords into data.
5//!
6//! Please refer to the `decode_ms` and `decode_bf` methods on
7//! [`LDPCCode`](../codes/enum.LDPCCode.html) for more details.
8
9use core::i8;
10use core::i16;
11use core::i32;
12use core::f32;
13use core::f64;
14
15use core::ops::{Add,AddAssign,Neg,Sub};
16
17use crate::codes::LDPCCode;
18
19/// Trait for types that the min-sum decoder can operate with.
20///
21/// Implemented for `i8`, `i16`, `i32`, `f32`, and `f64`.
22pub trait DecodeFrom:
23    Sized + Clone + Copy + PartialEq + PartialOrd
24    + Add + AddAssign + Neg<Output=Self> + Sub<Output=Self>
25{
26    /// 1 in T
27    fn one()            -> Self;
28    /// 0 in T
29    fn zero()           -> Self;
30    /// Maximum value T can represent
31    fn maxval()         -> Self;
32    /// Absolute value of self
33    fn abs(&self)       -> Self;
34    /// Saturating add
35    fn saturating_add(&self, other: Self) -> Self;
36    /// Saturating sub
37    fn saturating_sub(&self, other: Self) -> Self;
38    /// Hard-information decoding for T, treating negative values as `true`
39    fn hard_bit(&self) -> bool;
40}
41
42impl DecodeFrom for i8 {
43    #[inline] fn one()      -> i8 { 1 }
44    #[inline] fn zero()     -> i8 { 0 }
45    #[inline] fn maxval()   -> i8 { i8::MAX }
46    #[inline] fn abs(&self) -> i8 { i8::saturating_abs(*self) }
47    #[inline] fn saturating_add(&self, other: Self) -> Self { i8::saturating_add(*self, other) }
48    #[inline] fn saturating_sub(&self, other: Self) -> Self { i8::saturating_sub(*self, other) }
49    #[inline] fn hard_bit(&self) -> bool { *self < 0 }
50}
51impl DecodeFrom for i16 {
52    #[inline] fn one()      -> i16 { 1 }
53    #[inline] fn zero()     -> i16 { 0 }
54    #[inline] fn maxval()   -> i16 { i16::MAX }
55    #[inline] fn abs(&self) -> i16 { i16::saturating_abs(*self) }
56    #[inline] fn saturating_add(&self, other: Self) -> Self { i16::saturating_add(*self, other) }
57    #[inline] fn saturating_sub(&self, other: Self) -> Self { i16::saturating_sub(*self, other) }
58    #[inline] fn hard_bit(&self) -> bool { *self < 0 }
59}
60impl DecodeFrom for i32 {
61    #[inline] fn one()      -> i32 { 1 }
62    #[inline] fn zero()     -> i32 { 0 }
63    #[inline] fn maxval()   -> i32 { i32::MAX }
64    #[inline] fn abs(&self) -> i32 { i32::saturating_abs(*self) }
65    #[inline] fn saturating_add(&self, other: Self) -> Self { i32::saturating_add(*self, other) }
66    #[inline] fn saturating_sub(&self, other: Self) -> Self { i32::saturating_sub(*self, other) }
67    #[inline] fn hard_bit(&self) -> bool { *self < 0 }
68}
69impl DecodeFrom for f32 {
70    #[inline] fn one()      -> f32 { 1.0 }
71    #[inline] fn zero()     -> f32 { 0.0 }
72    #[inline] fn maxval()   -> f32 { f32::MAX }
73    #[inline] fn abs(&self) -> f32 { f32::from_bits(self.to_bits() & 0x7FFF_FFFF) }
74    #[inline] fn saturating_add(&self, other: Self) -> Self { *self + other }
75    #[inline] fn saturating_sub(&self, other: Self) -> Self { *self - other }
76    #[inline] fn hard_bit(&self) -> bool { *self < 0.0 }
77}
78impl DecodeFrom for f64 {
79    #[inline] fn one()      -> f64 { 1.0 }
80    #[inline] fn zero()     -> f64 { 0.0 }
81    #[inline] fn maxval()   -> f64 { f64::MAX }
82    #[inline] fn abs(&self) -> f64 { f64::from_bits(self.to_bits() & 0x7FFF_FFFF_FFFF_FFFF) }
83    #[inline] fn saturating_add(&self, other: Self) -> Self { *self + other }
84    #[inline] fn saturating_sub(&self, other: Self) -> Self { *self - other }
85    #[inline] fn hard_bit(&self) -> bool { *self < 0.0 }
86}
87
88impl LDPCCode {
89
90    /// Get the length of [u8] required for the working area of `decode_bf`.
91    ///
92    /// Equal to n + punctured_bits.
93    pub const fn decode_bf_working_len(self) -> usize {
94        self.n() + self.punctured_bits()
95    }
96
97    /// Get the length of [T] required for the working area of `decode_ms`.
98    ///
99    /// Equal to 2 * paritycheck_sum + 3*n + 3*punctured_bits - 2*k.
100    pub const fn decode_ms_working_len(self) -> usize {
101        2 * self.paritycheck_sum() as usize + 3*self.n() + 3*self.punctured_bits() - 2*self.k()
102    }
103
104    /// Get the length of [u8] required for the working_u8 area of `decode_ms`.
105    ///
106    /// Equal to (n + punctured_bits - k)/8.
107    pub const fn decode_ms_working_u8_len(self) -> usize {
108        (self.n() + self.punctured_bits() - self.k()) / 8
109    }
110
111    /// Get the length of [u8] required for the output of any decoder.
112    ///
113    /// Equal to (n+punctured_bits)/8.
114    pub const fn output_len(self) -> usize {
115        (self.n() + self.punctured_bits()) / 8
116    }
117
118    /// Hard erasure decoding algorithm.
119    ///
120    /// Used to preprocess punctured codes before attempting bit-flipping decoding,
121    /// as the bit-flipping algorithm cannot handle erasures.
122    ///
123    /// The algorithm is:
124    ///     * We compute the parity of each check over all non-erased bits
125    ///     * We count how many erased bits are connected to each check (0, 1, or "more than 1")
126    ///     * Then each parity check with exactly one erased variable casts a vote for
127    ///       that variable, +1 if check parity is 1, otherwise -1
128    ///     * Each variable that receives a majority vote (i.e. not equal 0) is set to that
129    ///       vote and marked decoded
130    ///     * Iterate until all variables are decoded or we reach the iteration limit
131    ///
132    /// This is based on the paper:
133    /// Novel multi-Gbps bit-flipping decoders for punctured LDPC codes,
134    /// by Archonta, Kanistras, and Paliouras, MOCAST 2016.
135    ///
136    /// * `codeword` must be (n+p)/8 long (`self.output_len()`), with the first n/8 bytes already
137    ///   set to the received hard information, and the punctured bits at the end will be updated.
138    /// * `working` must be (n+p) bytes long (`self.decode_bf_working_len()`).
139    ///
140    /// Returns `(success, number of iterations run)`. Success only indicates that every punctured
141    /// bit got a majority vote; but they might still be wrong; likewise failure means not every
142    /// bit got a vote but many may still have been determined correctly.
143    #[allow(clippy::many_single_char_names)]
144    fn decode_erasures(self, codeword: &mut [u8], working: &mut [u8], maxiters: usize)
145        -> (bool, usize)
146    {
147        assert_eq!(codeword.len(), self.output_len());
148        assert_eq!(working.len(), self.decode_bf_working_len());
149
150        let n = self.n();
151        let p = self.punctured_bits();
152
153        // Working area:
154        // * The top bit 0x80 for byte 'i' is the parity bit for check 'i'.
155        // * The second and third top bits 0x60 for byte 'i' indicate the number of erased
156        //   variables connected to check 'i':
157        //   00 for no erasures, 01 for a single erasure, 11 for more than one erasure
158        // * The fourth top bit 0x10 for byte 'a' indicates whether variable 'a' is erased
159        // * The lowest four bits 0x0F for byte 'a' indicate the votes received for variable 'a',
160        //   starting at 8 for 0 votes and being incremented and decremented from there.
161
162        // Initialse working area: mark all punctured bits as erased
163        for w in &mut working[..n] { *w = 0x00 }
164        for w in &mut working[n..] { *w = 0x10 }
165
166        // Also write all the punctured bits in the codeword to zero
167        for c in &mut codeword[n/8..] { *c = 0x00 }
168
169        // Keep track of how many bits we've fixed
170        let mut bits_fixed = 0;
171
172        for iter in 0..maxiters {
173            // Initialise parity and erasure counts to zero, reset votes, preserve erasure bit
174            for w in &mut working[..] { *w = (*w & 0x10) | 0x08 }
175
176            // Compute check parity and erasure count
177            for (check, var) in self.iter_paritychecks() {
178                if working[var] & 0x10 == 0x10 {
179                    // If var is erased, update check erasure count
180                    match working[check] & 0x60 {
181                        0x00 => working[check] |= 0x20,
182                        0x20 => working[check] |= 0x40,
183                        _    => (),
184                    }
185                } else if codeword[var/8] >> (7-(var%8)) & 1 == 1 {
186                    // If var is not erased and this codeword bit is set, update check parity
187                    working[check] ^= 0x80;
188                }
189            }
190
191            // Now accumulate votes for each erased variable
192            for (check, var) in self.iter_paritychecks() {
193                // If this variable is erased and this check has only one vote
194                if working[var] & 0x10 == 0x10 && working[check] & 0x60 == 0x20 {
195                    // Vote +1 if our parity is currently 1, -1 otherwise
196                    if working[check] & 0x80 == 0x80 {
197                        working[var] += 1;
198                    } else {
199                        working[var] -= 1;
200                    }
201                }
202            }
203
204            // Finally fix all bits that are erased and have a majority vote
205            for (var, working) in working[0..(n+p)].iter_mut().enumerate() {
206                if *working & 0x10 == 0x10 {
207                    if *working & 0x0F > 0x08 {
208                        codeword[var/8] |= 1<<(7-(var%8));
209                        *working &= !0x10;
210                    }
211                    bits_fixed += 1;
212                }
213            }
214
215            if bits_fixed == p {
216                // Hurray we're done
217                return (true, iter)
218            }
219        }
220
221        // If we finished the iteration loop then we did not succeed.
222        (false, maxiters)
223    }
224
225    /// Bit flipping decoder.
226    ///
227    /// This algorithm is quick but only operates on hard information and consequently leaves a
228    /// lot of error-correcting capability behind. It is around 1-2dB worse than the min-sum
229    /// decoder. However, it requires much less memory and is a lot quicker.
230    ///
231    /// Requires:
232    ///
233    /// * `input` must be `n/8` long, where each bit is the received hard information
234    /// * `output` must be `(n+punctured_bits)/8` (=`self.output_len()`) bytes long and is written
235    ///   with the decoded codeword, so the user data is present in the first `k/8` bytes.
236    /// * `working` must be `n+punctured_bits` (=`self.decode_bf_working_len()`) bytes long.
237    ///
238    /// Runs for at most `maxiters` iterations, both when attempting to fix punctured erasures on
239    /// applicable codes, and in the main bit flipping decoder.
240    ///
241    /// Returns `(decoding success, iters)`. For punctured codes, `iters` includes iterations
242    /// of the erasure decoding algorithm which is run first.
243    pub fn decode_bf(self, input: &[u8], output: &mut [u8],
244                     working: &mut [u8], maxiters: usize)
245        -> (bool, usize)
246    {
247        assert_eq!(input.len(), self.n()/8, "input.len() != n/8");
248        assert_eq!(output.len(), self.output_len(), "output.len != (n+p)/8");
249        assert_eq!(working.len(), self.decode_bf_working_len(), "working.len() incorrect");
250
251        output[..self.n()/8].copy_from_slice(input);
252
253        // For punctured codes we must first try and fix all the punctured bits.
254        // We run them through an erasure decoding algorithm and record how many iterations
255        // it took (so we can return the total).
256        let erasure_iters = if self.punctured_bits() > 0 {
257            let (_, iters) = self.decode_erasures(output, working, maxiters);
258            iters
259        } else { 0 };
260
261        // Working area: we use the top bit of the first k bytes to store that parity check,
262        // and the remaining 7 bits of the first n+p bytes to store violation count for that var.
263
264        for iter in 0..maxiters {
265            // Zero out violation counts
266            for v in &mut working[..] { *v = 0 }
267
268            // Calculate the parity of each parity check
269            for (check, var) in self.iter_paritychecks() {
270                if output[var/8] >> (7-(var%8)) & 1 == 1 {
271                    working[check] ^= 0x80;
272                }
273            }
274
275            // Count how many parity violations each variable is associated with
276            let mut max_violations = 0;
277            for (check, var) in self.iter_paritychecks() {
278                if working[check] & 0x80 == 0x80 {
279                    // Unless we have more than 127 checks for a single variable, this
280                    // can't overflow into the parity bit. And we don't have that.
281                    working[var] += 1;
282                    if working[var] & 0x7F > max_violations {
283                        max_violations = working[var] & 0x7F;
284                    }
285                }
286            }
287
288            if max_violations == 0 {
289                return (true, iter + erasure_iters);
290            } else {
291                // Flip all the bits that have the maximum number of violations
292                for (var, violations) in working.iter().enumerate() {
293                    if *violations & 0x7F == max_violations {
294                        output[var/8] ^= 1<<(7-(var%8));
295                    }
296                }
297            }
298        }
299
300        (false, maxiters + erasure_iters)
301    }
302
303    /// Message passing based min-sum decoder.
304    ///
305    /// This algorithm is slower and requires more memory than the bit-flipping decode, but
306    /// operates on soft information and provides very close to optimal decoding. If you don't have
307    /// soft information, you can use `hard_to_llrs` to go from hard information (bytes from a
308    /// receiver) to soft information (LLRs).
309    ///
310    /// Requires:
311    ///
312    /// * `llrs` must be `n` long, with positive numbers more likely to be a 0 bit.
313    /// * `output` must be allocated to (n+punctured_bits)/8 bytes, aka `output_len()`, of which
314    ///   the first k/8 bytes will be set to the decoded message (and the rest to the parity bits
315    ///   of the complete codeword)
316    /// * `working` is the main working area which must be provided and must have
317    ///   `decode_ms_working_len()` elements, equal to
318    ///   2*paritycheck_sum + 3*n + 3*punctured_bits - 2*k
319    /// * `working_u8` is the secondary working area which must be provided and must have
320    ///   `decode_ms_working_u8_len()` elements, equal to (n + punctured_bits - k)/8.
321    ///
322    /// Will run for at most `maxiters` iterations.
323    ///
324    /// Returns decoding success and the number of iterations run for.
325    ///
326    /// ## Log Likelihood Ratios and choice of `T`
327    ///
328    /// The `llrs` input is a list of signed numbers, one per bit, where positive numbers mean
329    /// a bit is more likely to be 0, and larger magnitude numbers indicate increased confidence
330    /// on a logarithmic scale (so every step increase is a multiplication of the confidence).
331    ///
332    /// This decoder is invariant to a linear scaling of all the LLRs (in other words, it is
333    /// invariant to the channel noise level), so you can choose any quantisation level and
334    /// fixed-point interpretation you desire. This means you can view `i8` as representing
335    /// the 256 numbers between -1 and +0.9921875, or as just representing -128 to +127.
336    ///
337    /// Internally, variables of type `T` are used to accumulate messages, so it is useful to leave
338    /// some headroom in `T` after the range of your LLRs. For `T=i8` you might assign -32 to 31
339    /// for LLR inputs, so that several full-scale messages can be accumulated before saturation
340    /// occurs. On floating point types this is less of a concern.
341    ///
342    /// This also means if you only have hard information it makes no practical difference what
343    /// exact value you give the LLRs, but in the interests of avoiding saturation you may as
344    /// well pick +-1 in any unit (and you may as well use i8 since the additional range will
345    /// not be of benefit).
346    #[allow(clippy::cognitive_complexity,clippy::many_single_char_names)]
347    pub fn decode_ms<T: DecodeFrom>(self, llrs: &[T], output: &mut [u8],
348                                    working: &mut [T], working_u8: &mut [u8],
349                                    maxiters: usize)
350        -> (bool, usize)
351    {
352        let n = self.n();
353        let k = self.k();
354        let p = self.punctured_bits();
355
356        assert_eq!(llrs.len(), n, "llrs.len() != n");
357        assert_eq!(output.len(), self.output_len(), "output.len() != (n+p)/8");
358        assert_eq!(working.len(), self.decode_ms_working_len(), "working.len() incorrect");
359        assert_eq!(working_u8.len(), self.decode_ms_working_u8_len(), "working_u8 != (n+p-k)/8");
360
361        // Rename output to parities as we'll use it to keep track of the status of each check's
362        // parity equations, until using it to write the decoded output on completion.
363        let parities = output;
364
365        // Rename working_u8 to ui_sgns.
366        // It will be used to accumulate products of signs of each check's incoming messages.
367        let ui_sgns = working_u8;
368        for x in &mut ui_sgns[..] { *x = 0 }
369
370        // Split up the working area.
371        // `u` contains check-to-variable messages, `v` contains variable-to-check messages,
372        // `va` contains the marginal a posteriori LLRs for each variable, `ui_min*` tracks the
373        // smallest and second-smallest variable-to-check message for each check.
374        for w in &mut working[..] { *w = T::zero() }
375        let (u, working)        = working.split_at_mut(self.paritycheck_sum() as usize);
376        let (v, working)        = working.split_at_mut(self.paritycheck_sum() as usize);
377        let (va, working)       = working.split_at_mut(n + p);
378        let (ui_min1, ui_min2)  = working.split_at_mut(n + p - k);
379
380        for iter in 0..maxiters {
381            // Initialise the marginals to the input LLRs (and to 0 for punctured bits).
382            va[..llrs.len()].copy_from_slice(llrs);
383            for x in &mut va[llrs.len()..] { *x = T::zero() }
384
385            // You'd think .enumerate() would be sensible, but actually it prevents
386            // inlining the iterator's next() method, which leads to a big performance hit.
387            let mut idx = 0;
388            for (check, var) in self.iter_paritychecks() {
389                // If this variable-to-check message equals the minimum of all messages to this
390                // check, use the second-minimum to obtain the minimum-excluding-this-variable.
391                if v[idx].abs() == ui_min1[check] {
392                    u[idx] = ui_min2[check];
393                } else {
394                    u[idx] = ui_min1[check];
395                }
396
397                // When the product of all incoming signs was -1, negate `u`.
398                if ui_sgns[check/8] >> (check%8) & 1 == 1 {
399                    u[idx] = -u[idx];
400                }
401
402                // Remove the effect of the sign of this variable's message to this check node.
403                if v[idx].hard_bit() {
404                    u[idx] = -u[idx];
405                }
406
407                // Accumulate with all incoming messages to this variable.
408                va[var] = va[var].saturating_add(u[idx]);
409
410                idx += 1;
411            }
412
413            // Compute variable-to-check messages `v`.
414            for x in &mut ui_min1[..] { *x = T::maxval() }
415            for x in &mut ui_min2[..] { *x = T::maxval() }
416            for x in &mut ui_sgns[..] { *x = 0 }
417            for x in &mut parities[..] { *x = 0 }
418            idx = 0;
419            for (check, var) in self.iter_paritychecks() {
420                // Compute new `v`, with self-correcting behaviour.
421                let new_v_ai = va[var].saturating_sub(u[idx]);
422                if new_v_ai.hard_bit() == v[idx].hard_bit() || v[idx] == T::zero() {
423                    v[idx] = new_v_ai;
424                } else {
425                    v[idx] = T::zero();
426                }
427
428                // Track the smallest and second-smallest abs(variable-to-check) messages.
429                // These may be the same if two messages have identical magnitude.
430                if v[idx].abs() < ui_min1[check] {
431                    ui_min2[check] = ui_min1[check];
432                    ui_min1[check] = v[idx].abs();
433                } else if v[idx].abs() < ui_min2[check] {
434                    ui_min2[check] = v[idx].abs();
435                }
436
437                // Accumulate product of signs of variable-to-check messages, with a set
438                // bit meaning the product is negative.
439                if v[idx].hard_bit() {
440                    ui_sgns[check/8] ^= 1<<(check%8);
441                }
442
443                // Accumulate output of each check's parity equation, used to detect
444                // when all parity checks are satisfied and thus decoding is complete.
445                if va[var].hard_bit() {
446                    parities[check/8] ^= 1<<(check%8);
447                }
448
449                idx += 1;
450            }
451
452            // Check parity equations. If none are 1 then we have a valid codeword.
453            if *parities.iter().max().unwrap() == 0 {
454                // Hard decode marginals into the output.
455                let output = parities;
456                for o in &mut output[..] { *o = 0 }
457                for (var, &va) in va[0..(n+p)].iter().enumerate() {
458                    if va.hard_bit() {
459                        output[var/8] |= 1 << (7 - (var%8));
460                    }
461                }
462                return (true, iter);
463            }
464        }
465
466        // If we failed to find a codeword, at least hard decode the marginals into the output.
467        let output = parities;
468        for o in &mut output[..] { *o = 0 }
469        for (var, &va) in va[0..(n+p)].iter().enumerate() {
470            if va.hard_bit() {
471                output[var/8] |= 1 << (7 - (var%8));
472            }
473        }
474        (false, maxiters)
475    }
476
477    /// Convert hard information into LLRs.
478    ///
479    /// The min-sum decoding used in `decode_ms` is invariant to linear scaling
480    /// in LLR, so it doesn't matter which value is picked so long as the sign
481    /// is correct. This function just assigns -/+ 1 for 1/0 bits.
482    ///
483    /// `input` must be n/8 long, `llrs` must be n long.
484    pub fn hard_to_llrs<T: DecodeFrom>(self, input: &[u8], llrs: &mut [T]) {
485        assert_eq!(input.len(), self.n()/8, "input.len() != n/8");
486        assert_eq!(llrs.len(), self.n(), "llrs.len() != n");
487        let llr = -T::one();
488        for (idx, byte) in input.iter().enumerate() {
489            for i in 0..8 {
490                llrs[idx*8 + i] = if (byte >> (7-i)) & 1 == 1 { llr } else { -llr };
491            }
492        }
493    }
494
495    /// Convert LLRs into hard information.
496    ///
497    /// `llrs` must be n long, `output` must be n/8 long.
498    pub fn llrs_to_hard<T: DecodeFrom>(self, llrs: &[T], output: &mut [u8]) {
499        assert_eq!(llrs.len(), self.n(), "llrs.len() != n");
500        assert_eq!(output.len(), self.n()/8, "output.len() != n/8");
501
502        for o in &mut output[..] { *o = 0 }
503
504        for (i, llr) in llrs.iter().enumerate() {
505            if llr.hard_bit() {
506                output[i/8] |= 1 << (7 - (i%8));
507            }
508        }
509    }
510}
511
512#[cfg(test)]
513mod tests {
514    use std::prelude::v1::*;
515
516    use crate::codes::{LDPCCode, CodeParams,
517                       TC128_PARAMS,  TC256_PARAMS,  TC512_PARAMS,
518                       TM1280_PARAMS, TM1536_PARAMS, TM2048_PARAMS,
519                       TM5120_PARAMS, TM6144_PARAMS, TM8192_PARAMS};
520
521    const CODES: [LDPCCode;  9] = [LDPCCode::TC128,   LDPCCode::TC256,   LDPCCode::TC512,
522                                   LDPCCode::TM1280,  LDPCCode::TM1536,  LDPCCode::TM2048,
523                                   LDPCCode::TM5120,  LDPCCode::TM6144,  LDPCCode::TM8192,
524    ];
525
526    const PARAMS: [CodeParams; 9] = [TC128_PARAMS,  TC256_PARAMS,  TC512_PARAMS,
527                                     TM1280_PARAMS, TM1536_PARAMS, TM2048_PARAMS,
528                                     TM5120_PARAMS, TM6144_PARAMS, TM8192_PARAMS,
529    ];
530
531    #[test]
532    fn test_decode_ms_working_len() {
533        for (code, param) in CODES.iter().zip(PARAMS.iter()) {
534            assert_eq!(code.decode_ms_working_len(), param.decode_ms_working_len);
535            assert_eq!(code.decode_ms_working_u8_len(), param.decode_ms_working_u8_len);
536        }
537    }
538
539    #[test]
540    fn test_decode_bf_working_len() {
541        for (code, param) in CODES.iter().zip(PARAMS.iter()) {
542            assert_eq!(code.decode_bf_working_len(), param.decode_bf_working_len);
543        }
544    }
545
546    #[test]
547    fn test_output_len() {
548        for (code, param) in CODES.iter().zip(PARAMS.iter()) {
549            assert_eq!(code.output_len(), param.output_len);
550        }
551    }
552
553    #[test]
554    fn test_hard_to_llrs() {
555        let code = LDPCCode::TC128;
556        let hard = vec![255, 254, 253, 252, 251, 250, 249, 248,
557                        203, 102, 103, 120, 107,  30, 157, 169];
558        let mut llrs = vec![0f32; code.n()];
559        let llr = -1.0;
560        code.hard_to_llrs(&hard, &mut llrs);
561        assert_eq!(llrs, vec![
562             llr,  llr,  llr,  llr,  llr,  llr,  llr,  llr,
563             llr,  llr,  llr,  llr,  llr,  llr,  llr, -llr,
564             llr,  llr,  llr,  llr,  llr,  llr, -llr,  llr,
565             llr,  llr,  llr,  llr,  llr,  llr, -llr, -llr,
566             llr,  llr,  llr,  llr,  llr, -llr,  llr,  llr,
567             llr,  llr,  llr,  llr,  llr, -llr,  llr, -llr,
568             llr,  llr,  llr,  llr,  llr, -llr, -llr,  llr,
569             llr,  llr,  llr,  llr,  llr, -llr, -llr, -llr,
570             llr,  llr, -llr, -llr,  llr, -llr,  llr,  llr,
571            -llr,  llr,  llr, -llr, -llr,  llr,  llr, -llr,
572            -llr,  llr,  llr, -llr, -llr,  llr,  llr,  llr,
573            -llr,  llr,  llr,  llr,  llr, -llr, -llr, -llr,
574            -llr,  llr,  llr, -llr,  llr, -llr,  llr,  llr,
575            -llr, -llr, -llr,  llr,  llr,  llr,  llr, -llr,
576             llr, -llr, -llr,  llr,  llr,  llr, -llr,  llr,
577             llr, -llr,  llr, -llr,  llr, -llr, -llr,  llr]);
578    }
579
580    #[test]
581    fn test_llrs_to_hard() {
582        let code = LDPCCode::TC128;
583        let llr = -1.0;
584        let llrs = vec![
585             llr,  llr,  llr,  llr,  llr,  llr,  llr,  llr,
586             llr,  llr,  llr,  llr,  llr,  llr,  llr, -llr,
587             llr,  llr,  llr,  llr,  llr,  llr, -llr,  llr,
588             llr,  llr,  llr,  llr,  llr,  llr, -llr, -llr,
589             llr,  llr,  llr,  llr,  llr, -llr,  llr,  llr,
590             llr,  llr,  llr,  llr,  llr, -llr,  llr, -llr,
591             llr,  llr,  llr,  llr,  llr, -llr, -llr,  llr,
592             llr,  llr,  llr,  llr,  llr, -llr, -llr, -llr,
593             llr,  llr, -llr, -llr,  llr, -llr,  llr,  llr,
594            -llr,  llr,  llr, -llr, -llr,  llr,  llr, -llr,
595            -llr,  llr,  llr, -llr, -llr,  llr,  llr,  llr,
596            -llr,  llr,  llr,  llr,  llr, -llr, -llr, -llr,
597            -llr,  llr,  llr, -llr,  llr, -llr,  llr,  llr,
598            -llr, -llr, -llr,  llr,  llr,  llr,  llr, -llr,
599             llr, -llr, -llr,  llr,  llr,  llr, -llr,  llr,
600             llr, -llr,  llr, -llr,  llr, -llr, -llr,  llr];
601        let mut hard = vec![0u8; code.n()/8];
602        code.llrs_to_hard(&llrs, &mut hard);
603        assert_eq!(hard, vec![255, 254, 253, 252, 251, 250, 249, 248,
604                              203, 102, 103, 120, 107,  30, 157, 169]);
605    }
606
607    #[test]
608    fn test_decode_erasures() {
609        for code in &CODES {
610            // Only bother testing codes that actually have punctured bits
611            if code.punctured_bits() == 0 {
612                continue;
613            }
614
615            // Encode a codeword
616            let txdata: Vec<u8> = (0..code.k()/8).map(|x| x as u8).collect();
617            let mut txcode = vec![0u8; code.n()/8];
618            code.copy_encode(&txdata, &mut txcode);
619
620            // Allocate working area
621            let mut working = vec![0u8; code.decode_bf_working_len()];
622            let mut output = vec![0u8; code.output_len()];
623
624            // Copy TX codeword into output manually (normally done by `decode_bf()`).
625            output[..txcode.len()].copy_from_slice(&txcode);
626
627            // Run erasure decoder
628            let (success, _) = code.decode_erasures(&mut output, &mut working, 50);
629
630            assert!(success);
631
632            // Now compare the result against the min-sum decoder which should
633            // also correctly decode the punctured parity bits
634            let mut llrs = vec![0i8; code.n()];
635            let mut working_ms = vec![0i8; code.decode_ms_working_len()];
636            let mut working_u8_ms = vec![0u8; code.decode_ms_working_u8_len()];
637            let mut output_ms = vec![0u8; code.output_len()];
638            code.hard_to_llrs(&txcode, &mut llrs);
639            let (success, _) = code.decode_ms(&llrs, &mut output_ms, &mut working_ms,
640                                              &mut working_u8_ms, 50);
641
642            assert!(success);
643            assert_eq!(output, output_ms);
644        }
645    }
646
647    #[test]
648    fn test_decode_bf() {
649        for code in &CODES {
650            // Make up some TX data
651            let txdata: Vec<u8> = (0..code.k()/8).map(|x| x as u8).collect();
652            let mut txcode = vec![0u8; code.n()/8];
653            code.copy_encode(&txdata, &mut txcode);
654
655            // Copy it and corrupt some bits
656            let mut rxcode = txcode.clone();
657            rxcode[0] ^= 1<<7 | 1<<5 | 1<<3;
658
659            // Allocate working area and output area
660            let mut working = vec![0u8; code.decode_bf_working_len()];
661            let mut output = vec![0u8; code.output_len()];
662
663            // Run decoder
664            let (success, _) = code.decode_bf(&rxcode, &mut output, &mut working, 50);
665
666            assert!(success);
667            assert_eq!(&txcode[..], &output[..txcode.len()]);
668        }
669
670    }
671    #[test]
672    fn test_decode_ms() {
673        for code in &CODES {
674            // Make up a TX codeword
675            let txdata: Vec<u8> = (0..code.k()/8).map(|x| x as u8).collect();
676            let mut txcode = vec![0u8; code.n()/8];
677            code.copy_encode(&txdata, &mut txcode);
678
679            // Copy it and corrupt some bits
680            let mut rxcode = txcode.clone();
681            rxcode[0] ^= 1<<7 | 1<<5 | 1<<3;
682
683            // Convert the hard data to LLRs
684            let mut llrs = vec![0i8; code.n()];
685            code.hard_to_llrs(&rxcode, &mut llrs);
686
687            // Allocate working area and output area
688            let mut working = vec![0i8; code.decode_ms_working_len()];
689            let mut working_u8 = vec![0u8; code.output_len() - code.k()/8];
690            let mut output = vec![0u8; code.output_len()];
691
692            // Run decoder
693            let (success, _) = code.decode_ms(&llrs, &mut output, &mut working,
694                                              &mut working_u8, 50);
695
696            assert!(success);
697            assert_eq!(&txcode[..], &output[..txcode.len()]);
698        }
699    }
700}