mod syndrome_based;
use super::galois::GF;
use alloc::{vec, vec::Vec};
#[cfg(test)]
use pretty_assertions::assert_eq;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ErrorDecodingError {
TooManyErrors,
ErrorsOutsideRange,
Malfunction,
}
pub use syndrome_based::decode;
fn primitive_element_evaluation<T, I>(c: I, out: &mut [GF]) -> bool
where
T: Into<GF> + Copy,
I: Iterator<Item = T> + DoubleEndedIterator,
{
if out.is_empty() {
return false;
}
let mut gamma: Vec<GF> = c.rev().map(Into::into).collect();
let mut errors = false;
for o in out.iter_mut() {
for (g, alpha) in gamma.iter_mut().zip(GF::primitive_powers()) {
*g *= alpha;
}
*o = gamma.iter().copied().sum();
errors = errors || (*o != GF(0));
}
errors
}
fn chien_search<T: Into<GF> + Copy>(c: &[T]) -> Vec<GF> {
let mut out = vec![];
if c.is_empty() {
return out;
}
if c.last().copied().unwrap().into() == GF(0) {
out.push(GF(0));
}
if c.len() == 2 {
if c[1].into() != GF(0) {
out.push(-c[1].into() / c[0].into());
}
return out;
}
let mut gamma: Vec<GF> = c.iter().rev().map(|x| (*x).into()).collect();
for i in 0..=254 {
let val: GF = gamma.iter().copied().sum();
if val == GF(0) {
out.push(GF::primitive_power(i));
}
for (g, alpha) in gamma.iter_mut().zip(GF::primitive_powers()) {
*g *= alpha;
}
}
out
}
#[allow(unused)]
fn solve(mat: &mut [GF], b: &mut [GF], row_stride: usize) -> bool {
let n = b.len();
let c = |i: usize, j: usize| i * row_stride + j;
for i in 0..(n - 1) {
if let Some(i_nz) = (i..n).find(|k| mat[c(*k, i)] != GF(0)) {
if i_nz != i {
b.swap(i, i_nz);
for j in 0..n {
mat.swap(c(i, j), c(i_nz, j));
}
}
} else {
return false;
};
for k in i + 1..n {
mat[c(k, i)] /= mat[c(i, i)];
for j in i + 1..n {
mat[c(k, j)] -= mat[c(k, i)] * mat[c(i, j)];
}
}
}
if mat[c(n - 1, n - 1)] == GF(0) {
return false;
}
for i in 0..n {
for j in 0..i {
let b_j = b[j];
b[i] -= mat[c(i, j)] * b_j;
}
}
for i in (0..n).rev() {
for j in i + 1..n {
let b_j = b[j];
b[i] -= mat[c(i, j)] * b_j;
}
b[i] /= mat[c(i, i)];
}
true
}
#[test]
fn test_evaluate_primitive() {
let c = &[GF(90), GF(0), GF(23), GF(0), GF(1)];
let mut out = vec![GF(0); 3];
primitive_element_evaluation(c.iter().cloned(), &mut out);
assert_eq!(out, vec![GF(100), GF(187), GF(131)]);
}
#[test]
fn test_solve_1x1() {
let mut mat = vec![GF(5)];
let mut b = [GF(88)];
let solved = solve(&mut mat, &mut b[..], 1);
assert!(solved);
assert_eq!(b, [GF(170)]);
}
#[test]
fn test_solve_2x2() {
let mut mat = vec![GF(2), GF(1), GF(5), GF(2)];
let mut b = [GF(56), GF(23)];
let solved = solve(&mut mat, &mut b[..], 2);
assert!(solved);
assert_eq!(GF(2) * b[0] + GF(1) * b[1], GF(56));
assert_eq!(GF(5) * b[0] + GF(2) * b[1], GF(23));
}
#[test]
fn test_solve_3x3_permute() {
let mut mat = vec![
GF(0),
GF(0),
GF(8),
GF(89),
GF(0),
GF(2),
GF(45),
GF(10),
GF(5),
];
let mut b = [GF(126), GF(23), GF(99)];
let solved = solve(&mut mat, &mut b[..], 3);
assert!(solved);
assert_eq!(GF(0) * b[0] + GF(0) * b[1] + GF(8) * b[2], GF(126));
assert_eq!(GF(89) * b[0] + GF(0) * b[1] + GF(2) * b[2], GF(23));
assert_eq!(GF(45) * b[0] + GF(10) * b[1] + GF(5) * b[2], GF(99));
}
#[test]
fn test_solve_2x2_singular() {
let mut mat = vec![GF(2), GF(1), GF(4), GF(2)];
let mut b = [GF(56), GF(23)];
let solved = solve(&mut mat, &mut b[..], 2);
assert!(!solved);
}
#[test]
fn test_primitive_element_evaluation() {
let x = [GF(128), GF(52), GF(33), GF(83), GF(33)];
let mut syndromes = vec![GF(0); 5];
primitive_element_evaluation(x.iter().cloned(), &mut syndromes);
assert_eq!(&syndromes, &[GF(203), GF(50), GF(3), GF(247), GF(100),]);
}
#[test]
fn test_error_code() {
let mut data = vec![1, 2, 3];
let ecc = super::encode_error(&data, crate::SymbolSize::Square10);
data.extend_from_slice(&ecc);
let mut syndromes = vec![GF(0); 5];
primitive_element_evaluation(data.iter().cloned(), &mut syndromes);
assert_eq!(&syndromes, &[GF(0), GF(0), GF(0), GF(0), GF(0)]);
}
#[test]
fn test_chien() {
let c = [GF(135), GF(239), GF(132), GF(21), GF(58), GF(77)];
let zeros = chien_search(&c);
assert_eq!(&zeros, &[GF(228), GF(78), GF(43)]);
}
#[test]
fn test_chien2() {
let c = [GF(1), GF(211)];
let zeros = chien_search(&c);
assert_eq!(&zeros, &[GF(211)]);
}
#[test]
fn test_chien3() {
let c = [GF(1), GF(0)];
let zeros = chien_search(&c);
assert_eq!(&zeros, &[GF(0)]);
}
#[test]
fn test_chien4() {
let c = [GF(2), GF(1)];
let zeros = chien_search(&c);
assert_eq!(&zeros, &[-GF(1) / GF(2)]);
}