use super::random_checks::Generator as CheckGenerator;
use super::CodeGenerator;
use crate::ParityCheckMatrix;
use rand::{thread_rng, Rng};
pub struct IncreasingRangeCodeGenerator {
initial_range: usize,
n_bits: usize,
n_checks: usize,
max_bit_degree: usize,
max_check_degree: usize,
minimal_girth: usize,
}
impl IncreasingRangeCodeGenerator {
fn get_random_range<R: Rng>(&self, range_length: usize, rng: &mut R) -> Vec<usize> {
if range_length >= self.n_bits {
(0..self.n_bits).collect()
} else {
let range_start = rng.gen_range(0, self.n_bits - range_length);
(range_start..range_start + range_length).collect()
}
}
}
impl CodeGenerator for IncreasingRangeCodeGenerator {
fn generate_with_rng<R: Rng>(&self, rng: &mut R) -> ParityCheckMatrix {
let mut check_generator =
CheckGenerator::with_n_bits(self.n_bits).with_random_number_generator(rng);
check_generator
.set_maximal_bit_degree(self.max_bit_degree)
.set_minimal_girth(self.minimal_girth)
.set_target_check_degree(self.max_check_degree)
.allow_checks_of_degree_at_least(2);
let mut checks = Vec::with_capacity(self.n_checks);
let mut range_length = self.initial_range;
let mut last_update = 0;
for c in 0..self.n_checks {
check_generator.set_over_bits(self.get_random_range(range_length, &mut thread_rng()));
if let Some(check) = check_generator.get_random_check() {
checks.push(check)
}
if (self.n_checks - last_update) <= 2 * c {
last_update = c;
range_length *= 2;
}
}
ParityCheckMatrix::with_n_bits(self.n_bits).with_checks(checks)
}
}
pub struct IRCodeGenBuilder {
n_bits: usize,
n_checks: usize,
initial_range: Option<usize>,
max_bit_degree: Option<usize>,
max_check_degree: Option<usize>,
minimal_girth: Option<usize>,
}
impl IRCodeGenBuilder {
pub fn build(&self) -> IncreasingRangeCodeGenerator {
IncreasingRangeCodeGenerator {
initial_range: self.initial_range(),
n_bits: self.n_bits(),
n_checks: self.n_checks(),
max_bit_degree: self.max_bit_degree(),
max_check_degree: self.max_check_degree(),
minimal_girth: self.minimal_girth(),
}
}
pub fn new(n_bits: usize, n_checks: usize) -> Self {
Self {
n_bits,
n_checks,
initial_range: None,
max_bit_degree: None,
max_check_degree: None,
minimal_girth: None,
}
}
pub fn with_max_bit_degree(&mut self, max_bit_degree: usize) -> &mut Self {
self.max_bit_degree = Some(max_bit_degree);
self
}
pub fn with_max_check_degree(&mut self, max_check_degree: usize) -> &mut Self {
self.max_check_degree = Some(max_check_degree);
self
}
pub fn with_max_degrees(
&mut self,
max_bit_degree: usize,
max_check_degree: usize,
) -> &mut Self {
self.max_bit_degree = Some(max_bit_degree);
self.max_check_degree = Some(max_check_degree);
self
}
pub fn with_initial_range(&mut self, initial_range: usize) -> &mut Self {
self.initial_range = Some(initial_range);
self
}
pub fn with_minimal_girth(&mut self, minimal_girth: usize) -> &mut Self {
self.minimal_girth = Some(minimal_girth);
self
}
fn initial_range(&self) -> usize {
self.initial_range.unwrap_or_else(|| self.n_bits() as usize)
}
fn n_bits(&self) -> usize {
self.n_bits
}
fn n_checks(&self) -> usize {
self.n_checks
}
fn max_bit_degree(&self) -> usize {
self.max_bit_degree.unwrap_or(self.n_checks() as usize)
}
fn max_check_degree(&self) -> usize {
self.max_check_degree.unwrap_or(self.n_bits() as usize)
}
fn minimal_girth(&self) -> usize {
self.minimal_girth.unwrap_or(0)
}
}