init
This commit is contained in:
202
srctmp/encoder.rs
Normal file
202
srctmp/encoder.rs
Normal file
@ -0,0 +1,202 @@
|
||||
use crate::code::{LdpcCode, SystematicForm};
|
||||
use crate::matrix::{DenseMatrixGF2, SparseMatrixGF2};
|
||||
use crate::{BitVec, Gf2, LdpcError, Result};
|
||||
|
||||
// Trait Encoder
|
||||
|
||||
pub trait Encoder: Send + Sync {
|
||||
fn encode(&self, message: &[Gf2]) -> Result<BitVec>;
|
||||
fn message_len(&self) -> usize;
|
||||
fn codeword_len(&self) -> usize;
|
||||
|
||||
fn check_input(&self, msg: &[Gf2]) -> Result<()> {
|
||||
if msg.len() != self.message_len() {
|
||||
return Err(LdpcError::DimensionMismatch {
|
||||
expected: self.message_len(),
|
||||
got: msg.len(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode d'encodage
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EncodingMethod {
|
||||
// Via G = [I_k | P]. Complexité O(n^2). Point de départ simple
|
||||
Systematic,
|
||||
// Richardson-Urbanke. Complexité O(n + g^2), g = gap << n
|
||||
RichardsonUrbanke,
|
||||
}
|
||||
|
||||
// Encodeur systématique
|
||||
// c = m * G = [m | m*P]
|
||||
// Les bits de parité p = m * P sont calculés par multiplication dense
|
||||
// Le mot de code est ensuite réordonné selon la permutation inverse
|
||||
|
||||
pub struct SystematicEncoder {
|
||||
k: usize,
|
||||
n: usize,
|
||||
g: DenseMatrixGF2,
|
||||
perm_inv: Vec<usize>,
|
||||
}
|
||||
|
||||
impl SystematicEncoder {
|
||||
pub fn new(code: &mut LdpcCode) -> Result<Self> {
|
||||
code.compute_systematic_form()?;
|
||||
let sf = code.systematic_form.as_ref().unwrap();
|
||||
Ok(Self {
|
||||
k: code.k(),
|
||||
n: code.n(),
|
||||
g: sf.g.clone(),
|
||||
perm_inv: sf.col_perm_inv.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encoder for SystematicEncoder {
|
||||
fn encode(&self, message: &[Gf2]) -> Result<BitVec> {
|
||||
self.check_input(message)?;
|
||||
let c_perm = self.g.multiply_vec(message);
|
||||
// Réordonner les bits selon la permutation inverse
|
||||
let mut c = vec![0u8; self.n];
|
||||
for (i, &ci) in c_perm.iter().enumerate() {
|
||||
c[self.perm_inv[i]] = ci;
|
||||
}
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
fn message_len(&self) -> usize {
|
||||
self.k
|
||||
}
|
||||
fn codeword_len(&self) -> usize {
|
||||
self.n
|
||||
}
|
||||
}
|
||||
|
||||
// Encodeur Richardson-Urbanke
|
||||
// H est réarrangée par permutations en :
|
||||
//
|
||||
// ┌ ┐
|
||||
// │ A B T │
|
||||
// H = │ │ T = triangulaire inférieure, φ = -ET^{-1}B + D
|
||||
// │ C D E │
|
||||
// └ ┘
|
||||
//
|
||||
// Encodage en deux étapes :
|
||||
// 1. p₂ = φ^{-1} * (-ET^{-1}*As - Cs) [dense g×g, g = gap]
|
||||
// 2. p₁ = T^{-1} * (As + Bp₂) [substitution arrière]
|
||||
// Complexité totale : O(n + g²)
|
||||
|
||||
pub struct RichardsonUrbankeEncoder {
|
||||
k: usize,
|
||||
n: usize,
|
||||
a: SparseMatrixGF2,
|
||||
b: SparseMatrixGF2,
|
||||
c: SparseMatrixGF2,
|
||||
d: SparseMatrixGF2,
|
||||
e: SparseMatrixGF2,
|
||||
// T^{-1} : résolution par substitution arrière (T triangulaire inférieure)
|
||||
t_inv: DenseMatrixGF2,
|
||||
// φ^{-1} : petit (g×g), calculé une fois offline
|
||||
phi_inv: DenseMatrixGF2,
|
||||
col_perm_inv: Vec<usize>,
|
||||
}
|
||||
|
||||
impl RichardsonUrbankeEncoder {
|
||||
pub fn new(code: &LdpcCode) -> Result<Self> {
|
||||
// TODO: implémenter le pré-traitement de H par permutations de lignes/colonnes
|
||||
// pour identifier les blocs A, B, C, D, E, T et calculer phi^{-1}.
|
||||
todo!("Pré-traitement Richardson-Urbanke")
|
||||
}
|
||||
|
||||
// Substitution arrière sur T triangulaire inférieure : résout T*x = b en GF(2)
|
||||
fn backward_substitution(t_inv: &DenseMatrixGF2, b: &[Gf2]) -> Vec<Gf2> {
|
||||
let n = b.len();
|
||||
let mut x = vec![0u8; n];
|
||||
for i in 0..n {
|
||||
let mut s = b[i];
|
||||
for j in 0..i {
|
||||
s ^= t_inv.get(i, j) & x[j];
|
||||
}
|
||||
x[i] = s;
|
||||
}
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
impl Encoder for RichardsonUrbankeEncoder {
|
||||
fn encode(&self, message: &[Gf2]) -> Result<BitVec> {
|
||||
self.check_input(message)?;
|
||||
// Étape 1 : As
|
||||
let a_s = self.a.multiply_vec(message);
|
||||
// Étape 2 : p₂ = φ^{-1} * (E*T^{-1}*As + Cs)
|
||||
let t_inv_as = Self::backward_substitution(&self.t_inv, &a_s);
|
||||
let e_t_inv_as = self.e.multiply_vec(&t_inv_as);
|
||||
let c_s = self.c.multiply_vec(message);
|
||||
let rhs: Vec<Gf2> = e_t_inv_as
|
||||
.iter()
|
||||
.zip(c_s.iter())
|
||||
.map(|(&a, &b)| a ^ b)
|
||||
.collect();
|
||||
let p2 = self.phi_inv.multiply_vec(&rhs);
|
||||
// Étape 3 : p₁ = T^{-1} * (As + Bp₂)
|
||||
let b_p2 = self.b.multiply_vec(&p2);
|
||||
let sum: Vec<Gf2> = a_s.iter().zip(b_p2.iter()).map(|(&a, &b)| a ^ b).collect();
|
||||
let p1 = Self::backward_substitution(&self.t_inv, &sum);
|
||||
// Assemblage et dépermutation
|
||||
let mut c_perm: Vec<Gf2> = message
|
||||
.iter()
|
||||
.chain(p1.iter())
|
||||
.chain(p2.iter())
|
||||
.cloned()
|
||||
.collect();
|
||||
let mut c = vec![0u8; self.n];
|
||||
for (i, &ci) in c_perm.iter().enumerate() {
|
||||
c[self.col_perm_inv[i]] = ci;
|
||||
}
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
fn message_len(&self) -> usize {
|
||||
self.k
|
||||
}
|
||||
fn codeword_len(&self) -> usize {
|
||||
self.n
|
||||
}
|
||||
}
|
||||
|
||||
// Factory
|
||||
|
||||
pub fn build_encoder(code: &mut LdpcCode, method: EncodingMethod) -> Result<Box<dyn Encoder>> {
|
||||
match method {
|
||||
EncodingMethod::Systematic => Ok(Box::new(SystematicEncoder::new(code)?)),
|
||||
EncodingMethod::RichardsonUrbanke => Ok(Box::new(RichardsonUrbankeEncoder::new(code)?)),
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use crate::code::{CodeTopology, GenerationMethod, LdpcCode, LdpcParams};
|
||||
//
|
||||
// fn make_code() -> LdpcCode {
|
||||
// LdpcCode::new(LdpcParams {
|
||||
// n: 12,
|
||||
// k: 6,
|
||||
// topology: CodeTopology::Regular { wc: 2, wr: 4 },
|
||||
// generation: GenerationMethod::Gallager,
|
||||
// seed: Some(42),
|
||||
// })
|
||||
// .unwrap()
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_encoder_wrong_input_length_errors() {
|
||||
// let mut code = make_code();
|
||||
// let enc = SystematicEncoder::new(&mut code).unwrap();
|
||||
// let result = enc.encode(&vec![0u8; 5]); // devrait être 6
|
||||
// assert!(result.is_err());
|
||||
// }
|
||||
// }
|
||||
Reference in New Issue
Block a user