pub const PATTERN_SIZE: usize = 4;
pub const NUM_EDGES: usize = 6;
pub const NUM_EDGE_RATIOS: usize = 5;
const MAGIC_RAND: u64 = 2654435761;
#[inline]
pub fn angle_from_distance(dist: f32) -> f32 {
2.0 * (0.5 * dist).clamp(-1.0, 1.0).asin()
}
#[inline]
pub fn distance_from_angle(angle: f32) -> f32 {
2.0 * (angle / 2.0).sin()
}
#[inline]
fn vec3_dist(a: &[f32; 3], b: &[f32; 3]) -> f32 {
let dx = a[0] - b[0];
let dy = a[1] - b[1];
let dz = a[2] - b[2];
(dx * dx + dy * dy + dz * dz).sqrt()
}
pub fn compute_sorted_edge_angles(vectors: &[[f32; 3]; PATTERN_SIZE]) -> [f32; NUM_EDGES] {
let mut edges = [0.0f32; NUM_EDGES];
let mut idx = 0;
for i in 0..PATTERN_SIZE {
for j in (i + 1)..PATTERN_SIZE {
edges[idx] = angle_from_distance(vec3_dist(&vectors[i], &vectors[j]));
idx += 1;
}
}
edges.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
edges
}
pub fn compute_edge_ratios(sorted_edges: &[f32; NUM_EDGES]) -> [f32; NUM_EDGE_RATIOS] {
let largest = sorted_edges[NUM_EDGES - 1];
let mut ratios = [0.0f32; NUM_EDGE_RATIOS];
if largest > 0.0 {
for i in 0..NUM_EDGE_RATIOS {
ratios[i] = sorted_edges[i] / largest;
}
}
ratios
}
pub fn compute_pattern_key(
edge_ratios: &[f32; NUM_EDGE_RATIOS],
bins: u32,
) -> [u32; NUM_EDGE_RATIOS] {
let mut key = [0u32; NUM_EDGE_RATIOS];
for i in 0..NUM_EDGE_RATIOS {
key[i] = (edge_ratios[i] * bins as f32) as u32;
}
key
}
pub fn compute_pattern_key_hash(key: &[u32; NUM_EDGE_RATIOS], bins: u32) -> u64 {
let bins64 = bins as u64;
let mut hash: u64 = 0;
let mut factor: u64 = 1;
for &k in key.iter() {
hash = hash.wrapping_add((k as u64).wrapping_mul(factor));
factor = factor.wrapping_mul(bins64);
}
hash
}
pub fn hash_to_index(hash: u64, table_size: u64) -> u64 {
hash.wrapping_mul(MAGIC_RAND) % table_size
}
pub fn insert_pattern(
entry: super::PatternEntry,
hash_index: u64,
table: &mut [super::PatternEntry],
) -> usize {
let max_ind = table.len() as u64;
for c in 0u64.. {
let i = ((hash_index.wrapping_add(c.wrapping_mul(c))) % max_ind) as usize;
if table[i].is_empty() {
table[i] = entry;
return i;
}
}
unreachable!("hash table is full")
}
pub fn sort_pattern_by_centroid_distance(
pattern: &mut [usize; PATTERN_SIZE],
vectors: &[[f32; 3]],
) {
let mut cx = 0.0f32;
let mut cy = 0.0f32;
let mut cz = 0.0f32;
for &idx in pattern.iter() {
let v = &vectors[idx];
cx += v[0];
cy += v[1];
cz += v[2];
}
cx /= PATTERN_SIZE as f32;
cy /= PATTERN_SIZE as f32;
cz /= PATTERN_SIZE as f32;
pattern.sort_by(|&a, &b| {
let va = &vectors[a];
let vb = &vectors[b];
let da = (va[0] - cx).powi(2) + (va[1] - cy).powi(2) + (va[2] - cz).powi(2);
let db = (vb[0] - cx).powi(2) + (vb[1] - cy).powi(2) + (vb[2] - cz).powi(2);
da.partial_cmp(&db).unwrap_or(std::cmp::Ordering::Equal)
});
}
pub fn sort_u32_pattern_by_centroid_distance(
pattern: &mut [u32; PATTERN_SIZE],
star_vectors: &[[f32; 3]],
) {
let mut cx = 0.0f32;
let mut cy = 0.0f32;
let mut cz = 0.0f32;
for &idx in pattern.iter() {
let v = &star_vectors[idx as usize];
cx += v[0];
cy += v[1];
cz += v[2];
}
cx /= PATTERN_SIZE as f32;
cy /= PATTERN_SIZE as f32;
cz /= PATTERN_SIZE as f32;
pattern.sort_by(|&a, &b| {
let va = &star_vectors[a as usize];
let vb = &star_vectors[b as usize];
let da = (va[0] - cx).powi(2) + (va[1] - cy).powi(2) + (va[2] - cz).powi(2);
let db = (vb[0] - cx).powi(2) + (vb[1] - cy).powi(2) + (vb[2] - cz).powi(2);
da.partial_cmp(&db).unwrap_or(std::cmp::Ordering::Equal)
});
}
pub fn is_prime(n: u64) -> bool {
if n < 2 {
return false;
}
if n == 2 || n == 3 {
return true;
}
if n % 2 == 0 || n % 3 == 0 {
return false;
}
let mut i = 5u64;
while i * i <= n {
if n % i == 0 || n % (i + 2) == 0 {
return false;
}
i += 6;
}
true
}
pub fn next_prime(n: u64) -> u64 {
if n <= 2 {
return 2;
}
let mut candidate = n | 1; while !is_prime(candidate) {
candidate += 2;
}
candidate
}