#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, Default)]
pub enum Axis {
#[default]
Row,
Column,
}
pub fn dct2_in_place(input: &mut [f64], skip: usize, buf: &mut [f64]) {
assert!(skip > 0, "skip value must be greater than 0");
if input.is_empty() {
return;
}
let n = input.len().div_ceil(skip);
assert!(n <= buf.len(), "buffer is too small for the DCT result");
(0..n)
.map(|k| {
2.0 * input
.chunks(skip)
.enumerate()
.map(|(i, x)| {
let numerator = std::f64::consts::PI * k as f64 * (2 * i + 1) as f64;
let denominator = (2 * n) as f64;
let cosine = (numerator / denominator).cos();
x[0] * cosine
})
.sum::<f64>()
})
.enumerate()
.for_each(|(i, value)| buf[i] = value);
input
.chunks_mut(skip)
.zip(buf.iter().copied())
.for_each(|(x, value)| {
x[0] = value;
});
}
pub fn dct2_over_matrix_in_place(input: &mut [f64], width: usize, axis: Axis) {
if input.is_empty() || width == 0 {
return;
}
match axis {
Axis::Row => {
let buf = &mut vec![0.0; width];
for row in input.chunks_mut(width) {
dct2_in_place(row, 1, buf);
}
}
Axis::Column => {
let buf = &mut vec![0.0; input.len() / width];
for n in 0..width {
dct2_in_place(&mut input[n..], width, buf);
}
}
}
}
pub fn median(input: impl IntoIterator<Item = f64>) -> Option<f64> {
let mut sorted = input.into_iter().collect::<Vec<_>>();
if sorted.is_empty() {
return None;
}
sorted.sort_by(|a, b| a.total_cmp(b));
let mid = sorted.len() / 2;
if sorted.len() % 2 == 0 {
Some((sorted[mid - 1] + sorted[mid]) / 2.0)
} else {
Some(sorted[mid])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dct2() {
let mut input = vec![1., 2., 3., 4.];
let buf = &mut vec![0.0; input.len()];
dct2_in_place(&mut input, 1, buf);
assert_eq!(
input,
vec![
20.0,
-6.308644059797899,
-1.7763568394002505e-15,
-0.44834152916796777
]
);
}
#[test]
fn test_dct2_with_empty_input() {
let mut input = vec![];
let buf = &mut vec![0.0; input.len()];
dct2_in_place(&mut input, 1, buf);
assert_eq!(input, vec![]);
}
#[test]
#[should_panic(expected = "skip value must be greater than 0")]
fn test_dct2_with_zero_skip() {
let mut input = vec![1., 2., 3.];
let buf = &mut vec![0.0; input.len()];
dct2_in_place(&mut input, 0, buf);
}
#[test]
#[should_panic(expected = "buffer is too small")]
fn test_dct2_with_small_buffer() {
let mut input = vec![1., 2., 3., 4.];
let buf = &mut [0.0; 1];
dct2_in_place(&mut input, 1, buf);
}
#[test]
fn test_dct2_over_matrix_rows() {
let mut input = vec![
1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.,
];
dct2_over_matrix_in_place(&mut input, 4, Axis::Row);
assert_eq!(
input,
vec![
20.0,
-6.308644059797899,
-1.7763568394002505e-15,
-0.44834152916796777,
52.0,
-6.308644059797897,
-3.552713678800501e-15,
-0.44834152916797,
84.0,
-6.308644059797897,
-7.105427357601002e-15,
-0.44834152916797265,
116.0,
-6.308644059797899,
-3.552713678800501e-15,
-0.4483415291679762
]
);
}
#[test]
fn test_dct2_over_matrix_column() {
let mut input = vec![
1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.,
];
dct2_over_matrix_in_place(&mut input, 4, Axis::Column);
assert_eq!(
input,
vec![
56.,
64.,
72.,
80.,
-25.234576239191597,
-25.234576239191597,
-25.234576239191597,
-25.234576239191597,
-7.105427357601002e-15,
-7.105427357601002e-15,
-7.105427357601002e-15,
-7.105427357601002e-15,
-1.7933661166718693,
-1.7933661166718693,
-1.7933661166718693,
-1.793366116671871
]
);
}
#[test]
fn test_dct2_over_matrix_with_empty_rows() {
let mut input = vec![];
dct2_over_matrix_in_place(&mut input, 0, Axis::Row);
assert_eq!(input, vec![]);
}
#[test]
fn test_dct2_over_matrix_with_empty_columns() {
let mut input = vec![];
dct2_over_matrix_in_place(&mut input, 0, Axis::Column);
assert_eq!(input, vec![]);
}
#[test]
fn test_median_with_even_numbers() {
let input = vec![3., 2., 1., 4.];
let result = median(input);
assert_eq!(result, Some(2.5));
}
#[test]
fn test_median_with_uneven_numbers() {
let input = vec![3., 4., 1., 2., 5.];
let result = median(input);
assert_eq!(result, Some(3.));
}
#[test]
fn test_median_with_single_element() {
let input = vec![42.0];
let result = median(input);
assert_eq!(result, Some(42.0));
}
#[test]
fn test_median_with_empty_vector() {
let input = vec![];
let result = median(input);
assert_eq!(result, None);
}
}