use crate::algebra::linear_algebra::Matrix;
use crate::data_manager::DataManager;
use crate::traits::CodeScheme;
use crate::traits::HDPC;
use crate::traits::LDPC;
use crate::types::CodeParams;
use crate::algebra::finite_field::GF2;
pub fn precode_encode<T: CodeScheme>(manager: &mut DataManager, params: &CodeParams, custom: &T) {
let (hdpc, ldpc) = custom.create_precode();
if let Some(ldpc) = ldpc.as_ref() {
ldpc.encode(manager, params);
}
if let Some(hdpc) = hdpc {
manager.config_finite_field(hdpc.gf_poly());
let variable_ids_kl: Vec<usize> = manager.data_id_range_of_msg_ldpc_variable();
let mut hdpc_constraint_data_ids = Vec::with_capacity(params.h);
for _ in 0..params.h {
hdpc_constraint_data_ids.push(manager.temp_data_id());
}
hdpc.mul_data(manager, params, &variable_ids_kl, &hdpc_constraint_data_ids);
hdpc_solve(
manager,
params,
&hdpc,
ldpc.as_ref().unwrap(),
&hdpc_constraint_data_ids,
);
}
}
#[allow(clippy::borrowed_box)]
fn hdpc_solve(
manager: &mut DataManager,
params: &CodeParams,
hdpc: &Box<dyn HDPC>,
ldpc: &Box<dyn LDPC>,
hdpc_ids: &[usize],
) {
let ldpc_adj_check_inactive = |row: usize| {
ldpc.inactive_row(row)
.iter()
.filter(|&id| *id >= params.b)
.map(|&id| id - params.b)
.collect::<Vec<_>>()
};
let mut idssh = hdpc.mul_sparse_sh(manager.gf256(), params, &ldpc_adj_check_inactive);
for (i, row) in idssh.iter_mut().take(params.h).enumerate() {
row[i] ^= 1;
}
let (p, r) = match manager.gf256() {
Some(gf) => Matrix::lu_decomp(gf, &mut idssh),
None => Matrix::lu_decomp(&GF2::new(), &mut idssh),
};
if r < params.h {
panic!("The matrix I'+D_sS_h is not invertible, rank = {}", r);
}
let variable_ids_hdpc: Vec<usize> = manager.data_id_range_of_hdpc_variable();
for i in 0..params.h {
manager.move_to(hdpc_ids[p[i]], variable_ids_hdpc[i]);
}
lu_solve(manager, &mut idssh, &variable_ids_hdpc);
for (var_col, &var_id) in variable_ids_hdpc.iter().take(params.h).enumerate() {
let ids = ldpc.inactive_column(var_col + params.b);
let ids = ids
.iter()
.map(|&id| manager.data_id_of_ldpc_variable(id))
.collect::<Vec<_>>();
manager.broadcast_add(var_id, &ids);
}
}
fn lu_solve(manager: &mut DataManager, matrix_a: &mut [Vec<u8>], target_ids: &[usize]) {
if matrix_a.len() != target_ids.len() {
panic!("The number of rows in A must be equal to the number of target IDs");
}
let n = matrix_a.len();
for j in 0..n - 1 {
for i in j + 1..n {
if matrix_a[i][j] != 0 {
manager.mul_add(target_ids[j], matrix_a[i][j], target_ids[i]);
}
}
}
for j in (0..n).rev() {
if matrix_a[j][j] == 0 {
panic!(
"Singular matrix: diagonal element at position {} is zero",
j
);
}
manager.divide_scalar(matrix_a[j][j], target_ids[j]);
for i in (0..j).rev() {
if matrix_a[i][j] != 0 {
manager.mul_add(target_ids[j], matrix_a[i][j], target_ids[i]);
}
}
}
}