use std::collections::HashMap;
use std::fmt;
use std::ops::Range;
use g_math::fixed_point::FixedPoint;
use super::config::HTTStorageConfig;
use super::constants::{OUTLIER_KNN, OUTLIER_MIN_POPULATION};
use super::metric_tree::{EuclideanMetric, MetricVpTree};
use super::storage::HTTStorage;
use super::tensor_network::HyperbolicTensorNetwork;
use super::tree_tensor::IntegrationError;
#[derive(Debug)]
pub enum StoreError {
NotFound(String),
AlreadyExists(String),
InvalidOperation(String),
Internal(String),
}
impl fmt::Display for StoreError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StoreError::NotFound(msg) => write!(f, "not found: {}", msg),
StoreError::AlreadyExists(msg) => write!(f, "already exists: {}", msg),
StoreError::InvalidOperation(msg) => write!(f, "invalid operation: {}", msg),
StoreError::Internal(msg) => write!(f, "internal error: {}", msg),
}
}
}
impl std::error::Error for StoreError {}
#[derive(Debug, Clone, PartialEq)]
pub struct SemanticOutlier {
pub key: String,
pub avg_knn_distance: FixedPoint,
pub z_score: FixedPoint,
pub nearest_peer: String,
pub nearest_distance: FixedPoint,
}
impl From<IntegrationError> for StoreError {
fn from(e: IntegrationError) -> Self {
match e {
IntegrationError::NotFound(msg) => StoreError::NotFound(msg),
IntegrationError::AlreadyExists(msg) => StoreError::AlreadyExists(msg),
IntegrationError::ValidationFailed(msg) | IntegrationError::ConfigurationError(msg) => {
StoreError::InvalidOperation(msg)
}
IntegrationError::OperationFailed(msg)
| IntegrationError::DeserializationError(msg)
| IntegrationError::LockError(msg) => StoreError::Internal(msg),
}
}
}
pub struct StoreConfig {
capacity: usize,
tau: FixedPoint,
}
impl StoreConfig {
pub fn new() -> Self {
Self { capacity: 10_000, tau: FixedPoint::from_int(0) }
}
pub fn capacity(mut self, n: usize) -> Self {
self.capacity = n;
self
}
pub fn tau(mut self, t: FixedPoint) -> Self {
self.tau = t;
self
}
fn to_htt_config(&self) -> HTTStorageConfig {
HTTStorageConfig {
dimension: 4,
max_memory_nodes: self.capacity,
cache_size: std::cmp::max(self.capacity / 10, 10),
storage_path: None,
flush_interval: 60,
optimize_on_shutdown: true,
grid_resolution: 0,
tau: self.tau,
}
}
}
impl Default for StoreConfig {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub enum QueryResult {
Entry {
key: String,
data: Vec<u8>,
meta: HashMap<String, String>,
},
Count(usize),
Keys(Vec<String>),
}
pub trait QueryAdapter: Send + Sync {
fn execute(&self, store: &Store, query: &str) -> Result<Vec<QueryResult>, StoreError>;
}
pub struct Store {
inner: HTTStorage,
}
impl Store {
pub fn new() -> Self {
Self::with_config(StoreConfig::new())
}
pub fn with_config(config: StoreConfig) -> Self {
Self {
inner: HTTStorage::new(config.to_htt_config()),
}
}
pub fn put(&self, key: &str, data: &[u8]) -> Result<(), StoreError> {
self.inner.store(key, data, None)?;
Ok(())
}
pub fn put_data_only(&self, key: &str, data: &[u8]) -> Result<(), StoreError> {
self.inner.store_data_only(key, data, None)?;
Ok(())
}
pub fn put_positioned(&self, key: &str, data: &[u8], child_index: u32) -> Result<(), StoreError> {
self.inner.store_positioned(key, data, None, child_index)?;
Ok(())
}
pub fn get(&self, key: &str) -> Result<Vec<u8>, StoreError> {
Ok(self.inner.retrieve(key)?)
}
pub fn remove(&self, key: &str) -> Result<(), StoreError> {
self.inner.delete(key)?;
Ok(())
}
pub fn exists(&self, key: &str) -> bool {
self.inner.exists(key)
}
pub fn children(&self, path: &str) -> Result<Vec<String>, StoreError> {
let htt = self.inner.shared_htt();
let nodes = htt.list_children(path)?;
Ok(nodes.into_iter().map(|n| n.metadata().key.clone()).collect())
}
pub fn list(&self, prefix: &str) -> Result<Vec<String>, StoreError> {
Ok(self.inner.list(prefix)?)
}
pub fn set_meta(&self, key: &str, name: &str, value: &str) -> Result<(), StoreError> {
self.inner.set_metadata(key, name, value)?;
Ok(())
}
pub fn get_meta(&self, key: &str) -> Result<HashMap<String, String>, StoreError> {
Ok(self.inner.get_metadata(key)?)
}
pub fn set_semantic(&self, key: &str, coords: Vec<u8>) -> Result<(), StoreError> {
if coords.len() % 16 != 0 {
return Err(StoreError::InvalidOperation(format!(
"semantic coordinates must be a multiple of 16 bytes (one Q64.64 value per dimension); got {} bytes",
coords.len()
)));
}
self.inner.set_semantic(key, coords)?;
Ok(())
}
pub fn get_semantic(&self, key: &str) -> Result<Vec<u8>, StoreError> {
Ok(self.inner.get_semantic(key)?)
}
pub fn nearest(&self, coords: &[FixedPoint]) -> Result<(String, FixedPoint), StoreError> {
Ok(self.inner.nearest_neighbor_point(coords)?)
}
pub fn nearest_k(&self, coords: &[FixedPoint], k: usize) -> Result<Vec<(String, FixedPoint)>, StoreError> {
Ok(self.inner.nearest_neighbor_point_k(coords, k)?)
}
pub fn neighbors(&self, path: &str, k: usize) -> Result<Vec<String>, StoreError> {
Ok(self.inner.find_nearest(path, k)?)
}
pub fn nearest_semantic(
&self,
query_coords: &[u8],
k: usize,
dim_range: Range<usize>,
) -> Result<Vec<(String, FixedPoint)>, StoreError> {
if query_coords.len() % 16 != 0 {
return Err(StoreError::InvalidOperation(format!(
"semantic query coordinates must be a multiple of 16 bytes; got {} bytes",
query_coords.len()
)));
}
let results = self.inner.nearest_semantic(query_coords, k, &dim_range)?;
Ok(results)
}
pub fn neighbors_semantic(
&self,
path: &str,
k: usize,
dim_range: Range<usize>,
) -> Result<Vec<(String, FixedPoint)>, StoreError> {
let results = self.inner.neighbors_semantic(path, k, &dim_range)?;
Ok(results)
}
pub fn find_similar(
&self,
key: &str,
k: usize,
dim_range: Range<usize>,
) -> Result<Vec<(String, FixedPoint)>, StoreError> {
self.neighbors_semantic(key, k, dim_range)
}
pub fn find_outliers(
&self,
prefix: &str,
z_threshold: FixedPoint,
dim_range: Range<usize>,
) -> Result<Vec<SemanticOutlier>, StoreError> {
if z_threshold <= FixedPoint::from_int(0) {
return Err(StoreError::InvalidOperation(format!(
"z_threshold must be a positive number; got {}",
z_threshold.to_f64()
)));
}
let mut keys = self.list(prefix)?;
keys.sort();
let entries: Vec<(String, Vec<FixedPoint>)> = keys
.into_iter()
.filter_map(|key| {
let coords = self.inner.get_semantic(&key).ok()?;
if coords.is_empty() {
return None;
}
Some((
key,
HyperbolicTensorNetwork::decode_semantic_slice(&coords, &dim_range),
))
})
.collect();
if entries.len() < OUTLIER_MIN_POPULATION {
return Ok(Vec::new());
}
let tree = MetricVpTree::build(entries.clone(), &EuclideanMetric);
let k = OUTLIER_KNN.min(entries.len() - 1);
let zero = FixedPoint::from_int(0);
let mut scored: Vec<(String, FixedPoint, String, FixedPoint)> = entries
.iter()
.map(|(key, point)| {
let peers: Vec<(String, FixedPoint)> = tree
.knn(point, k + 1, &EuclideanMetric)
.into_iter()
.filter(|(id, _)| id != key)
.take(k)
.collect();
let sum = peers.iter().fold(zero, |acc, (_, d)| acc + *d);
let avg = sum / FixedPoint::from_int(k as i32);
let (nearest_peer, nearest_distance) = peers[0].clone();
(key.clone(), avg, nearest_peer, nearest_distance)
})
.collect();
let n = FixedPoint::from_int(scored.len() as i32);
let mean = scored.iter().fold(zero, |acc, (_, avg, _, _)| acc + *avg) / n;
let variance = scored
.iter()
.fold(zero, |acc, (_, avg, _, _)| {
let d = *avg - mean;
acc + d * d
})
/ n;
let stdev = variance.sqrt();
if stdev <= FixedPoint::from_raw(1) {
return Ok(Vec::new()); }
scored.sort_by(|a, b| {
b.1.partial_cmp(&a.1)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| a.0.cmp(&b.0))
});
Ok(scored
.into_iter()
.filter_map(|(key, avg, nearest_peer, nearest_distance)| {
let z_score = (avg - mean) / stdev;
(z_score > z_threshold).then_some(SemanticOutlier {
key,
avg_knn_distance: avg,
z_score,
nearest_peer,
nearest_distance,
})
})
.collect())
}
pub fn embed_existing(&self, key: &str) -> Result<bool, StoreError> {
Ok(self.inner.embed_existing(key)?)
}
pub fn embed_all(&self, prefix: &str) -> Result<usize, StoreError> {
let mut upgraded = 0;
if self.exists(prefix) && self.embed_existing(prefix)? {
upgraded += 1;
}
let mut keys = self.list(prefix)?;
keys.sort();
for key in keys {
if self.embed_existing(&key)? {
upgraded += 1;
}
}
Ok(upgraded)
}
pub fn position(&self, key: &str) -> Result<Vec<FixedPoint>, StoreError> {
let point = self.inner.position(key)?;
Ok(point.coords().iter().copied().collect())
}
pub(crate) fn position_fixed(
&self,
key: &str,
) -> Result<crate::hyperbolic_geometry::HyperbolicPoint, StoreError> {
Ok(self.inner.position(key)?)
}
pub fn semantic_epoch(&self) -> u64 {
self.inner.semantic_epoch()
}
pub fn semantic_distance(
coords_a: &[u8],
coords_b: &[u8],
dim_range: Range<usize>,
) -> FixedPoint {
HyperbolicTensorNetwork::semantic_distance(coords_a, coords_b, &dim_range)
}
pub fn find_within(&self, path: &str, radius: FixedPoint) -> Result<Vec<String>, StoreError> {
Ok(self.inner.find_in_radius(path, radius)?)
}
pub fn query(&self, adapter: &dyn QueryAdapter, query: &str) -> Result<Vec<QueryResult>, StoreError> {
adapter.execute(self, query)
}
pub fn len(&self) -> usize {
self.inner.node_count().saturating_sub(1) }
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn inner(&self) -> &HTTStorage {
&self.inner
}
#[deprecated(note = "All HTTStorage methods now take &self; use inner() instead")]
pub fn inner_mut(&mut self) -> &mut HTTStorage {
&mut self.inner
}
}
impl Default for Store {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
fn fp(vals: &[f64]) -> Vec<g_math::fixed_point::FixedPoint> {
vals.iter().map(|&v| g_math::fixed_point::FixedPoint::from_f64(v)).collect()
}
use super::*;
#[test]
fn test_new_store_is_empty() {
let store = Store::new();
assert!(store.is_empty());
assert_eq!(store.len(), 0);
}
#[test]
fn test_put_get_roundtrip() {
let store = Store::new();
store.put("/hello", b"world").unwrap();
assert_eq!(store.get("/hello").unwrap(), b"world");
}
#[test]
fn test_upsert() {
let store = Store::new();
store.put("/key", b"v1").unwrap();
store.put("/key", b"v2").unwrap();
assert_eq!(store.get("/key").unwrap(), b"v2");
}
#[test]
fn test_remove() {
let store = Store::new();
store.put("/tmp", b"data").unwrap();
assert!(store.exists("/tmp"));
store.remove("/tmp").unwrap();
assert!(!store.exists("/tmp"));
}
#[test]
fn test_exists() {
let store = Store::new();
assert!(!store.exists("/nope"));
store.put("/yes", b"").unwrap();
assert!(store.exists("/yes"));
}
#[test]
fn test_children() {
let store = Store::new();
store.put("/a/b", b"1").unwrap();
store.put("/a/c", b"2").unwrap();
store.put("/a/c/d", b"3").unwrap();
let kids = store.children("/a").unwrap();
assert!(kids.contains(&"/a/b".to_string()));
assert!(kids.contains(&"/a/c".to_string()));
assert!(!kids.contains(&"/a/c/d".to_string()));
}
#[test]
fn test_list() {
let store = Store::new();
store.put("/x/y", b"1").unwrap();
store.put("/x/z", b"2").unwrap();
let all = store.list("/x").unwrap();
assert!(all.contains(&"/x/y".to_string()));
assert!(all.contains(&"/x/z".to_string()));
}
#[test]
fn test_metadata() {
let store = Store::new();
store.put("/doc", b"content").unwrap();
store.set_meta("/doc", "author", "alice").unwrap();
let meta = store.get_meta("/doc").unwrap();
assert_eq!(meta.get("author"), Some(&"alice".to_string()));
}
#[test]
fn test_nearest() {
let store = Store::new();
store.put("/a", b"a").unwrap();
store.put("/b", b"b").unwrap();
let (path, dist) = store.nearest(&fp(&[0.0, 0.0, 0.0, 0.0])).unwrap();
assert_eq!(path, "/");
assert!(dist.to_f64() < 0.1);
}
#[test]
fn test_neighbors() {
let store = Store::new();
store.put("/a", b"a").unwrap();
store.put("/b", b"b").unwrap();
store.put("/c", b"c").unwrap();
let nbrs = store.neighbors("/a", 2).unwrap();
assert!(!nbrs.is_empty());
assert!(nbrs.len() <= 2);
assert!(!nbrs.contains(&"/a".to_string()));
}
#[test]
fn test_find_within() {
let store = Store::new();
store.put("/x", b"x").unwrap();
store.put("/y", b"y").unwrap();
let results = store.find_within("/x", g_math::fixed_point::FixedPoint::from_f64(10.0)).unwrap();
assert!(!results.is_empty());
}
#[test]
fn test_error_not_found() {
let store = Store::new();
let err = store.get("/missing").unwrap_err();
assert!(matches!(err, StoreError::NotFound(_)));
}
#[test]
fn test_len_tracking() {
let store = Store::new();
assert_eq!(store.len(), 0);
store.put("/one", b"1").unwrap();
assert_eq!(store.len(), 1);
store.put("/two", b"2").unwrap();
assert_eq!(store.len(), 2);
store.remove("/one").unwrap();
assert_eq!(store.len(), 1);
}
#[test]
fn test_inner_escape_hatch() {
let store = Store::new();
store.put("/test", b"data").unwrap();
assert!(store.inner().exists("/test"));
store.inner().store("/via_inner", b"inner", None).unwrap();
assert!(store.exists("/via_inner"));
}
#[test]
fn test_with_config() {
let config = StoreConfig::new().capacity(500);
let store = Store::with_config(config);
assert!(store.is_empty());
}
#[test]
fn test_tau_config() {
let store = Store::with_config(StoreConfig::new().capacity(1000).tau(FixedPoint::from_f64(0.8)));
store.put("/a", b"a").unwrap();
store.put("/b", b"b").unwrap();
store.put("/a/child", b"c").unwrap();
assert_eq!(store.len(), 3);
let (path, dist) = store.nearest(&fp(&[0.0, 0.0, 0.0, 0.0])).unwrap();
assert_eq!(path, "/");
assert!(dist.to_f64() < 0.1);
}
#[test]
fn test_tau_deep_tree() {
let store = Store::with_config(StoreConfig::new().tau(FixedPoint::from_f64(0.8)));
let mut path = String::new();
for i in 0..40 {
path = format!("{}/n{}", path, i);
store.put(&path, b"x").unwrap();
}
assert!(store.exists(&path));
let (nn, _) = store.nearest(&fp(&[0.0, 0.0, 0.0, 0.0])).unwrap();
assert!(store.exists(&nn));
}
#[test]
fn test_query_adapter() {
struct ChildrenAdapter;
impl QueryAdapter for ChildrenAdapter {
fn execute(&self, store: &Store, query: &str) -> Result<Vec<QueryResult>, StoreError> {
let children = store.children(query)?;
Ok(vec![QueryResult::Keys(children)])
}
}
let store = Store::new();
store.put("/a/b", b"1").unwrap();
store.put("/a/c", b"2").unwrap();
let results = store.query(&ChildrenAdapter, "/a").unwrap();
assert_eq!(results.len(), 1);
match &results[0] {
QueryResult::Keys(keys) => {
assert!(keys.contains(&"/a/b".to_string()));
assert!(keys.contains(&"/a/c".to_string()));
}
_ => panic!("Expected Keys result"),
}
}
#[test]
fn test_query_adapter_object_safe() {
struct CountAdapter;
impl QueryAdapter for CountAdapter {
fn execute(&self, store: &Store, query: &str) -> Result<Vec<QueryResult>, StoreError> {
let keys = store.list(query)?;
Ok(vec![QueryResult::Count(keys.len())])
}
}
let adapter: Box<dyn QueryAdapter> = Box::new(CountAdapter);
let store = Store::new();
store.put("/x", b"x").unwrap();
store.put("/y", b"y").unwrap();
let results = store.query(&*adapter, "/").unwrap();
match &results[0] {
QueryResult::Count(n) => assert_eq!(*n, 2),
_ => panic!("Expected Count result"),
}
}
#[test]
fn test_nearest_semantic() {
use g_math::fixed_point::FixedPoint;
let store = Store::new();
store.put("/courses/trauma/emdr", b"EMDR").unwrap();
store.put("/courses/trauma/ptss", b"PTSS").unwrap();
store.put("/courses/cgt/basis", b"CGT").unwrap();
let coords = |d0: f64, d1: f64| -> Vec<u8> {
let mut v = vec![0u8; 2 * 16];
v[0..16].copy_from_slice(&FixedPoint::from_f64(d0).raw().to_le_bytes());
v[16..32].copy_from_slice(&FixedPoint::from_f64(d1).raw().to_le_bytes());
v
};
store.set_semantic("/courses/trauma/emdr", coords(0.9, 0.1)).unwrap();
store.set_semantic("/courses/trauma/ptss", coords(0.8, 0.2)).unwrap();
store.set_semantic("/courses/cgt/basis", coords(0.1, 0.9)).unwrap();
let query = coords(0.85, 0.15);
let results = store.nearest_semantic(&query, 3, 0..2).unwrap();
assert_eq!(results.len(), 3);
let paths: Vec<&str> = results.iter().map(|(p, _)| p.as_str()).collect();
assert!(paths[0].contains("trauma"), "Nearest should be a trauma course, got {}", paths[0]);
assert!(paths[2].contains("cgt"), "Farthest should be CGT, got {}", paths[2]);
}
#[test]
fn test_neighbors_semantic() {
use g_math::fixed_point::FixedPoint;
let store = Store::new();
store.put("/a", b"a").unwrap();
store.put("/b", b"b").unwrap();
store.put("/c", b"c").unwrap();
let coords = |v: f64| -> Vec<u8> {
let mut buf = vec![0u8; 16];
buf[0..16].copy_from_slice(&FixedPoint::from_f64(v).raw().to_le_bytes());
buf
};
store.set_semantic("/a", coords(0.1)).unwrap();
store.set_semantic("/b", coords(0.2)).unwrap();
store.set_semantic("/c", coords(0.9)).unwrap();
let results = store.neighbors_semantic("/a", 2, 0..1).unwrap();
assert_eq!(results.len(), 2);
assert_eq!(results[0].0, "/b", "Nearest semantic neighbor of /a should be /b");
assert_eq!(results[1].0, "/c", "Second neighbor of /a should be /c");
let paths: Vec<&str> = results.iter().map(|(p, _)| p.as_str()).collect();
assert!(!paths.contains(&"/a"), "Self should be excluded from neighbors_semantic");
}
#[test]
fn test_semantic_distance_utility() {
use g_math::fixed_point::FixedPoint;
let coords = |d0: f64, d1: f64| -> Vec<u8> {
let mut v = vec![0u8; 2 * 16];
v[0..16].copy_from_slice(&FixedPoint::from_f64(d0).raw().to_le_bytes());
v[16..32].copy_from_slice(&FixedPoint::from_f64(d1).raw().to_le_bytes());
v
};
let a = coords(0.0, 0.0);
let b = coords(0.3, 0.4);
let dist = Store::semantic_distance(&a, &b, 0..2);
assert!((dist.to_f64() - 0.5).abs() < 0.01,
"Distance (0,0)→(0.3,0.4) should be 0.5, got {}", dist.to_f64());
}
}