#![deny(warnings)] #![allow(dead_code)] //! [TSM.ID].[11031972] -- Platform X Ecosystem //! xcu-tesseract -- Multi-dimensional indexing engine //! KD-Tree spatial search for multi-parameter queries use std::collections::HashMap; #[derive(Debug)] pub enum TesseractError { DimensionMismatch(String), EmptyTree(String), NotFound(String), } impl std::fmt::Display for TesseractError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::DimensionMismatch(e) => write!(f, "Dim: {e}"), Self::EmptyTree(e) => write!(f, "Empty: {e}"), Self::NotFound(e) => write!(f, "Not found: {e}"), } } } impl std::error::Error for TesseractError {} #[derive(Debug, Clone)] pub struct TesseractPoint { pub id: String, pub coords: Vec, pub metadata: HashMap, } struct KdNode { point: TesseractPoint, left: Option>, right: Option>, split_dim: usize, } pub struct Tesseract { root: Option>, dimensions: usize, size: usize, } impl Tesseract { pub fn new(dimensions: usize) -> Self { Self { root: None, dimensions, size: 0 } } pub fn build(mut points: Vec, dimensions: usize) -> Result { if points.is_empty() { return Ok(Self { root: None, dimensions, size: 0 }); } for p in &points { if p.coords.len() != dimensions { return Err(TesseractError::DimensionMismatch( format!("Expected {dimensions}, got {}", p.coords.len()))); } } let size = points.len(); let root = Self::build_tree(&mut points, 0, dimensions); Ok(Self { root, dimensions, size }) } fn build_tree(points: &mut [TesseractPoint], depth: usize, dims: usize) -> Option> { if points.is_empty() { return None; } let axis = depth % dims; points.sort_by(|a, b| a.coords[axis].partial_cmp(&b.coords[axis]).unwrap_or(std::cmp::Ordering::Equal)); let mid = points.len() / 2; let (left_slice, rest) = points.split_at_mut(mid); let (median, right_slice) = match rest.split_first_mut() { Some(v) => v, None => return None, }; Some(Box::new(KdNode { point: median.clone(), left: Self::build_tree(left_slice, depth + 1, dims), right: Self::build_tree(right_slice, depth + 1, dims), split_dim: axis, })) } /// Nearest neighbor search pub fn nearest(&self, query: &[f64]) -> Result<(TesseractPoint, f64), TesseractError> { if query.len() != self.dimensions { return Err(TesseractError::DimensionMismatch(format!("Query dim {} != {}", query.len(), self.dimensions))); } let root = self.root.as_ref().ok_or_else(|| TesseractError::EmptyTree("No points".into()))?; let mut best = root.point.clone(); let mut best_dist = Self::distance(&root.point.coords, query); Self::search_nearest(root, query, &mut best, &mut best_dist); Ok((best, best_dist)) } fn search_nearest(node: &KdNode, query: &[f64], best: &mut TesseractPoint, best_dist: &mut f64) { let dist = Self::distance(&node.point.coords, query); if dist < *best_dist { *best_dist = dist; *best = node.point.clone(); } let axis = node.split_dim; let diff = query[axis] - node.point.coords[axis]; let (first, second) = if diff < 0.0 { (&node.left, &node.right) } else { (&node.right, &node.left) }; if let Some(child) = first { Self::search_nearest(child, query, best, best_dist); } if diff.abs() < *best_dist { if let Some(child) = second { Self::search_nearest(child, query, best, best_dist); } } } /// Range search: find all points within radius pub fn range_search(&self, center: &[f64], radius: f64) -> Result, TesseractError> { if center.len() != self.dimensions { return Err(TesseractError::DimensionMismatch("".into())); } let mut results = Vec::new(); if let Some(root) = &self.root { Self::search_range(root, center, radius, &mut results); } results.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal)); Ok(results) } fn search_range(node: &KdNode, center: &[f64], radius: f64, results: &mut Vec<(TesseractPoint, f64)>) { let dist = Self::distance(&node.point.coords, center); if dist <= radius { results.push((node.point.clone(), dist)); } let axis = node.split_dim; let diff = center[axis] - node.point.coords[axis]; if let Some(left) = &node.left { if diff - radius <= 0.0 { Self::search_range(left, center, radius, results); } } if let Some(right) = &node.right { if diff + radius >= 0.0 { Self::search_range(right, center, radius, results); } } } fn distance(a: &[f64], b: &[f64]) -> f64 { a.iter().zip(b.iter()).map(|(x, y)| (x - y) * (x - y)).sum::().sqrt() } pub fn size(&self) -> usize { self.size } } #[cfg(test)] mod tests { use super::*; fn pt(id: &str, coords: Vec) -> TesseractPoint { TesseractPoint { id: id.into(), coords, metadata: HashMap::new() } } #[test] fn test_nearest() { let points = vec![pt("a", vec![1.0, 2.0]), pt("b", vec![5.0, 6.0]), pt("c", vec![3.0, 3.0])]; let t = Tesseract::build(points, 2).unwrap(); let (nearest, dist) = t.nearest(&[2.5, 2.5]).unwrap(); assert_eq!(nearest.id, "c"); assert!(dist < 1.0); } #[test] fn test_range() { let points = vec![pt("a", vec![0.0, 0.0]), pt("b", vec![1.0, 1.0]), pt("c", vec![10.0, 10.0])]; let t = Tesseract::build(points, 2).unwrap(); let results = t.range_search(&[0.0, 0.0], 2.0).unwrap(); assert_eq!(results.len(), 2); } }