use crate::engine::ps_hybrid::HybridConfig;
const B_K_20: [u8; 71] = [
1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, ];
const B_K_34: [u8; 91] = [
0, 1, 2, 3, 4, 5, 6, 6, 7, 2, 1, 0, 10, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 9, 14, 11, 12, 13, 14, 15, 16, 13, 16, 17, 18, 19, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
33, ];
#[must_use]
pub fn parameter_map(config: HybridConfig) -> &'static [u8] {
match config {
HybridConfig::Bands1020 => &B_K_20,
HybridConfig::Bands34 => &B_K_34,
}
}
#[must_use]
pub fn conjugate_flags(config: HybridConfig) -> &'static [usize] {
match config {
HybridConfig::Bands1020 => &[0, 1],
HybridConfig::Bands34 => &[9, 10, 11],
}
}
#[must_use]
pub fn map_10_to_20(v: &[i32]) -> Vec<i32> {
(0..20).map(|k| v[k / 2]).collect()
}
#[derive(Debug, Clone, Copy)]
pub enum MapSrc {
Single(usize),
Avg(usize, usize),
Avg4(usize, usize, usize, usize),
W21(usize, usize),
W12(usize, usize),
}
pub const MAP_20_TO_34: [MapSrc; 34] = [
MapSrc::Single(0),
MapSrc::Avg(0, 1),
MapSrc::Single(1),
MapSrc::Single(2),
MapSrc::Avg(2, 3),
MapSrc::Single(3),
MapSrc::Single(4),
MapSrc::Single(4),
MapSrc::Single(5),
MapSrc::Single(5),
MapSrc::Single(6),
MapSrc::Single(7),
MapSrc::Single(8),
MapSrc::Single(8),
MapSrc::Single(9),
MapSrc::Single(9),
MapSrc::Single(10),
MapSrc::Single(11),
MapSrc::Single(12),
MapSrc::Single(13),
MapSrc::Single(14),
MapSrc::Single(14),
MapSrc::Single(15),
MapSrc::Single(15),
MapSrc::Single(16),
MapSrc::Single(16),
MapSrc::Single(17),
MapSrc::Single(17),
MapSrc::Single(18),
MapSrc::Single(18),
MapSrc::Single(18),
MapSrc::Single(18),
MapSrc::Single(19),
MapSrc::Single(19),
];
pub const MAP_34_TO_20: [MapSrc; 20] = [
MapSrc::W21(0, 1),
MapSrc::W12(1, 2),
MapSrc::W21(3, 4),
MapSrc::W12(4, 5),
MapSrc::Avg(6, 7),
MapSrc::Avg(8, 9),
MapSrc::Single(10),
MapSrc::Single(11),
MapSrc::Avg(12, 13),
MapSrc::Avg(14, 15),
MapSrc::Single(16),
MapSrc::Single(17),
MapSrc::Single(18),
MapSrc::Single(19),
MapSrc::Avg(20, 21),
MapSrc::Avg(22, 23),
MapSrc::Avg(24, 25),
MapSrc::Avg(26, 27),
MapSrc::Avg4(28, 29, 30, 31),
MapSrc::Avg(32, 33),
];
impl MapSrc {
#[must_use]
pub fn apply_i32(&self, v: &[i32]) -> i32 {
match *self {
MapSrc::Single(i) => v[i],
MapSrc::Avg(i, j) => (v[i] + v[j]) / 2,
MapSrc::Avg4(i, j, k, l) => (v[i] + v[j] + v[k] + v[l]) / 4,
MapSrc::W21(i, j) => (2 * v[i] + v[j]) / 3,
MapSrc::W12(i, j) => (v[i] + 2 * v[j]) / 3,
}
}
#[must_use]
pub fn apply_f64(&self, v: &[f64]) -> f64 {
match *self {
MapSrc::Single(i) => v[i],
MapSrc::Avg(i, j) => (v[i] + v[j]) / 2.0,
MapSrc::Avg4(i, j, k, l) => (v[i] + v[j] + v[k] + v[l]) / 4.0,
MapSrc::W21(i, j) => (2.0 * v[i] + v[j]) / 3.0,
MapSrc::W12(i, j) => (v[i] + 2.0 * v[j]) / 3.0,
}
}
}
#[must_use]
pub fn map_indices(v: &[i32], target: usize) -> Vec<i32> {
match (v.len(), target) {
(n, t) if n == t => v.to_vec(),
(10, 20) => map_10_to_20(v),
(20, 34) => MAP_20_TO_34.iter().map(|m| m.apply_i32(v)).collect(),
(10, 34) => {
let v20 = map_10_to_20(v);
MAP_20_TO_34.iter().map(|m| m.apply_i32(&v20)).collect()
}
(34, 20) => MAP_34_TO_20.iter().map(|m| m.apply_i32(v)).collect(),
_ => v.to_vec(),
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
#[test]
fn b_k_tables_are_consistent() {
assert_eq!(B_K_20.len(), 71);
assert_eq!(B_K_34.len(), 91);
assert!(B_K_20.iter().all(|&b| b < 20));
assert!(B_K_34.iter().all(|&b| b < 34));
for b in 0..20u8 {
assert!(B_K_20.contains(&b), "20-band {b} unused");
}
for b in 0..34u8 {
assert!(B_K_34.contains(&b), "34-band {b} unused");
}
assert_eq!(&B_K_20[10..16], &[8, 9, 10, 11, 12, 13]);
assert_eq!(&B_K_34[12..20], &[10, 10, 4, 5, 6, 7, 8, 9]);
}
#[test]
fn index_mapping_round_trips_shape() {
let v10: Vec<i32> = (0..10).collect();
let v20 = map_indices(&v10, 20);
assert_eq!(
v20,
vec![0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]
);
let v34 = map_indices(&v20, 34);
assert_eq!(v34.len(), 34);
assert_eq!(v34[0], 0);
assert_eq!(v34[1], (v20[0] + v20[1]) / 2);
assert_eq!(v34[2], v20[1]);
let back = map_indices(&v34, 20);
assert_eq!(back.len(), 20);
let c34 = map_indices(&[5i32; 20], 34);
assert_eq!(c34, vec![5i32; 34]);
let c20 = map_indices(&[5i32; 34], 20);
assert_eq!(c20, vec![5i32; 20]);
}
#[test]
fn ansi_c_integer_average_truncates_toward_zero() {
let v = vec![-3i32, 2];
assert_eq!(MapSrc::Avg(0, 1).apply_i32(&v), 0);
assert_eq!(MapSrc::W21(0, 1).apply_i32(&v), -1); }
}