ldpc_toolbox/cli/
encode.rs

1//! Encode CLI subcommand.
2//!
3//! This command can be used to encode using a systematic LDPC code.
4
5use super::ber::parse_puncturing_pattern;
6use crate::{
7    cli::Run, encoder::Encoder, gf2::GF2, simulation::puncturing::Puncturer, sparse::SparseMatrix,
8};
9use clap::Parser;
10use ndarray::Array1;
11use num_traits::{One, Zero};
12use std::{
13    error::Error,
14    fs::File,
15    io::{ErrorKind, Read, Write},
16    path::PathBuf,
17};
18
19/// Encode CLI arguments.
20#[derive(Debug, Parser)]
21#[command(about = "Performs LDPC encoding")]
22pub struct Args {
23    /// alist file for the code
24    pub alist: PathBuf,
25    /// input file (information words as unpacked bits)
26    pub input: PathBuf,
27    /// output file (punctured words as unpacked bits)
28    pub output: PathBuf,
29    /// Puncturing pattern (format "1,1,1,0")
30    #[structopt(long)]
31    pub puncturing: Option<String>,
32}
33
34impl Run for Args {
35    fn run(&self) -> Result<(), Box<dyn Error>> {
36        let puncturer = if let Some(p) = self.puncturing.as_ref() {
37            Some(Puncturer::new(&parse_puncturing_pattern(p)?))
38        } else {
39            None
40        };
41        let h = SparseMatrix::from_alist(&std::fs::read_to_string(&self.alist)?)?;
42        let mut input = File::open(&self.input)?;
43        let mut output = File::create(&self.output)?;
44        let encoder = Encoder::from_h(&h)?;
45        let n = h.num_cols();
46        let k = n - h.num_rows();
47        let mut information_word = vec![0; k];
48        let mut codeword_buf = vec![0; n];
49        loop {
50            match input.read_exact(&mut information_word[..]) {
51                Err(e) if e.kind() == ErrorKind::UnexpectedEof => break,
52                ret => ret?,
53            };
54            let word = Array1::from_iter(
55                information_word
56                    .iter()
57                    .map(|&b| if b == 1 { GF2::one() } else { GF2::zero() }),
58            );
59            let codeword = encoder.encode(&word);
60            let codeword = match &puncturer {
61                Some(p) => p.puncture(&codeword)?,
62                None => codeword,
63            };
64            for (x, y) in codeword.iter().zip(codeword_buf.iter_mut()) {
65                *y = x.is_one().into();
66            }
67            output.write_all(&codeword_buf)?;
68        }
69        Ok(())
70    }
71}