use crate::degree_sets::asymp_optimal_cdf;
use crate::degree_sets::validate_cdf;
use crate::degree_sets::RaptorDegreeSetGenerator;
use crate::parameters::rq_like;
use crate::precodes::default_rq_hdpc;
use crate::precodes::RQLDPC;
use crate::types::ProbValue;
use crate::types::PseudoRandom;
use fountain_engine::traits::{CodeScheme, HDPC, LDPC};
use fountain_engine::types::{CodeParams, CodeType, DecodingConfig, DegreeSetFn};
#[derive(Clone)]
pub struct HDPCLTCode<R: PseudoRandom> {
degree_cdf: Vec<ProbValue>,
params: CodeParams,
rng: R,
code_type: CodeType,
}
fn hdpc_lt_code_params(k: usize) -> CodeParams {
rq_like::generate_rq_like_parameters(k)
}
impl<R: PseudoRandom> HDPCLTCode<R> {
pub fn new(k: usize, cdf: Vec<ProbValue>, rng: R) -> Self {
let m = cdf.last().expect("CDF must be non-empty");
if !validate_cdf(&cdf, *m as usize) {
panic!("Invalid CDF: {:?}", cdf);
}
Self {
degree_cdf: cdf,
params: hdpc_lt_code_params(k),
rng,
code_type: CodeType::Ordinary,
}
}
pub fn new_with_ideal_soliton(k: usize, rng: R) -> Self {
let params = hdpc_lt_code_params(k);
let cdf = asymp_optimal_cdf(k, 2, k);
Self {
degree_cdf: cdf,
params,
rng,
code_type: CodeType::Ordinary,
}
}
pub fn as_systematic(&mut self) {
self.code_type = CodeType::Systematic;
}
}
impl<R: PseudoRandom + 'static> CodeScheme for HDPCLTCode<R> {
fn get_params(&self) -> CodeParams {
self.params.clone()
}
fn code_type(&self) -> CodeType {
self.code_type
}
fn create_degree_set_fn(&self) -> DegreeSetFn {
let mut degree_set = if self.code_type == CodeType::Systematic {
RaptorDegreeSetGenerator::new_systematic(
self.degree_cdf.clone(),
self.params.clone(),
self.rng.clone(),
)
} else {
RaptorDegreeSetGenerator::new(
self.degree_cdf.clone(),
self.params.clone(),
self.rng.clone(),
)
};
Box::new(move |coded_id| degree_set.degree_set(coded_id))
}
fn create_precode(&self) -> (Option<Box<dyn HDPC>>, Option<Box<dyn LDPC>>) {
let hdpc = (self.params.h > 0).then(|| default_rq_hdpc(self.params.h));
let ldpc = (self.params.l > 0).then(|| Box::new(RQLDPC::new(&self.params)) as Box<dyn LDPC>);
(hdpc, ldpc)
}
fn decoding_config(&self) -> DecodingConfig {
DecodingConfig::default().with_max_inact_num((self.params.h + self.params.b + 5).min(128))
}
}