use serde::{Deserialize, Serialize};
pub const RESIDUE_CLASSES: usize = 96;
pub const PRIME_RESIDUE_CLASSES: [u16; RESIDUE_CLASSES] = [
1, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 49, 53, 59,
61, 67, 71, 73, 77, 79, 83, 89, 91, 97, 101, 103, 107, 109, 113, 119,
121, 127, 131, 133, 137, 139, 143, 149, 151, 157, 161, 163, 167, 169, 173, 179,
181, 187, 191, 193, 197, 199, 203, 209, 211, 217, 221, 223, 227, 229, 233, 239,
241, 247, 251, 253, 257, 259, 263, 269, 271, 277, 281, 283, 287, 289, 293, 299,
301, 307, 311, 313, 317, 319, 323, 329, 331, 337, 341, 343, 347, 349, 353, 359,
];
pub const FACTOR_COVERED: [u16; 48] = [
1, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 49, 53, 59,
61, 67, 71, 73, 77, 79, 83, 89, 271, 277, 281, 283, 287, 289, 293, 299,
301, 307, 311, 313, 317, 319, 323, 329, 331, 337, 341, 343, 347, 349, 353, 359,
];
pub const SEQUENCE_COVERED: [u16; 46] = [
91, 97, 101, 103, 107, 109, 113, 119, 121, 127, 131, 133, 137, 139, 143, 149,
151, 157, 161, 163, 167, 169, 173, 179, 181, 187, 191, 193, 197, 199, 203, 209,
211, 217, 221, 223, 227, 229, 233, 239, 241, 247, 251, 253, 257, 259,
];
pub const SCALE_DEPENDENT: [u16; 2] = [261, 269];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ExtendedPrime {
SignPrime,
MagnitudePrime(u32),
}
impl ExtendedPrime {
pub fn is_prime(n: i32) -> bool {
if n == -1 {
return true; }
if n < 2 {
return false;
}
if n == 2 || n == 3 {
return true;
}
if n % 2 == 0 || n % 3 == 0 {
return false;
}
let mut i = 5;
while i * i <= n {
if n % i == 0 || n % (i + 2) == 0 {
return false;
}
i += 6;
}
true
}
pub fn value(&self) -> i32 {
match self {
ExtendedPrime::SignPrime => -1,
ExtendedPrime::MagnitudePrime(p) => *p as i32,
}
}
}
#[derive(Debug, Clone)]
pub struct QuantizationTable {
pub base_q: u16,
pub weights: [f32; RESIDUE_CLASSES],
}
impl QuantizationTable {
pub fn new(base_q: u16) -> Self {
let mut weights = [1.0f32; RESIDUE_CLASSES];
for &residue in &FACTOR_COVERED {
if let Some(idx) = PRIME_RESIDUE_CLASSES.iter().position(|&r| r == residue) {
weights[idx] = 0.9; }
}
for &residue in &SEQUENCE_COVERED {
if let Some(idx) = PRIME_RESIDUE_CLASSES.iter().position(|&r| r == residue) {
weights[idx] = 1.0;
}
}
for &residue in &SCALE_DEPENDENT {
if let Some(idx) = PRIME_RESIDUE_CLASSES.iter().position(|&r| r == residue) {
weights[idx] = 1.1; }
}
QuantizationTable { base_q, weights }
}
pub fn get_step(&self, x: usize, y: usize) -> u16 {
let residue = ((x + y * 360) % 360) as u16;
let idx = self.find_closest_residue(residue);
let weighted_q = self.base_q as f32 * self.weights[idx];
weighted_q.round() as u16
}
fn find_closest_residue(&self, residue: u16) -> usize {
let mut min_dist = u16::MAX;
let mut min_idx = 0;
for (idx, &prime_residue) in PRIME_RESIDUE_CLASSES.iter().enumerate() {
let dist = if residue > prime_residue {
residue - prime_residue
} else {
prime_residue - residue
};
let wraparound_dist = 360 - dist;
let effective_dist = dist.min(wraparound_dist);
if effective_dist < min_dist {
min_dist = effective_dist;
min_idx = idx;
}
}
min_idx
}
}
pub struct PpfHash {
seed: u32,
}
impl PpfHash {
pub fn new(seed: u32) -> Self {
PpfHash { seed }
}
pub fn hash(&self, x: u32, y: u32) -> f32 {
let combined = self.combine_coords(x, y);
let hash = combined.wrapping_mul(2654435761u32);
let residue = (hash % 360) as usize;
let idx = self.find_prime_residue(residue);
PRIME_RESIDUE_CLASSES[idx] as f32 / 360.0
}
fn combine_coords(&self, x: u32, y: u32) -> u32 {
let x_prime = self.prime_factorize_approx(x);
let y_prime = self.prime_factorize_approx(y);
x_prime ^ y_prime ^ self.seed
}
fn prime_factorize_approx(&self, n: u32) -> u32 {
if n == 0 {
return 0;
}
let mut residue = n;
let mut factor_hash = 1u32;
while residue % 2 == 0 {
factor_hash = factor_hash.wrapping_mul(2);
residue /= 2;
}
while residue % 3 == 0 {
factor_hash = factor_hash.wrapping_mul(3);
residue /= 3;
}
while residue % 5 == 0 {
factor_hash = factor_hash.wrapping_mul(5);
residue /= 5;
}
factor_hash.wrapping_add(residue)
}
fn find_prime_residue(&self, residue: usize) -> usize {
let residue = residue as u16;
let mut min_dist = u16::MAX;
let mut min_idx = 0;
for (idx, &prime_residue) in PRIME_RESIDUE_CLASSES.iter().enumerate() {
let dist = if residue > prime_residue {
residue - prime_residue
} else {
prime_residue - residue
};
let wraparound_dist = 360 - dist;
let effective_dist = dist.min(wraparound_dist);
if effective_dist < min_dist {
min_dist = effective_dist;
min_idx = idx;
}
}
min_idx
}
}
pub struct RecursiveSequence {
scale: u32,
index: u32,
value: u32,
}
impl RecursiveSequence {
pub fn new(scale: u32) -> Self {
let value = (scale - 1) * 360 + 181;
RecursiveSequence {
scale,
index: 1,
value,
}
}
pub fn value(&self) -> u32 {
self.value
}
pub fn next(&mut self) -> u32 {
self.index += 1;
self.value += self.index;
self.value
}
pub fn in_range(&self) -> bool {
self.value <= self.scale * 360 + 180
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_residue_classes() {
assert_eq!(PRIME_RESIDUE_CLASSES.len(), RESIDUE_CLASSES);
for &residue in &PRIME_RESIDUE_CLASSES {
assert_eq!(gcd(residue as u32, 360), 1);
}
}
#[test]
fn test_category_distribution() {
assert_eq!(
FACTOR_COVERED.len() + SEQUENCE_COVERED.len() + SCALE_DEPENDENT.len(),
RESIDUE_CLASSES
);
}
#[test]
fn test_extended_prime() {
assert!(ExtendedPrime::is_prime(-1)); assert!(ExtendedPrime::is_prime(2));
assert!(ExtendedPrime::is_prime(3));
assert!(ExtendedPrime::is_prime(5));
assert!(ExtendedPrime::is_prime(7));
assert!(!ExtendedPrime::is_prime(0));
assert!(!ExtendedPrime::is_prime(1));
assert!(!ExtendedPrime::is_prime(4));
assert!(!ExtendedPrime::is_prime(6));
assert!(!ExtendedPrime::is_prime(-2));
assert!(!ExtendedPrime::is_prime(-3));
}
#[test]
fn test_quantization_table() {
let table = QuantizationTable::new(10);
assert_eq!(table.base_q, 10);
assert_eq!(table.weights.len(), RESIDUE_CLASSES);
let step1 = table.get_step(0, 0);
let step2 = table.get_step(100, 100);
assert!(step1 >= 8 && step1 <= 12);
assert!(step2 >= 8 && step2 <= 12);
}
#[test]
fn test_ppf_hash_determinism() {
let hash = PpfHash::new(42);
let h1 = hash.hash(10, 20);
let h2 = hash.hash(10, 20);
assert_eq!(h1, h2);
let h3 = hash.hash(10, 21);
assert_ne!(h1, h3);
assert!(h1 >= 0.0 && h1 < 1.0);
}
#[test]
fn test_recursive_sequence() {
let mut seq = RecursiveSequence::new(1);
assert_eq!(seq.value(), 181);
assert_eq!(seq.next(), 183); assert_eq!(seq.next(), 186); assert_eq!(seq.next(), 190);
let mut seq2 = RecursiveSequence::new(2);
assert_eq!(seq2.value(), 541); }
#[test]
fn test_sequence_coverage() {
let mut seq = RecursiveSequence::new(1);
let mut count = 0;
while seq.in_range() && count < 1000 {
seq.next();
count += 1;
}
assert!(count > 10);
assert!(count < 1000); }
fn gcd(mut a: u32, mut b: u32) -> u32 {
while b != 0 {
let temp = b;
b = a % b;
a = temp;
}
a
}
}