pub fn forward_dct_4x4(input: &[[i32; 4]; 4]) -> [[i32; 4]; 4] {
let mut f = [[0i32; 4]; 4];
for i in 0..4 {
let a = input[i][0] + input[i][3];
let b = input[i][1] + input[i][2];
let c = input[i][1] - input[i][2];
let d = input[i][0] - input[i][3];
f[i][0] = a + b;
f[i][1] = (d << 1) + c;
f[i][2] = a - b;
f[i][3] = d - (c << 1);
}
let mut y = [[0i32; 4]; 4];
for j in 0..4 {
let a = f[0][j] + f[3][j];
let b = f[1][j] + f[2][j];
let c = f[1][j] - f[2][j];
let d = f[0][j] - f[3][j];
y[0][j] = a + b;
y[1][j] = (d << 1) + c;
y[2][j] = a - b;
y[3][j] = d - (c << 1);
}
y
}
pub fn forward_hadamard_4x4(input: &[[i32; 4]; 4]) -> [[i32; 4]; 4] {
let mut f = [[0i32; 4]; 4];
for i in 0..4 {
let a0 = input[i][0] + input[i][2];
let a1 = input[i][1] + input[i][3];
let a2 = input[i][0] - input[i][2];
let a3 = input[i][1] - input[i][3];
f[i][0] = a0 + a1;
f[i][1] = a2 + a3;
f[i][2] = a2 - a3;
f[i][3] = a0 - a1;
}
let mut y = [[0i32; 4]; 4];
for j in 0..4 {
let b0 = f[0][j] + f[2][j];
let b1 = f[1][j] + f[3][j];
let b2 = f[0][j] - f[2][j];
let b3 = f[1][j] - f[3][j];
y[0][j] = b0 + b1;
y[1][j] = b2 + b3;
y[2][j] = b2 - b3;
y[3][j] = b0 - b1;
}
y
}
pub fn forward_hadamard_2x2(input: &[[i32; 2]; 2]) -> [[i32; 2]; 2] {
let r00 = input[0][0] + input[0][1];
let r01 = input[0][0] - input[0][1];
let r10 = input[1][0] + input[1][1];
let r11 = input[1][0] - input[1][1];
[
[r00 + r10, r01 + r11],
[r00 - r10, r01 - r11],
]
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codec::h264::transform::inverse_4x4_integer;
#[test]
fn dct_zero_input_zero_output() {
let zero = [[0i32; 4]; 4];
let y = forward_dct_4x4(&zero);
for row in &y {
assert_eq!(row, &[0, 0, 0, 0]);
}
}
#[test]
fn dct_flat_input_only_dc_nonzero() {
let flat = [[5i32; 4]; 4];
let y = forward_dct_4x4(&flat);
assert_eq!(y[0][0], 16 * 5);
for i in 0..4 {
for j in 0..4 {
if (i, j) != (0, 0) {
assert_eq!(y[i][j], 0, "AC at ({i},{j}) must be zero for flat input");
}
}
}
}
#[test]
fn dct_linearity() {
let a = [
[10, -5, 22, -3],
[7, 0, -11, 4],
[-2, 18, -6, 1],
[9, -14, 0, 12],
];
let b = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16],
];
let mut sum = [[0i32; 4]; 4];
for i in 0..4 {
for j in 0..4 {
sum[i][j] = a[i][j] + b[i][j];
}
}
let ya = forward_dct_4x4(&a);
let yb = forward_dct_4x4(&b);
let ysum = forward_dct_4x4(&sum);
for i in 0..4 {
for j in 0..4 {
assert_eq!(
ysum[i][j],
ya[i][j] + yb[i][j],
"linearity at ({i},{j})"
);
}
}
}
#[test]
fn dct_delta_at_origin_is_outer_product_of_first_rows() {
let mut x = [[0i32; 4]; 4];
x[0][0] = 1;
let y = forward_dct_4x4(&x);
let t_col0 = [1, 2, 1, 1];
for i in 0..4 {
for j in 0..4 {
assert_eq!(
y[i][j],
t_col0[i] * t_col0[j],
"delta @ (0,0) at ({i},{j})"
);
}
}
}
#[test]
fn dct_inverse_approx_shape_recovered() {
let x = [
[16, -16, 16, -16],
[16, -16, 16, -16],
[16, -16, 16, -16],
[16, -16, 16, -16],
];
let y = forward_dct_4x4(&x);
let recovered = inverse_4x4_integer(&y);
for i in 0..4 {
for j in 0..4 {
assert_eq!(
recovered[i][j].signum(),
x[i][j].signum(),
"sign flip at ({i},{j}): {} → {}",
x[i][j],
recovered[i][j],
);
}
}
}
#[test]
fn hadamard4_zero_input_zero_output() {
let zero = [[0i32; 4]; 4];
let y = forward_hadamard_4x4(&zero);
for row in &y {
assert_eq!(row, &[0, 0, 0, 0]);
}
}
#[test]
fn hadamard4_flat_input_only_top_left_nonzero() {
let flat = [[3i32; 4]; 4];
let y = forward_hadamard_4x4(&flat);
assert_eq!(y[0][0], 16 * 3);
for i in 0..4 {
for j in 0..4 {
if (i, j) != (0, 0) {
assert_eq!(y[i][j], 0, "Hadamard AC at ({i},{j})");
}
}
}
}
#[test]
fn hadamard4_self_inverse_up_to_scale16() {
let x = [
[1, -2, 3, -4],
[5, 6, -7, 8],
[-9, 10, 11, -12],
[13, -14, -15, 16],
];
let once = forward_hadamard_4x4(&x);
let twice = forward_hadamard_4x4(&once);
for i in 0..4 {
for j in 0..4 {
assert_eq!(
twice[i][j],
16 * x[i][j],
"H4² scale at ({i},{j})"
);
}
}
}
#[test]
fn hadamard2_zero_input_zero_output() {
let zero = [[0i32; 2]; 2];
let y = forward_hadamard_2x2(&zero);
assert_eq!(y, [[0, 0], [0, 0]]);
}
#[test]
fn hadamard2_flat_input_only_top_left_nonzero() {
let flat = [[7i32; 2]; 2];
let y = forward_hadamard_2x2(&flat);
assert_eq!(y, [[28, 0], [0, 0]]);
}
#[test]
fn hadamard2_self_inverse_up_to_scale4() {
let x = [[3, -5], [7, -2]];
let once = forward_hadamard_2x2(&x);
let twice = forward_hadamard_2x2(&once);
assert_eq!(twice, [[4 * x[0][0], 4 * x[0][1]], [4 * x[1][0], 4 * x[1][1]]]);
}
#[test]
fn hadamard2_known_delta() {
let mut x = [[0i32; 2]; 2];
x[0][0] = 1;
let y = forward_hadamard_2x2(&x);
assert_eq!(y, [[1, 1], [1, 1]]);
}
}