-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add transformation to systematic code
This adds a CLI command that transforms a parity check matrix to one that can be used for systematic encoding with the first variables by permuting columns of the parity check matrix. The crate::encoder::gauss module has been moved to crate::linalg because it is now used outside crate::encoder too.
- Loading branch information
1 parent
b0c7095
commit 53dec0d
Showing
6 changed files
with
208 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//! Systematic CLI subcommand. | ||
//! | ||
//! This command can be used to convert an n x m parity check matrix into one | ||
//! that supports systematic encoding using the first m - n columns by permuting | ||
//! columns in such a way that the n x n submatrix formed by the last n columns | ||
//! is invertible. | ||
|
||
use crate::{cli::Run, sparse::SparseMatrix, systematic::parity_to_systematic}; | ||
use clap::Parser; | ||
use std::error::Error; | ||
|
||
/// Systematic CLI arguments. | ||
#[derive(Debug, Parser)] | ||
#[command(about = "Converts a parity check matrix into systematic form")] | ||
pub struct Args { | ||
/// alist file for the code | ||
alist: String, | ||
} | ||
|
||
impl Run for Args { | ||
fn run(&self) -> Result<(), Box<dyn Error>> { | ||
let h = SparseMatrix::from_alist(&std::fs::read_to_string(&self.alist)?)?; | ||
let h_sys = parity_to_systematic(&h)?; | ||
println!("{}", h_sys.alist()); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,5 +21,7 @@ pub mod peg; | |
pub mod rand; | ||
pub mod simulation; | ||
pub mod sparse; | ||
pub mod systematic; | ||
|
||
mod linalg; | ||
mod util; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
//! Systematic code constructions. | ||
//! | ||
//! This module contains a function [`parity_to_systematic`] that can be used to | ||
//! convert a full-rank parity check matrix into one that supports systematic | ||
//! encoding using the first variables (as done by the systematic encoder in the | ||
//! [`encoder`](crate::encoder) module) by permuting the columns of the parity | ||
//! check matrix. | ||
|
||
use crate::{gf2::GF2, linalg, sparse::SparseMatrix}; | ||
use ndarray::Array2; | ||
use num_traits::{One, Zero}; | ||
use thiserror::Error; | ||
|
||
/// Systematic construction error. | ||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Error)] | ||
pub enum Error { | ||
/// The parity check matrix has more rows than columns. | ||
#[error("the parity check matrix has more rows than columns")] | ||
ParityOverdetermined, | ||
/// The parity check matrix does not have full rank. | ||
#[error("the parity check matrix does not have full rank")] | ||
NotFullRank, | ||
} | ||
|
||
/// Permutes the columns of the parity check matrix to obtain a parity check | ||
/// matrix that supports systematic encoding using the first variables. | ||
/// | ||
/// This function returns a parity check matrix obtaining by permuting the | ||
/// columns of `h` in such a way that the square submatrix formed by the last | ||
/// columns is invertible. | ||
pub fn parity_to_systematic(h: &SparseMatrix) -> Result<SparseMatrix, Error> { | ||
let n = h.num_rows(); | ||
let m = h.num_cols(); | ||
if n > m { | ||
return Err(Error::ParityOverdetermined); | ||
} | ||
let mut a = Array2::zeros((n, m)); | ||
for (j, k) in h.iter_all() { | ||
a[[j, k]] = GF2::one(); | ||
} | ||
linalg::row_echelon_form(&mut a); | ||
// write point for columns that do not "go down" in the row echelon form | ||
let mut k = 0; | ||
let mut h_new = SparseMatrix::new(n, m); | ||
let mut j0 = 0; | ||
for j in 0..n { | ||
assert!(k < m - n); | ||
let mut found = false; | ||
for s in j0..m { | ||
if a[[j, s]] == GF2::zero() { | ||
// Column does not "go down" on row echelon form. Place it at the current write point. | ||
for &u in h.iter_col(s) { | ||
h_new.insert(u, k); | ||
} | ||
k += 1; | ||
} else { | ||
// Column goes down on row echelon form. Move to its appropriate | ||
// position in the last columns. | ||
let col = m - n + j; | ||
for &u in h.iter_col(s) { | ||
h_new.insert(u, col); | ||
} | ||
found = true; | ||
j0 = s + 1; | ||
break; | ||
} | ||
} | ||
if !found { | ||
// No column "going down" found. The matrix doesn't have full rank. | ||
return Err(Error::NotFullRank); | ||
} | ||
} | ||
// Insert remaining columns at the write point | ||
for j in j0..m { | ||
assert!(k < m - n); | ||
for &u in h.iter_col(j) { | ||
h_new.insert(u, k); | ||
} | ||
k += 1; | ||
} | ||
Ok(h_new) | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
#[test] | ||
fn to_systematic() { | ||
let mut h = SparseMatrix::new(3, 9); | ||
h.insert_col(0, [0, 1, 2].into_iter()); | ||
h.insert_col(1, [0, 2].into_iter()); | ||
// h.insert_col(2, [].into_iter()); this does nothing and does not compile | ||
h.insert_col(3, [1].into_iter()); | ||
h.insert_col(4, [0, 1].into_iter()); | ||
h.insert_col(5, [1, 2].into_iter()); | ||
h.insert_col(6, [0, 2].into_iter()); | ||
h.insert_col(7, [1].into_iter()); | ||
h.insert_col(8, [0, 2].into_iter()); | ||
let mut expected = SparseMatrix::new(3, 9); | ||
expected.insert_col(6, [0, 1, 2].into_iter()); | ||
expected.insert_col(7, [0, 2].into_iter()); | ||
// expected.insert_col(0, [].into_iter()); this does nothing and does not compile | ||
expected.insert_col(1, [1].into_iter()); | ||
expected.insert_col(8, [0, 1].into_iter()); | ||
expected.insert_col(2, [1, 2].into_iter()); | ||
expected.insert_col(3, [0, 2].into_iter()); | ||
expected.insert_col(4, [1].into_iter()); | ||
expected.insert_col(5, [0, 2].into_iter()); | ||
assert_eq!(parity_to_systematic(&h).unwrap(), expected); | ||
} | ||
} |