use fountain_engine::DataManager;
use fountain_engine::GF256;
use fountain_engine::traits::HDPC;
use fountain_engine::types::CodeParams;
use fountain_engine::types::SolverType;
use fountain_utility::VecDataOperater;
pub fn validate_hdpc_mul_sparse<T: HDPC + ?Sized>(
hdpc: &T,
params: &CodeParams,
sh_fn: &dyn Fn(usize) -> Vec<usize>,
gf: &GF256,
) {
let h = params.h;
let l = params.l;
let a = params.a;
let result_mul_sparse_sh = hdpc.mul_sparse_sh(Some(gf), params, &sh_fn);
let v = |row: usize| -> Vec<u8> {
let mut col = vec![0u8; h];
if row < a {
} else if row < a + l {
for &j in &sh_fn(row - a) {
col[j] = 1;
}
}
col
};
let result_mul_binary = hdpc.mul_binary(Some(gf), params, h, &v);
assert_eq!(
result_mul_sparse_sh.len(),
h,
"HDPC validation failed: mul_sparse_sh returned {} rows, expected {}",
result_mul_sparse_sh.len(),
h
);
assert_eq!(
result_mul_binary.len(),
h,
"HDPC validation failed: mul_binary returned {} rows, expected {}",
result_mul_binary.len(),
h
);
for i in 0..h {
assert_eq!(
result_mul_sparse_sh[i].len(),
h,
"HDPC validation failed: mul_sparse_sh row {} has {} columns, expected {}",
i,
result_mul_sparse_sh[i].len(),
h
);
assert_eq!(
result_mul_binary[i].len(),
h,
"HDPC validation failed: mul_binary row {} has {} columns, expected {}",
i,
result_mul_binary[i].len(),
h
);
for j in 0..h {
assert_eq!(
result_mul_sparse_sh[i][j], result_mul_binary[i][j],
"HDPC validation failed: mul_sparse_sh and mul_binary differ at position ({}, {}) for D_s S_h: {} vs {}",
i, j, result_mul_sparse_sh[i][j], result_mul_binary[i][j]
);
}
}
}
#[allow(clippy::too_many_lines)]
pub fn validate_hdpc_mul_data<T: HDPC + ?Sized>(
hdpc: &T,
params: &CodeParams,
matrix_x: &[Vec<u8>],
gf: &GF256,
) {
let h = params.h;
let kl = params.num_message_ldpc();
let vector_length = matrix_x[0].len();
assert!(
kl == matrix_x.len(),
"HDPC validation failed: kl != matrix_x.len()"
);
let v = |row: usize| -> Vec<u8> { matrix_x[row].clone() };
let result_mul_binary_dx = hdpc.mul_binary(Some(gf), params, vector_length, &v);
let mut manager = DataManager::new_with_operator(Box::new(VecDataOperater::new_with_gf256(
vector_length,
gf.primitive_polynomial(),
)));
manager.config_from(params.clone(), SolverType::OrdEnc);
let x_ids: Vec<usize> = (0..kl).collect();
for i in 0..kl {
manager.insert_data_vector(x_ids[i], &matrix_x[i]);
}
let y_ids: Vec<usize> = (kl..kl + h).collect();
for &id in &y_ids {
manager.ensure_zero_one(id);
}
hdpc.mul_data(&mut manager, params, &x_ids, &y_ids);
let result_mul_data: Vec<Vec<u8>> = y_ids
.iter()
.map(|&id| manager.get_data_vector(id).to_vec())
.collect();
for i in 0..h {
assert_eq!(
result_mul_binary_dx[i].len(),
vector_length,
"HDPC validation failed: mul_binary row {} has {} columns, expected {}",
i,
result_mul_binary_dx[i].len(),
vector_length
);
assert_eq!(
result_mul_data[i].len(),
vector_length,
"HDPC validation failed: mul_data row {} has {} columns, expected {}",
i,
result_mul_data[i].len(),
vector_length
);
for j in 0..vector_length {
assert_eq!(
result_mul_binary_dx[i][j], result_mul_data[i][j],
"HDPC validation failed: mul_binary and mul_data differ at position ({}, {}) for D*X: {} vs {}",
i, j, result_mul_binary_dx[i][j], result_mul_data[i][j]
);
}
}
let a = params.a;
let l = params.l;
let al = a + l;
let v_2 = |row: usize| -> Vec<u8> {
if row < al {
matrix_x[row].clone()
} else {
vec![0u8; vector_length]
}
};
let result_mul_binary_dx_2 = hdpc.mul_binary(Some(gf), params, vector_length, &v_2);
let mut manager = DataManager::new_with_operator(Box::new(VecDataOperater::new_with_gf256(
vector_length,
gf.primitive_polynomial(),
)));
manager.config_from(params.clone(), SolverType::OrdEnc);
let x_ids: Vec<usize> = (0..al).collect();
for i in x_ids.clone() {
manager.insert_data_vector(i, &matrix_x[i]);
}
let y_ids: Vec<usize> = (al..al + h).collect();
for &id in &y_ids {
manager.ensure_zero_one(id);
}
hdpc.mul_data(&mut manager, params, &x_ids, &y_ids);
let result_mul_data_2: Vec<Vec<u8>> = y_ids
.iter()
.map(|&id| manager.get_data_vector(id).to_vec())
.collect();
for i in 0..h {
assert_eq!(
result_mul_binary_dx_2[i].len(),
vector_length,
"HDPC validation failed: mul_binary row {} has {} columns, expected {}",
i,
result_mul_binary_dx_2[i].len(),
vector_length
);
assert_eq!(
result_mul_data_2[i].len(),
vector_length,
"HDPC validation failed: mul_data row {} has {} columns, expected {}",
i,
result_mul_data_2[i].len(),
vector_length
);
for j in 0..vector_length {
assert_eq!(
result_mul_binary_dx_2[i][j], result_mul_data_2[i][j],
"HDPC validation failed: `mul_binary` and `mul_data` differ at position ({}, {}) for D*X': {} vs {}",
i, j, result_mul_binary_dx_2[i][j], result_mul_data_2[i][j]
);
}
}
}
#[cfg(test)]
pub fn cross_validate_hdpc<T: HDPC + ?Sized>(hdpc: &T, params: &CodeParams, gf: &GF256) {
use rand::rngs::StdRng;
use rand::seq::SliceRandom;
use rand::{Rng, SeedableRng};
let h = params.h;
let kl = params.num_message_ldpc();
let mut rng = rand::thread_rng();
let sh_fn = |row: usize| -> Vec<usize> {
let mut r = StdRng::seed_from_u64(row as u64);
let mut cols: Vec<usize> = (0..h).collect();
cols.shuffle(&mut r);
cols.truncate(3.min(h));
cols
};
validate_hdpc_mul_sparse(hdpc, params, &sh_fn, gf);
let vector_length = 4.max(h / 2);
let mut matrix_x = vec![vec![0u8; vector_length]; kl];
for i in 0..kl {
let num_ones = rng.gen_range(1..=vector_length);
let mut cols: Vec<usize> = (0..vector_length).collect();
cols.shuffle(&mut rng);
for j in 0..num_ones {
matrix_x[i][cols[j]] = 1;
}
}
validate_hdpc_mul_data(hdpc, params, &matrix_x, gf);
}