pccc/
lib.rs

1//! # Parallel-concatenated convolutional code (PCCC)
2//!
3//! This crate implements encoding and decoding functionality for a _parallel-concatenated
4//! convolutional code_ (PCCC), commonly referred to as a
5//! [turbo code](https://en.wikipedia.org/wiki/Turbo_code). An instance of such a code is
6//! used for forward error correction in the 4G LTE standard for wireless broadband communication
7//! (see [3GPP TS 36.212](https://www.3gpp.org/ftp/Specs/archive/36_series/36.212/)).
8//!
9//! The encoder for a PCCC comprises the parallel concatenation of two identical _recursive
10//! systematic convolutional_ (RSC) encoders, separated by an internal interleaver. The decoder is
11//! based on "turbo" iterations between two corresponding soft-input/soft-output _a posteriori
12//! probability_ (APP) decoders, separated by an interleaver and deinterleaver.
13//!
14//! The [`encoder`] and [`decoder`] functions handle PCCC encoding and decoding, respectively,
15//! while the [`Interleaver`] struct models the internal interleaver and associated deinterleaver.
16//! The [`Bit`] enum represents binary symbol values, and the [`DecodingAlgo`] enum the supported
17//! decoding algorithms; each variant of the latter holds a [`u32`] representing the number of
18//! turbo iterations. The code below illustrates their usage through a toy example.
19//!
20//! # Examples
21//!
22//! ```
23//! use pccc::{decoder, encoder, Bit, DecodingAlgo, Interleaver};
24//! use Bit::{One, Zero};
25//!
26//! // Rate-1/3 PCCC in LTE, 4 information bits, Log-MAP decoding (8 turbo iterations)
27//! let code_polynomials = [0o13, 0o15];
28//! let interleaver = Interleaver::new(&[3, 0, 1, 2])?;
29//!
30//! // Encoding
31//! let info_bits = [One, Zero, Zero, One];
32//! let code_bits = encoder(&info_bits, &interleaver, &code_polynomials)?;
33//! assert_eq!(
34//!     code_bits,
35//!     [
36//!         One, One, One, Zero, One, Zero, Zero, One, Zero, One, Zero, Zero, One, Zero, One, One,
37//!         Zero, Zero, Zero, One, One, One, Zero, Zero
38//!     ]
39//! );
40//!
41//! // Decoding
42//! let code_bits_llr = [
43//!     -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
44//!     1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0,
45//! ];
46//! let info_bits_hat = decoder(
47//!     &code_bits_llr,
48//!     &interleaver,
49//!     &code_polynomials,
50//!     DecodingAlgo::LogMAP(8),
51//! )?;
52//! assert_eq!(info_bits_hat, [One, Zero, Zero, One]);
53//! # Ok::<(), Box<dyn std::error::Error>>(())
54//! ```
55//!
56//! The [`lte`] module contains encoder and decoder functions specifically for the rate-1/3 PCCC
57//! used in the LTE standard; the block size is restricted to the values in Table 5.1.3-3 of 3GPP
58//! TS 36.212 (from 40 to 6144 bits), and the interleaver for each of these block sizes is
59//! automatically set to the _quadratic permutation polynomial_ (QPP) interleaver prescribed
60//! therein. This module also has functions to evaluate the performance of the LTE PCCC over a
61//! BPSK-AWGN channel by simulation. Finally, the [`utils`] module has some useful functions for
62//! such a simulation.
63
64#![warn(
65    clippy::complexity,
66    clippy::pedantic,
67    clippy::perf,
68    clippy::style,
69    clippy::suspicious,
70    missing_copy_implementations,
71    missing_debug_implementations,
72    missing_docs,
73    trivial_casts,
74    trivial_numeric_casts,
75    unused_allocation,
76    unused_import_braces,
77    unused_qualifications
78)]
79
80use std::fmt;
81use std::io;
82
83use rand::{rngs::ThreadRng, seq::SliceRandom};
84use serde::{Deserialize, Serialize};
85use thiserror::Error;
86
87pub mod lte;
88mod rsc;
89pub mod utils;
90
91/// Custom error type
92#[derive(Error, Debug)]
93pub enum Error {
94    /// Invalid input error
95    #[error("{0}")]
96    InvalidInput(String),
97    /// File read/write error
98    #[error("{0}")]
99    FileReadWriteError(#[from] io::Error),
100    /// Serde read/write error
101    #[error("{0}")]
102    SerdeReadWriteError(#[from] serde_json::Error),
103    /// Unknown error
104    #[error("Unknown error")]
105    Unknown,
106}
107
108/// Enumeration of binary symbol values
109#[derive(Clone, Eq, PartialEq, Debug, Copy)]
110pub enum Bit {
111    /// Binary symbol `0`
112    Zero = 0,
113    /// Binary symbol `1`
114    One = 1,
115}
116
117/// Enumeration of PCCC decoding algorithms
118#[derive(Clone, Eq, Hash, PartialEq, Debug, Copy, Deserialize, Serialize)]
119pub enum DecodingAlgo {
120    /// Log-MAP decoding with given number of turbo iterations
121    LogMAP(u32),
122    /// Max-Log-MAP decoding with given number of turbo iterations
123    MaxLogMAP(u32),
124    /// Linear-Log-MAP decoding (Valenti & Sun, 2001) with given number of turbo iterations
125    LinearLogMAP(u32),
126}
127
128impl DecodingAlgo {
129    /// Returns the name of the variant.
130    fn name(&self) -> &str {
131        match self {
132            DecodingAlgo::LogMAP(_) => "Log-MAP",
133            DecodingAlgo::MaxLogMAP(_) => "Max-Log-MAP",
134            DecodingAlgo::LinearLogMAP(_) => "Linear-Log-MAP",
135        }
136    }
137
138    /// Returns the number of turbo iterations held in the variant.
139    fn num_iter(self) -> u32 {
140        match self {
141            DecodingAlgo::LogMAP(n)
142            | DecodingAlgo::MaxLogMAP(n)
143            | DecodingAlgo::LinearLogMAP(n) => n,
144        }
145    }
146}
147
148impl fmt::Display for DecodingAlgo {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        write!(
151            f,
152            "{} decoding, {} iterations",
153            self.name(),
154            self.num_iter()
155        )
156    }
157}
158
159/// Interleaver for sequences of a given length
160#[derive(Eq, PartialEq, Debug)]
161pub struct Interleaver {
162    /// Length of input/output sequence
163    length: usize,
164    /// Input index for each output index (needed in interleaving)
165    all_in_index_given_out_index: Vec<usize>,
166    /// Output index for each input index (needed in deinterleaving)
167    all_out_index_given_in_index: Vec<usize>,
168}
169
170impl Interleaver {
171    /// Returns interleaver corresponding to a given permutation.
172    ///
173    /// # Parameters
174    ///
175    /// - `perm`: Permutation of integers in `[0, L)` for some positive integer `L`. If the
176    ///   interleaver input is the sequence `x[0], x[1], ..., x[L-1]`, then its output is the
177    ///   sequence `x[perm[0]], x[perm[1]], ..., x[perm[L-1]]`.
178    ///
179    /// # Errors
180    ///
181    /// Returns an error if `perm` is not a permutation of the integers in `[0, L)` for some
182    /// positive integer `L`.
183    ///
184    /// # Examples
185    ///
186    /// ```
187    /// use pccc::Interleaver;
188    ///
189    /// let perm = [0, 3, 2, 5, 4, 7, 6, 1];
190    /// let interleaver = Interleaver::new(&perm)?;
191    /// # Ok::<(), Box<dyn std::error::Error>>(())
192    /// ```
193    pub fn new(perm: &[usize]) -> Result<Self, Error> {
194        if perm.is_empty() {
195            return Err(Error::InvalidInput(
196                "Permutation cannot be empty".to_string(),
197            ));
198        }
199        let perm_vec = perm.to_vec();
200        let mut perm_vec_sorted = perm.to_vec();
201        perm_vec_sorted.sort_unstable();
202        if !perm_vec_sorted.into_iter().eq(0 .. perm_vec.len()) {
203            return Err(Error::InvalidInput(format!(
204                "Expected permutation of all integers in the range [0, {})",
205                perm_vec.len()
206            )));
207        }
208        Ok(Self::from_valid_perm(perm_vec))
209    }
210
211    /// Returns random interleaver for sequences of a given length.
212    ///
213    /// # Parameters
214    ///
215    /// - `length`: Length of input/output sequence.
216    ///
217    /// - `rng`: Random number generator to be used.
218    ///
219    /// # Errors
220    ///
221    /// Returns an error if `length` is `0`.
222    ///
223    /// # Examples
224    ///
225    /// ```
226    /// use pccc::Interleaver;
227    ///
228    /// let mut rng = rand::thread_rng();
229    /// let length = 8;
230    /// let interleaver = Interleaver::random(length, &mut rng)?;
231    /// # Ok::<(), Box<dyn std::error::Error>>(())
232    /// ```
233    pub fn random(length: usize, rng: &mut ThreadRng) -> Result<Self, Error> {
234        if length == 0 {
235            return Err(Error::InvalidInput(
236                "Length must be a positive integer".to_string(),
237            ));
238        }
239        let mut perm_vec: Vec<usize> = (0 .. length).collect();
240        perm_vec.shuffle(rng);
241        Ok(Self::from_valid_perm(perm_vec))
242    }
243
244    /// Generates interleaver output given its input.
245    ///
246    /// # Parameters
247    ///
248    /// - `input`: Interleaver input.
249    ///
250    /// - `output`: Buffer for interleaver output (any pre-existing contents will be cleared).
251    ///
252    /// # Errors
253    ///
254    /// Returns an error if `input.len()` is not equal to `self.length`.
255    ///
256    /// # Examples
257    ///
258    /// ```
259    /// use pccc::Interleaver;
260    ///
261    /// let perm = [0, 3, 2, 5, 4, 7, 6, 1];
262    /// let interleaver = Interleaver::new(&perm)?;
263    /// let input = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
264    /// let mut output = Vec::new();
265    /// interleaver.interleave(&input, &mut output)?;
266    /// assert_eq!(output, ['a', 'd', 'c', 'f', 'e', 'h', 'g', 'b']);
267    /// # Ok::<(), Box<dyn std::error::Error>>(())
268    /// ```
269    pub fn interleave<T: Copy>(&self, input: &[T], output: &mut Vec<T>) -> Result<(), Error> {
270        if input.len() != self.length {
271            return Err(Error::InvalidInput(format!(
272                "Interleaver input has length {} (expected {})",
273                input.len(),
274                self.length,
275            )));
276        }
277        output.clear();
278        for out_index in 0 .. self.length {
279            output.push(input[self.all_in_index_given_out_index[out_index]]);
280        }
281        Ok(())
282    }
283
284    /// Generates interleaver input given its output.
285    ///
286    /// # Parameters
287    ///
288    /// - `output`: Interleaver output.
289    ///
290    /// - `input`: Buffer for interleaver input (any pre-existing contents will be cleared).
291    ///
292    /// # Errors
293    ///
294    /// Returns an error if `output.len()` is not equal to `self.length`.
295    ///
296    /// # Examples
297    ///
298    /// ```
299    /// use pccc::Interleaver;
300    ///
301    /// let perm = [0, 3, 2, 5, 4, 7, 6, 1];
302    /// let interleaver = Interleaver::new(&perm)?;
303    /// let output = ['a', 'd', 'c', 'f', 'e', 'h', 'g', 'b'];
304    /// let mut input = Vec::new();
305    /// interleaver.deinterleave(&output, &mut input)?;
306    /// assert_eq!(input, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
307    /// # Ok::<(), Box<dyn std::error::Error>>(())
308    /// ```
309    pub fn deinterleave<T: Copy>(&self, output: &[T], input: &mut Vec<T>) -> Result<(), Error> {
310        if output.len() != self.length {
311            return Err(Error::InvalidInput(format!(
312                "Interleaver output has length {} (expected {})",
313                output.len(),
314                self.length,
315            )));
316        }
317        input.clear();
318        for in_index in 0 .. self.length {
319            input.push(output[self.all_out_index_given_in_index[in_index]]);
320        }
321        Ok(())
322    }
323
324    /// Returns interleaver corresponding to a valid permutation.
325    fn from_valid_perm(perm_vec: Vec<usize>) -> Self {
326        let length = perm_vec.len();
327        let all_in_index_given_out_index: Vec<usize> = perm_vec;
328        let mut all_out_index_given_in_index: Vec<usize> = (0 .. length).collect();
329        all_out_index_given_in_index.sort_by_key(|&k| all_in_index_given_out_index[k]);
330        Self {
331            length,
332            all_in_index_given_out_index,
333            all_out_index_given_in_index,
334        }
335    }
336}
337
338/// Returns code bits from PCCC encoder for given information bits.
339///
340/// # Parameters
341///
342/// - `info_bits`: Information bits to be encoded.
343///
344/// - `interleaver`: Internal interleaver for the code.
345///
346/// - `code_polynomials`: Integer representations of the generator polynomials for the code. Must
347///   have length `N >= 2` for a PCCC code of rate `1/(2*N-1)`. The first element is taken as the
348///   feedback polynomial (this corresponds to the systematic bit), and all subsequent ones as the
349///   feedforward polynomials (these correspond to the parity bits from each RSC encoder). For a
350///   code of constraint length `L`, the feedback polynomial must be in the range `(2^(L-1), 2^L)`,
351///   and each feedforward polynomial must be in the range `[1, 2^L)` and different from the
352///   feedback polynomial.
353///
354/// # Returns
355///
356/// - `code_bits`: Code bits from the PCCC encoder.
357///
358/// # Errors
359///
360/// Returns an error if the number of information bits is not equal to `interleaver.length` or if
361/// `code_polynomials` is invalid. The latter condition holds if the number of code polynomials is
362/// less than `2`, if the first code polynomial is either `0` or a power of `2`, or if any
363/// subsequent code polynomial is either not in the range `[1, 2^L)` or equals the first code
364/// polynomial; here, `L` is the positive integer such that the first code polynomial is in the
365/// range `(2^(L-1), 2^L)`.
366///
367/// # Examples
368/// ```
369/// use pccc::{encoder, Bit, Interleaver};
370/// use Bit::{One, Zero};
371///
372/// let code_polynomials = [0o13, 0o15]; // Rate-1/3 PCCC in LTE
373/// let interleaver = Interleaver::new(&[3, 0, 1, 2])?; // 4 information bits
374/// let info_bits = [One, Zero, Zero, One];
375/// let code_bits = encoder(&info_bits, &interleaver, &code_polynomials)?;
376/// assert_eq!(
377///     code_bits,
378///     [
379///         One, One, One, Zero, One, Zero, Zero, One, Zero, One, Zero, Zero, One, Zero, One, One,
380///         Zero, Zero, Zero, One, One, One, Zero, Zero
381///     ]
382/// );
383/// # Ok::<(), Box<dyn std::error::Error>>(())
384/// ```
385pub fn encoder(
386    info_bits: &[Bit],
387    interleaver: &Interleaver,
388    code_polynomials: &[usize],
389) -> Result<Vec<Bit>, Error> {
390    let mut sm = rsc::StateMachine::new(code_polynomials)?;
391    let num_info_bits = interleaver.length;
392    let num_code_bits_per_rsc = (num_info_bits + sm.memory_len) * sm.num_output_bits;
393    // Top RSC encoder output
394    let mut top_code_bits = Vec::with_capacity(num_code_bits_per_rsc);
395    rsc::encode(info_bits, &mut sm, &mut top_code_bits);
396    // Bottom RSC encoder output
397    let mut bottom_code_bits = Vec::with_capacity(num_code_bits_per_rsc);
398    let mut interleaved_info_bits = Vec::with_capacity(num_info_bits);
399    interleaver.interleave(info_bits, &mut interleaved_info_bits)?;
400    rsc::encode(&interleaved_info_bits, &mut sm, &mut bottom_code_bits);
401    // PCCC encoder output
402    let mut code_bits = Vec::with_capacity(2 * num_code_bits_per_rsc - num_info_bits);
403    let i_first_rsc_tail_code_bit = num_info_bits * sm.num_output_bits;
404    // Code bits corresponding to information bits
405    for (top_chunk, bottom_chunk) in top_code_bits[.. i_first_rsc_tail_code_bit]
406        .chunks_exact(sm.num_output_bits)
407        .zip(bottom_code_bits[.. i_first_rsc_tail_code_bit].chunks_exact(sm.num_output_bits))
408    {
409        code_bits.extend(top_chunk.iter());
410        code_bits.extend(bottom_chunk.iter().skip(1));
411    }
412    // Code bits corresponding to tail bits
413    code_bits.extend(top_code_bits[i_first_rsc_tail_code_bit ..].iter());
414    code_bits.extend(bottom_code_bits[i_first_rsc_tail_code_bit ..].iter());
415    Ok(code_bits)
416}
417
418/// Returns information bit decisions from PCCC decoder for given code bit LLR values.
419///
420/// # Parameters
421///
422/// - `code_bits_llr`: Log-likelihood-ratio (LLR) values for the code bits.
423///
424/// - `interleaver`: Internal interleaver for the code.
425///
426/// - `code_polynomials`: Integer representations of the generator polynomials for the code. Must
427///   have length `N >= 2` for a PCCC code of rate `1/(2*N-1)`. The first element is taken as the
428///   feedback polynomial (this corresponds to the systematic bit), and all subsequent ones as the
429///   feedforward polynomials (these correspond to the parity bits from each RSC encoder). For a
430///   code of constraint length `L`, the feedback polynomial must be in the range `(2^(L-1), 2^L)`,
431///   and each feedforward polynomial must be in the range `[1, 2^L)` and different from the
432///   feedback polynomial.
433///
434/// - `decoding_algo`: Decoding algorithm to use, and associated number of turbo iterations.
435///
436/// # Returns
437///
438/// - `info_bits_hat`: Decisions on the information bits.
439///
440/// # Errors
441///
442/// Returns an error if the number of code bit LLR values is incompatible with `interleaver.length`
443/// or if `code_polynomials` is invalid. The latter condition holds if the number of code
444/// polynomials is less than `2`, if the first code polynomial is either `0` or a power of `2`, or
445/// if any subsequent code polynomial is either not in the range `[1, 2^L)` or equals the first
446/// code polynomial; here, `L` is the positive integer such that the first code polynomial is in
447/// the range `(2^(L-1), 2^L)`.
448///
449/// # Examples
450/// ```
451/// use pccc::{decoder, Bit, DecodingAlgo, Interleaver};
452/// use Bit::{One, Zero};
453///
454/// let code_polynomials = [0o13, 0o15]; // Rate-1/3 PCCC in LTE
455/// let interleaver = Interleaver::new(&[3, 0, 1, 2])?; // 4 information bits
456/// let code_bits_llr = [
457///     -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
458///     1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0,
459/// ];
460/// let info_bits_hat = decoder(
461///     &code_bits_llr,
462///     &interleaver,
463///     &code_polynomials,
464///     DecodingAlgo::LogMAP(8),
465/// )?; // Log-MAP decoding with 8 turbo iterations
466/// assert_eq!(info_bits_hat, [One, Zero, Zero, One]);
467/// # Ok::<(), Box<dyn std::error::Error>>(())
468/// ```
469pub fn decoder(
470    code_bits_llr: &[f64],
471    interleaver: &Interleaver,
472    code_polynomials: &[usize],
473    decoding_algo: DecodingAlgo,
474) -> Result<Vec<Bit>, Error> {
475    let mut sm = rsc::StateMachine::new(code_polynomials)?;
476    check_decoder_inputs(code_bits_llr, interleaver, &sm)?;
477    let num_info_bits = interleaver.length;
478    if decoding_algo.num_iter() == 0 {
479        return Ok(vec![Bit::Zero; num_info_bits]);
480    }
481    let mut ws = rsc::DecoderWorkspace::new(sm.num_states, num_info_bits, decoding_algo);
482    let (top_code_bits_llr, bottom_code_bits_llr) = bcjr_inputs(code_bits_llr, interleaver, &sm);
483    let mut info_bits_llr_prior = vec![0.0; num_info_bits];
484    for i_iter in 0 .. decoding_algo.num_iter() {
485        // Bottom RSC decoder
486        if i_iter > 0 {
487            interleaver.interleave(&ws.extrinsic_info, &mut info_bits_llr_prior)?;
488        }
489        rsc::decode(
490            &bottom_code_bits_llr,
491            &info_bits_llr_prior,
492            &mut sm,
493            &mut ws,
494        )?;
495        // Top RSC decoder
496        interleaver.deinterleave(&ws.extrinsic_info, &mut info_bits_llr_prior)?;
497        rsc::decode(&top_code_bits_llr, &info_bits_llr_prior, &mut sm, &mut ws)?;
498    }
499    Ok(utils::bpsk_slicer(&ws.llr_posterior))
500}
501
502/// Checks validity of decoder inputs.
503fn check_decoder_inputs(
504    code_bits_llr: &[f64],
505    interleaver: &Interleaver,
506    sm: &rsc::StateMachine,
507) -> Result<(), Error> {
508    let num_info_bits = interleaver.length;
509    let num_code_bits_per_rsc = (num_info_bits + sm.memory_len) * sm.num_output_bits;
510    let expected_code_bits_llr_len = 2 * num_code_bits_per_rsc - num_info_bits;
511    if code_bits_llr.len() == expected_code_bits_llr_len {
512        Ok(())
513    } else {
514        Err(Error::InvalidInput(format!(
515            "For interleaver of length {}, expected {} code bit LLR values (found {})",
516            num_info_bits,
517            expected_code_bits_llr_len,
518            code_bits_llr.len(),
519        )))
520    }
521}
522
523/// Returns code bit LLR values to be input to top and bottom BCJR decoders.
524fn bcjr_inputs(
525    code_bits_llr: &[f64],
526    interleaver: &Interleaver,
527    sm: &rsc::StateMachine,
528) -> (Vec<f64>, Vec<f64>) {
529    let num_info_bits = interleaver.length;
530    let inverse_code_rate = 2 * sm.num_output_bits - 1;
531    let num_code_bits_per_rsc = (num_info_bits + sm.memory_len) * sm.num_output_bits;
532    let mut top_code_bits_llr = Vec::with_capacity(num_code_bits_per_rsc);
533    let mut bottom_code_bits_llr = Vec::with_capacity(num_code_bits_per_rsc);
534    // Information bits
535    for k in 0 .. num_info_bits {
536        let i_top = k * inverse_code_rate;
537        top_code_bits_llr.extend_from_slice(&code_bits_llr[i_top .. i_top + sm.num_output_bits]);
538        let i_bottom = interleaver.all_in_index_given_out_index[k] * inverse_code_rate;
539        bottom_code_bits_llr.push(code_bits_llr[i_bottom]);
540        bottom_code_bits_llr.extend_from_slice(
541            &code_bits_llr[i_top + sm.num_output_bits .. i_top + inverse_code_rate],
542        );
543    }
544    // Tail bits
545    top_code_bits_llr.extend_from_slice(
546        &code_bits_llr[num_info_bits * inverse_code_rate
547            .. num_info_bits * inverse_code_rate + sm.memory_len * sm.num_output_bits],
548    );
549    bottom_code_bits_llr.extend_from_slice(
550        &code_bits_llr[num_info_bits * inverse_code_rate + sm.memory_len * sm.num_output_bits ..],
551    );
552    (top_code_bits_llr, bottom_code_bits_llr)
553}
554
555#[cfg(test)]
556mod tests_of_interleaver {
557    use super::*;
558
559    #[test]
560    fn test_new() {
561        // Invalid input
562        assert!(Interleaver::new(&[]).is_err());
563        assert!(Interleaver::new(&[1, 2, 3, 4]).is_err());
564        assert!(Interleaver::new(&[0, 1, 2, 4]).is_err());
565        assert!(Interleaver::new(&[0, 0, 1, 2]).is_err());
566        // Valid input
567        let interleaver = Interleaver::new(&[0, 3, 2, 5, 4, 7, 6, 1]).unwrap();
568        assert_eq!(interleaver.length, 8);
569        assert_eq!(
570            interleaver.all_in_index_given_out_index,
571            [0, 3, 2, 5, 4, 7, 6, 1]
572        );
573        assert_eq!(
574            interleaver.all_out_index_given_in_index,
575            [0, 7, 2, 1, 4, 3, 6, 5]
576        );
577    }
578
579    #[test]
580    fn test_random() {
581        let mut rng = rand::thread_rng();
582        // Invalid input
583        assert!(Interleaver::random(0, &mut rng).is_err());
584        // Valid input
585        let length = 8;
586        let interleaver = Interleaver::random(length, &mut rng).unwrap();
587        let mut o2i = interleaver.all_in_index_given_out_index;
588        o2i.sort_unstable();
589        assert!(o2i == (0 .. length).collect::<Vec<usize>>());
590    }
591
592    #[test]
593    fn test_interleave() {
594        let interleaver = Interleaver::new(&[0, 3, 2, 5, 4, 7, 6, 1]).unwrap();
595        let mut output = Vec::new();
596        // Invalid input
597        let input = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
598        assert!(interleaver.interleave(&input, &mut output).is_err());
599        // Valid input
600        let input = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
601        for _ in 0 .. 2 {
602            interleaver.interleave(&input, &mut output).unwrap();
603            assert_eq!(output, ['a', 'd', 'c', 'f', 'e', 'h', 'g', 'b']);
604        }
605    }
606
607    #[test]
608    fn test_deinterleave() {
609        let interleaver = Interleaver::new(&[0, 3, 2, 5, 4, 7, 6, 1]).unwrap();
610        let mut input = Vec::new();
611        // Invalid output
612        let output = ['a', 'd', 'c', 'f', 'e', 'h', 'g'];
613        assert!(interleaver.deinterleave(&output, &mut input).is_err());
614        // Valid output
615        let output = ['a', 'd', 'c', 'f', 'e', 'h', 'g', 'b'];
616        for _ in 0 .. 2 {
617            interleaver.deinterleave(&output, &mut input).unwrap();
618            assert_eq!(input, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
619        }
620    }
621
622    #[test]
623    fn test_from_valid_perm() {
624        let interleaver = Interleaver::from_valid_perm(vec![0, 3, 2, 5, 4, 7, 6, 1]);
625        assert_eq!(interleaver.length, 8);
626        assert_eq!(
627            interleaver.all_in_index_given_out_index,
628            [0, 3, 2, 5, 4, 7, 6, 1]
629        );
630        assert_eq!(
631            interleaver.all_out_index_given_in_index,
632            [0, 7, 2, 1, 4, 3, 6, 5]
633        );
634    }
635}
636
637#[cfg(test)]
638mod tests_of_functions {
639    use super::*;
640    use float_eq::assert_float_eq;
641    use Bit::{One, Zero};
642
643    #[test]
644    fn test_encoder() {
645        let code_polynomials = [0o13, 0o15];
646        let interleaver = Interleaver::new(&[3, 0, 1, 2]).unwrap();
647        // Invalid inputs
648        let info_bits = [Zero, One, One];
649        assert!(encoder(&info_bits, &interleaver, &code_polynomials).is_err());
650        // Valid inputs
651        let info_bits = [One, Zero, Zero, One];
652        let code_bits = encoder(&info_bits, &interleaver, &code_polynomials).unwrap();
653        assert_eq!(
654            code_bits,
655            [
656                One, One, One, Zero, One, Zero, Zero, One, Zero, One, Zero, Zero, One, Zero, One,
657                One, Zero, Zero, Zero, One, One, One, Zero, Zero
658            ]
659        );
660    }
661
662    #[test]
663    fn test_decoder() {
664        let code_polynomials = [0o13, 0o15];
665        let interleaver = Interleaver::new(&[3, 0, 1, 2]).unwrap();
666        // Invalid inputs
667        let code_bits_llr = [10.0, -10.0, -10.0];
668        assert!(decoder(
669            &code_bits_llr,
670            &interleaver,
671            &code_polynomials,
672            DecodingAlgo::LinearLogMAP(8),
673        )
674        .is_err());
675        // Valid inputs
676        let code_bits_llr = [
677            -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,
678            -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0,
679        ];
680        let info_bits_hat = decoder(
681            &code_bits_llr,
682            &interleaver,
683            &code_polynomials,
684            DecodingAlgo::LinearLogMAP(8),
685        )
686        .unwrap();
687        assert_eq!(info_bits_hat, [One, Zero, Zero, One]);
688    }
689
690    #[test]
691    fn test_check_decoder_inputs() {
692        let sm = rsc::StateMachine::new(&[0o13, 0o15]).unwrap();
693        let interleaver = Interleaver::new(&[0, 3, 1, 2]).unwrap();
694        // Invalid inputs
695        let code_bits_llr = [
696            0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
697            16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0,
698        ];
699        assert!(check_decoder_inputs(&code_bits_llr, &interleaver, &sm).is_err());
700        let code_bits_llr = [
701            0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
702            16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0,
703        ];
704        assert!(check_decoder_inputs(&code_bits_llr, &interleaver, &sm).is_err());
705        // Valid inputs
706        let code_bits_llr = [
707            0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
708            16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0,
709        ];
710        assert!(check_decoder_inputs(&code_bits_llr, &interleaver, &sm).is_ok());
711    }
712
713    #[test]
714    fn test_bcjr_inputs() {
715        let sm = rsc::StateMachine::new(&[0o13, 0o15]).unwrap();
716        let interleaver = Interleaver::new(&[0, 3, 1, 2]).unwrap();
717        let code_bits_llr = [
718            0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
719            16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0,
720        ];
721        let (top_code_bits_llr, bottom_code_bits_llr) =
722            bcjr_inputs(&code_bits_llr, &interleaver, &sm);
723        assert_float_eq!(
724            top_code_bits_llr,
725            [0.0, 1.0, 3.0, 4.0, 6.0, 7.0, 9.0, 10.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0].to_vec(),
726            abs_all <= 1e-8
727        );
728        assert_float_eq!(
729            bottom_code_bits_llr,
730            [0.0, 2.0, 9.0, 5.0, 3.0, 8.0, 6.0, 11.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0].to_vec(),
731            abs_all <= 1e-8
732        );
733    }
734}