1use std::collections::HashMap;
8use std::fmt::{self, Debug, Formatter};
9use std::ops::Range;
10use std::sync::Arc;
11use dashmap::DashMap;
12use super::concurrency::StripedLock;
13use super::hash_table::GeometricSignature;
14use super::tensor_network::{HyperbolicTensorNetwork, CompressedNode, NodeMetadata};
15
16#[derive(Debug)]
18pub enum IntegrationError {
19 AlreadyExists(String),
21 NotFound(String),
23 OperationFailed(String),
25 ValidationFailed(String),
27 DeserializationError(String),
29 LockError(String),
31 ConfigurationError(String),
33}
34
35impl IntegrationError {
36 pub fn configuration_error(msg: String) -> Self {
38 Self::ConfigurationError(msg)
39 }
40}
41
42impl std::fmt::Display for IntegrationError {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match self {
45 Self::AlreadyExists(s) => write!(f, "already exists: {s}"),
46 Self::NotFound(s) => write!(f, "not found: {s}"),
47 Self::OperationFailed(s) => write!(f, "operation failed: {s}"),
48 Self::ValidationFailed(s) => write!(f, "validation failed: {s}"),
49 Self::DeserializationError(s) => write!(f, "deserialization error: {s}"),
50 Self::LockError(s) => write!(f, "lock error: {s}"),
51 Self::ConfigurationError(s) => write!(f, "configuration error: {s}"),
52 }
53 }
54}
55
56impl std::error::Error for IntegrationError {}
57
58pub type IntegrationResult<T> = Result<T, IntegrationError>;
60
61pub trait PathOperations {
63 fn split_path(&self, path: &str) -> Vec<String>;
65
66 fn join_path(&self, components: &[String]) -> String;
68
69 fn parent_path(&self, path: &str) -> Option<String>;
71
72 fn last_component(&self, path: &str) -> Option<String>;
74}
75
76pub struct DefaultPathOps;
78
79impl PathOperations for DefaultPathOps {
80 fn split_path(&self, path: &str) -> Vec<String> {
81 path.split('/')
82 .filter(|s| !s.is_empty())
83 .map(String::from)
84 .collect()
85 }
86
87 fn join_path(&self, components: &[String]) -> String {
88 let mut path = String::new();
89 for component in components {
90 path.push('/');
91 path.push_str(component);
92 }
93 if path.is_empty() {
94 path.push('/');
95 }
96 path
97 }
98
99 fn parent_path(&self, path: &str) -> Option<String> {
100 if path == "/" {
101 return None;
102 }
103
104 let components = self.split_path(path);
105 if components.is_empty() {
106 return Some("/".to_string());
107 }
108
109 let parent_components = &components[0..components.len() - 1];
110 Some(self.join_path(parent_components))
111 }
112
113 fn last_component(&self, path: &str) -> Option<String> {
114 let components = self.split_path(path);
115 components.last().cloned()
116 }
117}
118
119#[derive(Clone, Debug)]
121pub struct HTTConfig {
122 dimension: usize,
124 max_memory_nodes: usize,
126 cache_size: usize,
128 tau: g_math::fixed_point::FixedPoint,
130 grid_resolution: usize,
132}
133
134impl HTTConfig {
135 pub fn new(dimension: usize, max_memory_nodes: usize, cache_size: usize) -> Self {
137 Self {
138 dimension,
139 max_memory_nodes,
140 cache_size,
141 tau: crate::constants::default_tau(),
142 grid_resolution: 0,
143 }
144 }
145
146 pub fn default_config() -> Self {
148 Self {
149 dimension: 4,
150 max_memory_nodes: 1000,
151 cache_size: 100,
152 tau: crate::constants::default_tau(),
153 grid_resolution: 0,
154 }
155 }
156
157 pub fn with_tau(mut self, tau: g_math::fixed_point::FixedPoint) -> Self {
159 self.tau = tau;
160 self
161 }
162
163 pub fn with_grid_resolution(mut self, resolution: usize) -> Self {
165 self.grid_resolution = resolution;
166 self
167 }
168
169 pub fn grid_resolution(&self) -> usize {
171 self.grid_resolution
172 }
173
174 pub fn dimension(&self) -> usize {
176 self.dimension
177 }
178
179 pub fn max_memory_nodes(&self) -> usize {
181 self.max_memory_nodes
182 }
183
184 pub fn cache_size(&self) -> usize {
186 self.cache_size
187 }
188
189 pub fn tau(&self) -> g_math::fixed_point::FixedPoint {
191 self.tau
192 }
193}
194
195impl Default for HTTConfig {
196 fn default() -> Self {
197 Self::default_config()
198 }
199}
200
201pub struct HyperbolicTreeTensor {
210 tensor_network: HyperbolicTensorNetwork,
212 path_ops: Box<dyn PathOperations + Send + Sync>,
214 path_map: DashMap<String, GeometricSignature>,
216 id_to_path: DashMap<String, String>,
218 parent_locks: StripedLock<64>,
221 config: HTTConfig,
223}
224
225impl HyperbolicTreeTensor {
226 pub fn new(config: HTTConfig) -> Self {
228 let grid_res = config.grid_resolution();
229 let tensor_network = if grid_res > 0 {
230 HyperbolicTensorNetwork::with_grid_resolution(config.dimension(), config.tau(), grid_res)
231 } else {
232 HyperbolicTensorNetwork::new(config.dimension(), config.tau())
233 };
234
235 Self {
236 tensor_network,
237 path_ops: Box::new(DefaultPathOps),
238 path_map: DashMap::new(),
239 id_to_path: DashMap::new(),
240 parent_locks: StripedLock::new(),
241 config,
242 }
243 }
244
245 fn resolve_parent(
254 &self,
255 path: &str,
256 parent_path: &Option<String>,
257 ) -> IntegrationResult<Option<GeometricSignature>> {
258 match parent_path {
259 Some(p) if p.as_str() != path => match self.path_map.get(p.as_str()) {
260 Some(r) => Ok(Some(r.value().clone())),
261 None => Err(IntegrationError::NotFound(format!(
262 "cannot insert '{}': parent '{}' does not exist",
263 path, p
264 ))),
265 },
266 _ => Ok(None), }
268 }
269
270 pub fn insert_data_only(&self, path: &str, value: Vec<u8>, content_type: Option<String>) -> IntegrationResult<()> {
276 if self.path_map.contains_key(path) {
278 return Err(IntegrationError::AlreadyExists(
279 format!("Node at path {} already exists", path),
280 ));
281 }
282
283 let parent_path = self.path_ops.parent_path(path);
287 if let Some(p) = &parent_path {
288 if p.as_str() != path && !self.path_map.contains_key(p.as_str()) {
289 return Err(IntegrationError::NotFound(format!(
290 "cannot insert '{}': parent '{}' does not exist",
291 path, p
292 )));
293 }
294 }
295
296 let _stripe_guard = parent_path.as_deref().map(|p| self.parent_locks.lock(p));
301
302 if self.path_map.contains_key(path) {
304 return Err(IntegrationError::AlreadyExists(
305 format!("Node at path {} already exists", path),
306 ));
307 }
308
309 let metadata = NodeMetadata::new(path.to_string(), content_type);
310
311 let unique_id = self.tensor_network.add_node_data_only(metadata, value, 0);
312
313 let stub_sig = GeometricSignature::stub(&unique_id);
315 self.id_to_path.insert(unique_id, path.to_string());
316 self.path_map.insert(path.to_string(), stub_sig);
317
318 Ok(())
319 }
320
321 pub fn insert(&self, path: &str, value: Vec<u8>, content_type: Option<String>) -> IntegrationResult<()> {
326 if self.path_map.contains_key(path) {
328 return Err(IntegrationError::AlreadyExists(
329 format!("Node at path {} already exists", path),
330 ));
331 }
332
333 let parent_path = self.path_ops.parent_path(path);
334 let level = self.path_depth(path);
335 let metadata = NodeMetadata::new(path.to_string(), content_type);
336
337 let parent_signature = self.resolve_parent(path, &parent_path)?;
341
342 let parent_uid = parent_signature.as_ref().map(|s| s.unique_id());
347 let _stripe_guard = parent_uid.as_deref().map(|uid| self.parent_locks.lock(uid));
348
349 if self.path_map.contains_key(path) {
351 return Err(IntegrationError::AlreadyExists(
352 format!("Node at path {} already exists", path),
353 ));
354 }
355
356 let signature = self
357 .tensor_network
358 .add_node(metadata, value, parent_signature.as_ref(), level)
359 .ok_or_else(|| {
360 IntegrationError::OperationFailed(
361 "Failed to add node to tensor network".to_string(),
362 )
363 })?;
364
365 let unique_id = signature.unique_id();
366 self.id_to_path.insert(unique_id, path.to_string());
367 self.path_map.insert(path.to_string(), signature);
368
369 Ok(())
371 }
372
373 pub fn insert_positioned(&self, path: &str, value: Vec<u8>, content_type: Option<String>, child_index: u32) -> IntegrationResult<()> {
378 if self.path_map.contains_key(path) {
379 return Err(IntegrationError::AlreadyExists(
380 format!("Node at path {} already exists", path),
381 ));
382 }
383
384 let parent_path = self.path_ops.parent_path(path);
385 let level = self.path_depth(path);
386 let metadata = NodeMetadata::new(path.to_string(), content_type);
387
388 let parent_signature = self.resolve_parent(path, &parent_path)?;
389
390 let parent_uid = parent_signature.as_ref().map(|s| s.unique_id());
391 let _stripe_guard = parent_uid.as_deref().map(|uid| self.parent_locks.lock(uid));
392
393 if self.path_map.contains_key(path) {
394 return Err(IntegrationError::AlreadyExists(
395 format!("Node at path {} already exists", path),
396 ));
397 }
398
399 let signature = self
400 .tensor_network
401 .add_node_positioned(metadata, value, parent_signature.as_ref(), level, child_index)
402 .ok_or_else(|| {
403 IntegrationError::OperationFailed(
404 "Failed to add node to tensor network".to_string(),
405 )
406 })?;
407
408 let unique_id = signature.unique_id();
409 self.id_to_path.insert(unique_id, path.to_string());
410 self.path_map.insert(path.to_string(), signature);
411
412 Ok(())
413 }
414
415 pub fn embed_existing(&self, path: &str) -> IntegrationResult<bool> {
444 let sig = match self.path_map.get(path) {
446 Some(r) => r.value().clone(),
447 None => {
448 return Err(IntegrationError::NotFound(format!(
449 "Node at path {} not found",
450 path
451 )))
452 }
453 };
454 if !sig.is_stub() {
455 return Ok(false);
456 }
457
458 let parent_path = self.path_ops.parent_path(path);
462 if let Some(p) = &parent_path {
463 if p.as_str() != path {
464 self.embed_existing(p)?;
465 }
466 }
467
468 let parent_signature = self.resolve_parent(path, &parent_path)?;
469 if let Some(ps) = &parent_signature {
470 if ps.is_stub() {
471 return Err(IntegrationError::OperationFailed(format!(
475 "cannot embed '{}': parent lost its embedding concurrently",
476 path
477 )));
478 }
479 }
480 let parent_uid = parent_signature.as_ref().map(|s| s.unique_id());
481 let _stripe_guard = parent_uid.as_deref().map(|uid| self.parent_locks.lock(uid));
482
483 let old_sig = match self.path_map.get(path) {
486 Some(r) => r.value().clone(),
487 None => {
488 return Err(IntegrationError::NotFound(format!(
489 "Node at path {} not found",
490 path
491 )))
492 }
493 };
494 if !old_sig.is_stub() {
495 return Ok(false);
496 }
497 let old_uid = old_sig.unique_id();
498
499 let node = self
501 .tensor_network
502 .get_node_by_signature(&old_sig)
503 .ok_or_else(|| {
504 IntegrationError::OperationFailed(format!(
505 "data-only node '{}' missing from the node map",
506 path
507 ))
508 })?;
509 let metadata = node.metadata().clone();
510 let value = node.value().to_vec();
511 let coords = node.semantic_coords().to_vec();
512
513 let level = self.path_depth(path);
514 let signature = self
515 .tensor_network
516 .add_node(metadata, value, parent_signature.as_ref(), level)
517 .ok_or_else(|| {
518 IntegrationError::OperationFailed(format!(
519 "failed to embed node '{}'",
520 path
521 ))
522 })?;
523 let new_uid = signature.unique_id();
524
525 if !coords.is_empty() {
528 self.tensor_network.set_node_semantic(&new_uid, coords);
529 }
530
531 self.id_to_path.insert(new_uid, path.to_string());
533 self.path_map.insert(path.to_string(), signature);
534 self.id_to_path.remove(&old_uid);
535 self.tensor_network.remove_detached_node(&old_uid);
536
537 Ok(true)
538 }
539
540 pub fn get(&self, path: &str) -> IntegrationResult<CompressedNode> {
542 let signature = self
543 .path_map
544 .get(path)
545 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
546
547 self.tensor_network
548 .get_node_by_signature(signature.value())
549 .ok_or_else(|| {
550 IntegrationError::NotFound(format!(
551 "Node with signature {} not found",
552 signature.value().hash()
553 ))
554 })
555 }
556
557 pub fn update_value(&self, path: &str, value: Vec<u8>) -> IntegrationResult<()> {
559 let uid = self
560 .path_map
561 .get(path)
562 .map(|r| r.value().unique_id())
563 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
564
565 if self.tensor_network.update_node_value(&uid, value) {
566 Ok(())
567 } else {
568 Err(IntegrationError::NotFound(format!("Node with uid {} not found in network", uid)))
569 }
570 }
571
572 pub fn set_node_metadata(&self, path: &str, key: &str, value: &str) -> IntegrationResult<()> {
574 let uid = self
575 .path_map
576 .get(path)
577 .map(|r| r.value().unique_id())
578 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
579
580 if self.tensor_network.set_node_metadata_entry(&uid, key, value) {
581 Ok(())
582 } else {
583 Err(IntegrationError::NotFound(format!("Node with uid {} not found in network", uid)))
584 }
585 }
586
587 pub fn set_semantic(&self, path: &str, coords: Vec<u8>) -> IntegrationResult<()> {
589 let uid = self
590 .path_map
591 .get(path)
592 .map(|r| r.value().unique_id())
593 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
594
595 if self.tensor_network.set_node_semantic(&uid, coords) {
596 Ok(())
597 } else {
598 Err(IntegrationError::NotFound(format!("Node with uid {} not found in network", uid)))
599 }
600 }
601
602 pub fn get_semantic(&self, path: &str) -> IntegrationResult<Vec<u8>> {
604 let uid = self
605 .path_map
606 .get(path)
607 .map(|r| r.value().unique_id())
608 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
609
610 self.tensor_network
611 .get_node_semantic(&uid)
612 .ok_or_else(|| IntegrationError::NotFound(format!("Node with uid {} not found in network", uid)))
613 }
614
615 pub fn delete(&self, path: &str) -> IntegrationResult<()> {
625 let node_uid = match self.path_map.get(path) {
627 Some(r) => r.value().unique_id(),
628 None => {
629 return Err(IntegrationError::NotFound(format!(
630 "Node at path {} not found",
631 path
632 )))
633 }
634 };
635 let parent_uid = self
636 .path_ops
637 .parent_path(path)
638 .and_then(|pp| self.path_map.get(&pp).map(|s| s.unique_id()));
639
640 let _guards = match &parent_uid {
643 Some(puid) => {
644 let (g1, g2) = self.parent_locks.lock_two(&node_uid, puid);
645 (Some(g1), g2)
646 }
647 None => (Some(self.parent_locks.lock(&node_uid)), None),
648 };
649
650 if !self.path_map.contains_key(path) {
653 return Err(IntegrationError::NotFound(format!(
654 "Node at path {} not found",
655 path
656 )));
657 }
658 let children = self.list_children(path)?;
659 if !children.is_empty() {
660 return Err(IntegrationError::ValidationFailed(format!(
661 "Cannot delete node at {} because it has {} children",
662 path,
663 children.len()
664 )));
665 }
666
667 if let Some((_, sig)) = self.path_map.remove(path) {
671 let unique_id = sig.unique_id();
672 self.id_to_path.remove(&unique_id);
673 self.tensor_network
674 .unregister_node_with_parent(&unique_id, parent_uid.as_deref());
675 }
676
677 Ok(())
678 }
679
680 pub fn list_children(&self, path: &str) -> IntegrationResult<Vec<CompressedNode>> {
682 let signature = self
683 .path_map
684 .get(path)
685 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
686
687 let children = self.tensor_network.children_of(signature.value());
688
689 let result = children
691 .into_iter()
692 .filter(|child| self.path_map.contains_key(&child.metadata().key))
693 .collect();
694
695 Ok(result)
696 }
697
698 pub fn list_subtree(&self, path: &str) -> IntegrationResult<Vec<String>> {
700 let prefix = if path.ends_with('/') {
701 path.to_string()
702 } else {
703 format!("{}/", path)
704 };
705
706 let mut result = Vec::new();
707 for entry in self.path_map.iter() {
708 let node_path = entry.key();
709 if node_path.as_str() != path && (path == "/" || node_path.starts_with(&prefix)) {
710 result.push(node_path.clone());
711 }
712 }
713
714 Ok(result)
715 }
716
717 fn path_depth(&self, path: &str) -> u32 {
719 if path == "/" {
720 return 0;
721 }
722 self.path_ops.split_path(path).len() as u32
723 }
724
725 pub fn exists(&self, path: &str) -> bool {
727 self.path_map.contains_key(path)
728 }
729
730 pub fn node_count(&self) -> usize {
732 self.path_map.len()
733 }
734
735 pub fn stats(&self) -> HashMap<String, String> {
737 let mut stats = HashMap::new();
738 stats.insert("node_count".to_string(), self.node_count().to_string());
739 stats.insert(
740 "dimension".to_string(),
741 self.config.dimension().to_string(),
742 );
743 stats
744 }
745
746 pub fn validate(&self) -> bool {
751 if self.path_map.is_empty() {
753 return true;
754 }
755
756 if !self.tensor_network.validate_network() {
758 return false;
759 }
760
761 for entry in self.path_map.iter() {
763 let path = entry.key();
764 if path == "/" {
765 continue;
766 }
767 if let Some(parent_path) = self.path_ops.parent_path(path) {
768 if !self.path_map.contains_key(&parent_path) {
769 return false;
770 }
771 }
772 }
773
774 for entry in self.path_map.iter() {
776 let path = entry.key();
777 let sig = entry.value();
778 let uid = sig.unique_id();
779 match self.id_to_path.get(&uid) {
780 Some(reverse_path) if reverse_path.value() == path => {},
781 _ => return false,
782 }
783 }
784 for entry in self.id_to_path.iter() {
785 let uid = entry.key();
786 let path = entry.value();
787 match self.path_map.get(path.as_str()) {
788 Some(sig) if sig.value().unique_id() == *uid => {},
789 _ => return false,
790 }
791 }
792
793 if self.path_map.len() != self.id_to_path.len() {
795 return false;
796 }
797
798 true
799 }
800
801 pub fn tensor_network(&self) -> &HyperbolicTensorNetwork {
803 &self.tensor_network
804 }
805
806 pub fn path_for_id(&self, unique_id: &str) -> Option<String> {
808 self.id_to_path.get(unique_id).map(|r| r.value().clone())
809 }
810
811 pub fn position(&self, path: &str) -> IntegrationResult<super::hyperbolic_geometry::HyperbolicPoint> {
816 let sig = self
817 .path_map
818 .get(path)
819 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
820 let unique_id = sig.value().unique_id();
821 drop(sig);
822 self.tensor_network.get_point(&unique_id).ok_or_else(|| {
823 IntegrationError::OperationFailed(format!(
824 "node {} has no geometric embedding (data-only)",
825 path
826 ))
827 })
828 }
829
830 pub fn path_ops(&self) -> &dyn PathOperations {
832 &*self.path_ops
833 }
834
835 pub fn nearest_neighbor_point(&self, query: &super::hyperbolic_geometry::HyperbolicPoint) -> IntegrationResult<(String, g_math::fixed_point::FixedPoint)> {
840 let (uid, dist) = self.tensor_network
841 .nearest_neighbor_point(query)
842 .ok_or_else(|| IntegrationError::OperationFailed(
843 "No nodes in tree for nearest neighbor query".to_string()
844 ))?;
845
846 let path = self.id_to_path.get(&uid)
847 .ok_or_else(|| IntegrationError::NotFound(
848 format!("No path for unique_id {}", uid)
849 ))?;
850
851 Ok((path.value().clone(), dist))
852 }
853
854 pub fn nearest_neighbor_point_k(&self, query: &super::hyperbolic_geometry::HyperbolicPoint, k: usize) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
858 let results = self.tensor_network.nearest_neighbor_point_k(query, k);
859 if results.is_empty() {
860 return Err(IntegrationError::OperationFailed(
861 "No nodes in tree for nearest neighbor query".to_string()
862 ));
863 }
864
865 let mut paths = Vec::with_capacity(results.len());
866 for (uid, dist) in results {
867 if let Some(p) = self.id_to_path.get(&uid) {
868 paths.push((p.value().clone(), dist));
869 }
870 }
871 Ok(paths)
872 }
873
874 pub fn find_nearest(&self, path: &str, k: usize) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
877 let sig = self
878 .path_map
879 .get(path)
880 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
881
882 let unique_id = sig.value().unique_id();
883 drop(sig);
885
886 let point = self
887 .tensor_network
888 .get_point(&unique_id)
889 .ok_or_else(|| IntegrationError::OperationFailed("Point not found in spatial index".to_string()))?;
890
891 let results = self
892 .tensor_network
893 .hash_table()
894 .find_nearest_nodes(&point, k + 1); let mut paths = Vec::new();
897 for (uid, dist) in results {
898 if uid == unique_id {
899 continue; }
901 if let Some(p) = self.id_to_path.get(&uid) {
902 paths.push((p.value().clone(), dist));
903 }
904 }
905 paths.truncate(k);
906 Ok(paths)
907 }
908
909 pub fn nearest_semantic(
922 &self,
923 query_coords: &[u8],
924 k: usize,
925 dim_range: &Range<usize>,
926 ) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
927 Ok(self.tensor_network.nearest_semantic(query_coords, k, dim_range))
930 }
931
932 pub fn neighbors_semantic(
937 &self,
938 path: &str,
939 k: usize,
940 dim_range: &Range<usize>,
941 ) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
942 let coords = self.get_semantic(path)?;
943
944 let results = self.tensor_network.nearest_semantic(&coords, k + 1, dim_range);
949
950 let self_key = self
951 .path_map
952 .get(path)
953 .and_then(|r| self.id_to_path.get(&r.value().unique_id()).map(|p| p.value().clone()));
954
955 let mut paths = Vec::with_capacity(k);
956 for (key, dist) in results {
957 if Some(&key) == self_key.as_ref() {
958 continue; }
960 paths.push((key, dist));
961 if paths.len() >= k {
962 break;
963 }
964 }
965 Ok(paths)
966 }
967
968 pub fn find_in_radius(&self, path: &str, radius: g_math::fixed_point::FixedPoint) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
971 let sig = self
972 .path_map
973 .get(path)
974 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
975
976 let unique_id = sig.value().unique_id();
977 drop(sig);
978
979 let point = self
980 .tensor_network
981 .get_point(&unique_id)
982 .ok_or_else(|| IntegrationError::OperationFailed("Point not found in spatial index".to_string()))?;
983
984 let results = self
985 .tensor_network
986 .hash_table()
987 .find_nodes_in_radius(&point, radius);
988
989 let mut paths = Vec::new();
990 for (uid, dist) in results {
991 if uid == unique_id {
992 continue; }
994 if let Some(p) = self.id_to_path.get(&uid) {
995 paths.push((p.value().clone(), dist));
996 }
997 }
998 Ok(paths)
999 }
1000}
1001
1002impl Debug for HyperbolicTreeTensor {
1003 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1004 write!(f, "HyperbolicTreeTensor(nodes={})", self.node_count())
1005 }
1006}
1007
1008pub type SharedHTT = Arc<HyperbolicTreeTensor>;
1013
1014#[cfg(test)]
1015mod tests {
1016 use super::*;
1017
1018 #[test]
1019 fn test_path_operations() {
1020 let path_ops = DefaultPathOps;
1021
1022 let components = path_ops.split_path("/a/b/c");
1023 assert_eq!(
1024 components,
1025 vec!["a".to_string(), "b".to_string(), "c".to_string()]
1026 );
1027
1028 let path = path_ops.join_path(&["a".to_string(), "b".to_string(), "c".to_string()]);
1029 assert_eq!(path, "/a/b/c");
1030
1031 assert_eq!(path_ops.parent_path("/a/b/c"), Some("/a/b".to_string()));
1032 assert_eq!(path_ops.parent_path("/a"), Some("/".to_string()));
1033 assert_eq!(path_ops.parent_path("/"), None);
1034
1035 assert_eq!(path_ops.last_component("/a/b/c"), Some("c".to_string()));
1036 assert_eq!(path_ops.last_component("/a"), Some("a".to_string()));
1037 assert_eq!(path_ops.last_component("/"), None);
1038 }
1039
1040 #[test]
1041 fn test_tree_tensor_creation() {
1042 let config = HTTConfig::default();
1043 let tree = HyperbolicTreeTensor::new(config);
1044 assert_eq!(tree.node_count(), 0);
1045 }
1046
1047 #[test]
1048 fn test_tree_tensor_operations() {
1049 let config = HTTConfig::default();
1050 let tree = HyperbolicTreeTensor::new(config);
1051
1052 tree.insert("/", vec![], None).unwrap();
1054 assert_eq!(tree.node_count(), 1);
1055 assert!(tree.exists("/"));
1056
1057 let root = tree.get("/").unwrap();
1059 assert_eq!(root.metadata().key, "/");
1060
1061 tree.insert("/child1", b"child1 data".to_vec(), None).unwrap();
1063 tree.insert("/child2", b"child2 data".to_vec(), None).unwrap();
1064 assert_eq!(tree.node_count(), 3);
1065
1066 tree.insert("/child1/grandchild", b"grandchild data".to_vec(), None).unwrap();
1068 assert_eq!(tree.node_count(), 4);
1069
1070 let children = tree.list_children("/").unwrap();
1072 assert_eq!(children.len(), 2);
1073
1074 let child_keys: Vec<&str> = children.iter().map(|c| c.metadata().key.as_str()).collect();
1075 assert!(child_keys.contains(&"/child1"));
1076 assert!(child_keys.contains(&"/child2"));
1077
1078 tree.update_value("/child1", b"updated data".to_vec()).unwrap();
1080 let updated = tree.get("/child1").unwrap();
1081 assert_eq!(updated.value(), b"updated data");
1082
1083 let subtree = tree.list_subtree("/").unwrap();
1085 assert_eq!(subtree.len(), 3); let result = tree.delete("/child1");
1089 assert!(result.is_err());
1090
1091 tree.delete("/child1/grandchild").unwrap();
1093 assert_eq!(tree.node_count(), 3);
1094
1095 tree.delete("/child1").unwrap();
1097 assert_eq!(tree.node_count(), 2);
1098 }
1099
1100 #[test]
1101 fn test_tree_validation() {
1102 let config = HTTConfig::default();
1103 let tree = HyperbolicTreeTensor::new(config);
1104
1105 assert!(tree.validate());
1107
1108 tree.insert("/", vec![], None).unwrap();
1110 tree.insert("/child", b"child data".to_vec(), None).unwrap();
1111
1112 assert!(tree.validate());
1114 }
1115
1116 #[test]
1117 fn test_id_to_path_mapping() {
1118 let config = HTTConfig::default();
1119 let tree = HyperbolicTreeTensor::new(config);
1120
1121 tree.insert("/", vec![], None).unwrap();
1122 tree.insert("/test", b"test".to_vec(), None).unwrap();
1123
1124 let uid = tree.path_map.get("/test").unwrap().value().unique_id();
1126 let resolved_path = tree.path_for_id(&uid);
1127 assert_eq!(resolved_path, Some("/test".to_string()));
1128 }
1129
1130 #[test]
1131 fn test_find_nearest() {
1132 let config = HTTConfig::default();
1133 let tree = HyperbolicTreeTensor::new(config);
1134
1135 tree.insert("/", vec![], None).unwrap();
1136 tree.insert("/a", b"a".to_vec(), None).unwrap();
1137 tree.insert("/b", b"b".to_vec(), None).unwrap();
1138 tree.insert("/c", b"c".to_vec(), None).unwrap();
1139 tree.insert("/a/child", b"ac".to_vec(), None).unwrap();
1140
1141 let nearest = tree.find_nearest("/a", 3).unwrap();
1143 assert!(!nearest.is_empty());
1144 assert!(nearest.len() <= 3);
1145
1146 let paths: Vec<&str> = nearest.iter().map(|(p, _)| p.as_str()).collect();
1148 assert!(!paths.contains(&"/a"));
1149
1150 for i in 1..nearest.len() {
1152 assert!(nearest[i].1 >= nearest[i - 1].1);
1153 }
1154 }
1155
1156 #[test]
1157 fn test_find_in_radius() {
1158 use g_math::fixed_point::FixedPoint;
1159
1160 let config = HTTConfig::default();
1161 let tree = HyperbolicTreeTensor::new(config);
1162
1163 tree.insert("/", vec![], None).unwrap();
1164 tree.insert("/a", b"a".to_vec(), None).unwrap();
1165 tree.insert("/b", b"b".to_vec(), None).unwrap();
1166
1167 let large_radius = FixedPoint::from_int(10);
1169 let results = tree.find_in_radius("/", large_radius).unwrap();
1170 assert!(results.len() >= 2, "Expected at least 2 nodes within large radius, got {}", results.len());
1171
1172 let tiny_radius = FixedPoint::from_int(1) / FixedPoint::from_int(10000);
1174 let results = tree.find_in_radius("/", tiny_radius).unwrap();
1175 assert!(results.len() <= 2);
1178 }
1179
1180 #[test]
1181 fn test_delete_unregisters_spatial() {
1182 let config = HTTConfig::default();
1183 let tree = HyperbolicTreeTensor::new(config);
1184
1185 tree.insert("/", vec![], None).unwrap();
1186 tree.insert("/leaf", b"leaf".to_vec(), None).unwrap();
1187
1188 let unique_id = tree.path_map.get("/leaf").unwrap().value().unique_id();
1190
1191 assert!(tree.tensor_network().get_point(&unique_id).is_some());
1193
1194 tree.delete("/leaf").unwrap();
1196
1197 assert!(tree.tensor_network().get_point(&unique_id).is_none());
1199 assert!(tree.path_for_id(&unique_id).is_none());
1200 }
1201}