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}
131
132impl HTTConfig {
133 pub fn new(dimension: usize, max_memory_nodes: usize, cache_size: usize) -> Self {
135 Self {
136 dimension,
137 max_memory_nodes,
138 cache_size,
139 tau: crate::constants::default_tau(),
140 }
141 }
142
143 pub fn default_config() -> Self {
145 Self {
146 dimension: 4,
147 max_memory_nodes: 1000,
148 cache_size: 100,
149 tau: crate::constants::default_tau(),
150 }
151 }
152
153 pub fn with_tau(mut self, tau: g_math::fixed_point::FixedPoint) -> Self {
155 self.tau = tau;
156 self
157 }
158
159 pub fn dimension(&self) -> usize {
161 self.dimension
162 }
163
164 pub fn max_memory_nodes(&self) -> usize {
166 self.max_memory_nodes
167 }
168
169 pub fn cache_size(&self) -> usize {
171 self.cache_size
172 }
173
174 pub fn tau(&self) -> g_math::fixed_point::FixedPoint {
176 self.tau
177 }
178}
179
180impl Default for HTTConfig {
181 fn default() -> Self {
182 Self::default_config()
183 }
184}
185
186pub struct HyperbolicTreeTensor {
194 tensor_network: HyperbolicTensorNetwork,
196 path_ops: Box<dyn PathOperations + Send + Sync>,
198 path_map: DashMap<String, GeometricSignature>,
200 id_to_path: DashMap<String, String>,
202 parent_locks: StripedLock<64>,
205 config: HTTConfig,
207}
208
209impl HyperbolicTreeTensor {
210 pub fn new(config: HTTConfig) -> Self {
212 let tensor_network = HyperbolicTensorNetwork::new(config.dimension(), config.tau());
213
214 Self {
215 tensor_network,
216 path_ops: Box::new(DefaultPathOps),
217 path_map: DashMap::new(),
218 id_to_path: DashMap::new(),
219 parent_locks: StripedLock::new(),
220 config,
221 }
222 }
223
224 fn resolve_parent(
233 &self,
234 path: &str,
235 parent_path: &Option<String>,
236 ) -> IntegrationResult<Option<GeometricSignature>> {
237 match parent_path {
238 Some(p) if p.as_str() != path => match self.path_map.get(p.as_str()) {
239 Some(r) => Ok(Some(r.value().clone())),
240 None => Err(IntegrationError::NotFound(format!(
241 "cannot insert '{}': parent '{}' does not exist",
242 path, p
243 ))),
244 },
245 _ => Ok(None), }
247 }
248
249 pub fn insert_data_only(&self, path: &str, value: Vec<u8>, content_type: Option<String>) -> IntegrationResult<()> {
255 if self.path_map.contains_key(path) {
257 return Err(IntegrationError::AlreadyExists(
258 format!("Node at path {} already exists", path),
259 ));
260 }
261
262 let parent_path = self.path_ops.parent_path(path);
266 if let Some(p) = &parent_path {
267 if p.as_str() != path && !self.path_map.contains_key(p.as_str()) {
268 return Err(IntegrationError::NotFound(format!(
269 "cannot insert '{}': parent '{}' does not exist",
270 path, p
271 )));
272 }
273 }
274
275 let _stripe_guard = parent_path.as_deref().map(|p| self.parent_locks.lock(p));
280
281 if self.path_map.contains_key(path) {
283 return Err(IntegrationError::AlreadyExists(
284 format!("Node at path {} already exists", path),
285 ));
286 }
287
288 let metadata = NodeMetadata::new(path.to_string(), content_type);
289
290 let unique_id = self.tensor_network.add_node_data_only(metadata, value, 0);
291
292 let stub_sig = GeometricSignature::stub(&unique_id);
294 self.id_to_path.insert(unique_id, path.to_string());
295 self.path_map.insert(path.to_string(), stub_sig);
296
297 Ok(())
298 }
299
300 pub fn insert(&self, path: &str, value: Vec<u8>, content_type: Option<String>) -> IntegrationResult<()> {
305 if self.path_map.contains_key(path) {
307 return Err(IntegrationError::AlreadyExists(
308 format!("Node at path {} already exists", path),
309 ));
310 }
311
312 let parent_path = self.path_ops.parent_path(path);
313 let level = self.path_depth(path);
314 let metadata = NodeMetadata::new(path.to_string(), content_type);
315
316 let parent_signature = self.resolve_parent(path, &parent_path)?;
320
321 let parent_uid = parent_signature.as_ref().map(|s| s.unique_id());
326 let _stripe_guard = parent_uid.as_deref().map(|uid| self.parent_locks.lock(uid));
327
328 if self.path_map.contains_key(path) {
330 return Err(IntegrationError::AlreadyExists(
331 format!("Node at path {} already exists", path),
332 ));
333 }
334
335 let signature = self
336 .tensor_network
337 .add_node(metadata, value, parent_signature.as_ref(), level)
338 .ok_or_else(|| {
339 IntegrationError::OperationFailed(
340 "Failed to add node to tensor network".to_string(),
341 )
342 })?;
343
344 let unique_id = signature.unique_id();
345 self.id_to_path.insert(unique_id, path.to_string());
346 self.path_map.insert(path.to_string(), signature);
347
348 Ok(())
350 }
351
352 pub fn insert_positioned(&self, path: &str, value: Vec<u8>, content_type: Option<String>, child_index: u32) -> IntegrationResult<()> {
357 if self.path_map.contains_key(path) {
358 return Err(IntegrationError::AlreadyExists(
359 format!("Node at path {} already exists", path),
360 ));
361 }
362
363 let parent_path = self.path_ops.parent_path(path);
364 let level = self.path_depth(path);
365 let metadata = NodeMetadata::new(path.to_string(), content_type);
366
367 let parent_signature = self.resolve_parent(path, &parent_path)?;
368
369 let parent_uid = parent_signature.as_ref().map(|s| s.unique_id());
370 let _stripe_guard = parent_uid.as_deref().map(|uid| self.parent_locks.lock(uid));
371
372 if self.path_map.contains_key(path) {
373 return Err(IntegrationError::AlreadyExists(
374 format!("Node at path {} already exists", path),
375 ));
376 }
377
378 let signature = self
379 .tensor_network
380 .add_node_positioned(metadata, value, parent_signature.as_ref(), level, child_index)
381 .ok_or_else(|| {
382 IntegrationError::OperationFailed(
383 "Failed to add node to tensor network".to_string(),
384 )
385 })?;
386
387 let unique_id = signature.unique_id();
388 self.id_to_path.insert(unique_id, path.to_string());
389 self.path_map.insert(path.to_string(), signature);
390
391 Ok(())
392 }
393
394 pub fn embed_existing(&self, path: &str) -> IntegrationResult<bool> {
423 let sig = match self.path_map.get(path) {
425 Some(r) => r.value().clone(),
426 None => {
427 return Err(IntegrationError::NotFound(format!(
428 "Node at path {} not found",
429 path
430 )))
431 }
432 };
433 if !sig.is_stub() {
434 return Ok(false);
435 }
436
437 let parent_path = self.path_ops.parent_path(path);
441 if let Some(p) = &parent_path {
442 if p.as_str() != path {
443 self.embed_existing(p)?;
444 }
445 }
446
447 let parent_signature = self.resolve_parent(path, &parent_path)?;
448 if let Some(ps) = &parent_signature {
449 if ps.is_stub() {
450 return Err(IntegrationError::OperationFailed(format!(
454 "cannot embed '{}': parent lost its embedding concurrently",
455 path
456 )));
457 }
458 }
459 let parent_uid = parent_signature.as_ref().map(|s| s.unique_id());
460 let _stripe_guard = parent_uid.as_deref().map(|uid| self.parent_locks.lock(uid));
461
462 let old_sig = match self.path_map.get(path) {
465 Some(r) => r.value().clone(),
466 None => {
467 return Err(IntegrationError::NotFound(format!(
468 "Node at path {} not found",
469 path
470 )))
471 }
472 };
473 if !old_sig.is_stub() {
474 return Ok(false);
475 }
476 let old_uid = old_sig.unique_id();
477
478 let node = self
480 .tensor_network
481 .get_node_by_signature(&old_sig)
482 .ok_or_else(|| {
483 IntegrationError::OperationFailed(format!(
484 "data-only node '{}' missing from the node map",
485 path
486 ))
487 })?;
488 let metadata = node.metadata().clone();
489 let value = node.value().to_vec();
490 let coords = node.semantic_coords().to_vec();
491
492 let level = self.path_depth(path);
493 let signature = self
494 .tensor_network
495 .add_node(metadata, value, parent_signature.as_ref(), level)
496 .ok_or_else(|| {
497 IntegrationError::OperationFailed(format!(
498 "failed to embed node '{}'",
499 path
500 ))
501 })?;
502 let new_uid = signature.unique_id();
503
504 if !coords.is_empty() {
507 self.tensor_network.set_node_semantic(&new_uid, coords);
508 }
509
510 self.id_to_path.insert(new_uid, path.to_string());
512 self.path_map.insert(path.to_string(), signature);
513 self.id_to_path.remove(&old_uid);
514 self.tensor_network.remove_detached_node(&old_uid);
515
516 Ok(true)
517 }
518
519 pub fn get(&self, path: &str) -> IntegrationResult<CompressedNode> {
521 let signature = self
522 .path_map
523 .get(path)
524 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
525
526 self.tensor_network
527 .get_node_by_signature(signature.value())
528 .ok_or_else(|| {
529 IntegrationError::NotFound(format!(
530 "Node with signature {} not found",
531 signature.value().hash()
532 ))
533 })
534 }
535
536 pub fn update_value(&self, path: &str, value: Vec<u8>) -> IntegrationResult<()> {
538 let uid = self
539 .path_map
540 .get(path)
541 .map(|r| r.value().unique_id())
542 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
543
544 if self.tensor_network.update_node_value(&uid, value) {
545 Ok(())
546 } else {
547 Err(IntegrationError::NotFound(format!("Node with uid {} not found in network", uid)))
548 }
549 }
550
551 pub fn set_node_metadata(&self, path: &str, key: &str, value: &str) -> IntegrationResult<()> {
553 let uid = self
554 .path_map
555 .get(path)
556 .map(|r| r.value().unique_id())
557 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
558
559 if self.tensor_network.set_node_metadata_entry(&uid, key, value) {
560 Ok(())
561 } else {
562 Err(IntegrationError::NotFound(format!("Node with uid {} not found in network", uid)))
563 }
564 }
565
566 pub fn set_semantic(&self, path: &str, coords: Vec<u8>) -> IntegrationResult<()> {
568 let uid = self
569 .path_map
570 .get(path)
571 .map(|r| r.value().unique_id())
572 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
573
574 if self.tensor_network.set_node_semantic(&uid, coords) {
575 Ok(())
576 } else {
577 Err(IntegrationError::NotFound(format!("Node with uid {} not found in network", uid)))
578 }
579 }
580
581 pub fn get_semantic(&self, path: &str) -> IntegrationResult<Vec<u8>> {
583 let uid = self
584 .path_map
585 .get(path)
586 .map(|r| r.value().unique_id())
587 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
588
589 self.tensor_network
590 .get_node_semantic(&uid)
591 .ok_or_else(|| IntegrationError::NotFound(format!("Node with uid {} not found in network", uid)))
592 }
593
594 pub fn delete(&self, path: &str) -> IntegrationResult<()> {
604 let node_uid = match self.path_map.get(path) {
606 Some(r) => r.value().unique_id(),
607 None => {
608 return Err(IntegrationError::NotFound(format!(
609 "Node at path {} not found",
610 path
611 )))
612 }
613 };
614 let parent_uid = self
615 .path_ops
616 .parent_path(path)
617 .and_then(|pp| self.path_map.get(&pp).map(|s| s.unique_id()));
618
619 let _guards = match &parent_uid {
622 Some(puid) => {
623 let (g1, g2) = self.parent_locks.lock_two(&node_uid, puid);
624 (Some(g1), g2)
625 }
626 None => (Some(self.parent_locks.lock(&node_uid)), None),
627 };
628
629 if !self.path_map.contains_key(path) {
632 return Err(IntegrationError::NotFound(format!(
633 "Node at path {} not found",
634 path
635 )));
636 }
637 let children = self.list_children(path)?;
638 if !children.is_empty() {
639 return Err(IntegrationError::ValidationFailed(format!(
640 "Cannot delete node at {} because it has {} children",
641 path,
642 children.len()
643 )));
644 }
645
646 if let Some((_, sig)) = self.path_map.remove(path) {
650 let unique_id = sig.unique_id();
651 self.id_to_path.remove(&unique_id);
652 self.tensor_network
653 .unregister_node_with_parent(&unique_id, parent_uid.as_deref());
654 }
655
656 Ok(())
657 }
658
659 pub fn list_children(&self, path: &str) -> IntegrationResult<Vec<CompressedNode>> {
661 let signature = self
662 .path_map
663 .get(path)
664 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
665
666 let children = self.tensor_network.children_of(signature.value());
667
668 let result = children
670 .into_iter()
671 .filter(|child| self.path_map.contains_key(&child.metadata().key))
672 .collect();
673
674 Ok(result)
675 }
676
677 pub fn list_subtree(&self, path: &str) -> IntegrationResult<Vec<String>> {
679 let prefix = if path.ends_with('/') {
680 path.to_string()
681 } else {
682 format!("{}/", path)
683 };
684
685 let mut result = Vec::new();
686 for entry in self.path_map.iter() {
687 let node_path = entry.key();
688 if node_path.as_str() != path && (path == "/" || node_path.starts_with(&prefix)) {
689 result.push(node_path.clone());
690 }
691 }
692
693 Ok(result)
694 }
695
696 fn path_depth(&self, path: &str) -> u32 {
698 if path == "/" {
699 return 0;
700 }
701 self.path_ops.split_path(path).len() as u32
702 }
703
704 pub fn exists(&self, path: &str) -> bool {
706 self.path_map.contains_key(path)
707 }
708
709 pub fn node_count(&self) -> usize {
711 self.path_map.len()
712 }
713
714 pub fn stats(&self) -> HashMap<String, String> {
716 let mut stats = HashMap::new();
717 stats.insert("node_count".to_string(), self.node_count().to_string());
718 stats.insert(
719 "dimension".to_string(),
720 self.config.dimension().to_string(),
721 );
722 stats
723 }
724
725 pub fn validate(&self) -> bool {
730 if self.path_map.is_empty() {
732 return true;
733 }
734
735 if !self.tensor_network.validate_network() {
737 return false;
738 }
739
740 for entry in self.path_map.iter() {
742 let path = entry.key();
743 if path == "/" {
744 continue;
745 }
746 if let Some(parent_path) = self.path_ops.parent_path(path) {
747 if !self.path_map.contains_key(&parent_path) {
748 return false;
749 }
750 }
751 }
752
753 for entry in self.path_map.iter() {
755 let path = entry.key();
756 let sig = entry.value();
757 let uid = sig.unique_id();
758 match self.id_to_path.get(&uid) {
759 Some(reverse_path) if reverse_path.value() == path => {},
760 _ => return false,
761 }
762 }
763 for entry in self.id_to_path.iter() {
764 let uid = entry.key();
765 let path = entry.value();
766 match self.path_map.get(path.as_str()) {
767 Some(sig) if sig.value().unique_id() == *uid => {},
768 _ => return false,
769 }
770 }
771
772 if self.path_map.len() != self.id_to_path.len() {
774 return false;
775 }
776
777 true
778 }
779
780 pub fn tensor_network(&self) -> &HyperbolicTensorNetwork {
782 &self.tensor_network
783 }
784
785 pub fn path_for_id(&self, unique_id: &str) -> Option<String> {
787 self.id_to_path.get(unique_id).map(|r| r.value().clone())
788 }
789
790 pub fn position(&self, path: &str) -> IntegrationResult<super::hyperbolic_geometry::HyperbolicPoint> {
795 let sig = self
796 .path_map
797 .get(path)
798 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
799 let unique_id = sig.value().unique_id();
800 drop(sig);
801 self.tensor_network.get_point(&unique_id).ok_or_else(|| {
802 IntegrationError::OperationFailed(format!(
803 "node {} has no geometric embedding (data-only)",
804 path
805 ))
806 })
807 }
808
809 pub fn path_ops(&self) -> &dyn PathOperations {
811 &*self.path_ops
812 }
813
814 pub fn nearest_neighbor_point(&self, query: &super::hyperbolic_geometry::HyperbolicPoint) -> IntegrationResult<(String, g_math::fixed_point::FixedPoint)> {
819 let (uid, dist) = self.tensor_network
820 .nearest_neighbor_point(query)
821 .ok_or_else(|| IntegrationError::OperationFailed(
822 "No nodes in tree for nearest neighbor query".to_string()
823 ))?;
824
825 let path = self.id_to_path.get(&uid)
826 .ok_or_else(|| IntegrationError::NotFound(
827 format!("No path for unique_id {}", uid)
828 ))?;
829
830 Ok((path.value().clone(), dist))
831 }
832
833 pub fn nearest_neighbor_point_k(&self, query: &super::hyperbolic_geometry::HyperbolicPoint, k: usize) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
842 if k == 0 {
843 return Ok(Vec::new());
844 }
845 let results = self.tensor_network.nearest_neighbor_point_k(query, k);
846 if results.is_empty() {
847 return Err(IntegrationError::OperationFailed(
848 "No nodes in tree for nearest neighbor query".to_string()
849 ));
850 }
851
852 let mut paths = Vec::with_capacity(results.len());
853 for (uid, dist) in results {
854 if let Some(p) = self.id_to_path.get(&uid) {
855 paths.push((p.value().clone(), dist));
856 }
857 }
858 Ok(paths)
859 }
860
861 pub fn find_nearest(&self, path: &str, k: usize) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
864 let sig = self
865 .path_map
866 .get(path)
867 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
868
869 let unique_id = sig.value().unique_id();
870 drop(sig);
872
873 let point = self
874 .tensor_network
875 .get_point(&unique_id)
876 .ok_or_else(|| IntegrationError::OperationFailed("Point not found in spatial index".to_string()))?;
877
878 let results = self
879 .tensor_network
880 .nearest_neighbor_point_k(&point, k + 1); let mut paths = Vec::new();
883 for (uid, dist) in results {
884 if uid == unique_id {
885 continue; }
887 if let Some(p) = self.id_to_path.get(&uid) {
888 paths.push((p.value().clone(), dist));
889 }
890 }
891 paths.truncate(k);
892 Ok(paths)
893 }
894
895 pub fn nearest_semantic(
908 &self,
909 query_coords: &[u8],
910 k: usize,
911 dim_range: &Range<usize>,
912 ) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
913 Ok(self.tensor_network.nearest_semantic(query_coords, k, dim_range))
916 }
917
918 pub fn neighbors_semantic(
923 &self,
924 path: &str,
925 k: usize,
926 dim_range: &Range<usize>,
927 ) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
928 let coords = self.get_semantic(path)?;
929
930 let results = self.tensor_network.nearest_semantic(&coords, k + 1, dim_range);
935
936 let self_key = self
937 .path_map
938 .get(path)
939 .and_then(|r| self.id_to_path.get(&r.value().unique_id()).map(|p| p.value().clone()));
940
941 let mut paths = Vec::with_capacity(k);
942 for (key, dist) in results {
943 if Some(&key) == self_key.as_ref() {
944 continue; }
946 paths.push((key, dist));
947 if paths.len() >= k {
948 break;
949 }
950 }
951 Ok(paths)
952 }
953
954 pub fn find_in_radius(&self, path: &str, radius: g_math::fixed_point::FixedPoint) -> IntegrationResult<Vec<(String, g_math::fixed_point::FixedPoint)>> {
957 let sig = self
958 .path_map
959 .get(path)
960 .ok_or_else(|| IntegrationError::NotFound(format!("Node at path {} not found", path)))?;
961
962 let unique_id = sig.value().unique_id();
963 drop(sig);
964
965 let point = self
966 .tensor_network
967 .get_point(&unique_id)
968 .ok_or_else(|| IntegrationError::OperationFailed("Point not found in spatial index".to_string()))?;
969
970 let results = self
971 .tensor_network
972 .nodes_in_radius(&point, radius);
973
974 let mut paths = Vec::new();
975 for (uid, dist) in results {
976 if uid == unique_id {
977 continue; }
979 if let Some(p) = self.id_to_path.get(&uid) {
980 paths.push((p.value().clone(), dist));
981 }
982 }
983 Ok(paths)
984 }
985}
986
987impl Debug for HyperbolicTreeTensor {
988 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
989 write!(f, "HyperbolicTreeTensor(nodes={})", self.node_count())
990 }
991}
992
993pub type SharedHTT = Arc<HyperbolicTreeTensor>;
998
999#[cfg(test)]
1000mod tests {
1001 use super::*;
1002
1003 #[test]
1004 fn test_path_operations() {
1005 let path_ops = DefaultPathOps;
1006
1007 let components = path_ops.split_path("/a/b/c");
1008 assert_eq!(
1009 components,
1010 vec!["a".to_string(), "b".to_string(), "c".to_string()]
1011 );
1012
1013 let path = path_ops.join_path(&["a".to_string(), "b".to_string(), "c".to_string()]);
1014 assert_eq!(path, "/a/b/c");
1015
1016 assert_eq!(path_ops.parent_path("/a/b/c"), Some("/a/b".to_string()));
1017 assert_eq!(path_ops.parent_path("/a"), Some("/".to_string()));
1018 assert_eq!(path_ops.parent_path("/"), None);
1019
1020 assert_eq!(path_ops.last_component("/a/b/c"), Some("c".to_string()));
1021 assert_eq!(path_ops.last_component("/a"), Some("a".to_string()));
1022 assert_eq!(path_ops.last_component("/"), None);
1023 }
1024
1025 #[test]
1026 fn test_tree_tensor_creation() {
1027 let config = HTTConfig::default();
1028 let tree = HyperbolicTreeTensor::new(config);
1029 assert_eq!(tree.node_count(), 0);
1030 }
1031
1032 #[test]
1033 fn test_tree_tensor_operations() {
1034 let config = HTTConfig::default();
1035 let tree = HyperbolicTreeTensor::new(config);
1036
1037 tree.insert("/", vec![], None).unwrap();
1039 assert_eq!(tree.node_count(), 1);
1040 assert!(tree.exists("/"));
1041
1042 let root = tree.get("/").unwrap();
1044 assert_eq!(root.metadata().key, "/");
1045
1046 tree.insert("/child1", b"child1 data".to_vec(), None).unwrap();
1048 tree.insert("/child2", b"child2 data".to_vec(), None).unwrap();
1049 assert_eq!(tree.node_count(), 3);
1050
1051 tree.insert("/child1/grandchild", b"grandchild data".to_vec(), None).unwrap();
1053 assert_eq!(tree.node_count(), 4);
1054
1055 let children = tree.list_children("/").unwrap();
1057 assert_eq!(children.len(), 2);
1058
1059 let child_keys: Vec<&str> = children.iter().map(|c| c.metadata().key.as_str()).collect();
1060 assert!(child_keys.contains(&"/child1"));
1061 assert!(child_keys.contains(&"/child2"));
1062
1063 tree.update_value("/child1", b"updated data".to_vec()).unwrap();
1065 let updated = tree.get("/child1").unwrap();
1066 assert_eq!(updated.value(), b"updated data");
1067
1068 let subtree = tree.list_subtree("/").unwrap();
1070 assert_eq!(subtree.len(), 3); let result = tree.delete("/child1");
1074 assert!(result.is_err());
1075
1076 tree.delete("/child1/grandchild").unwrap();
1078 assert_eq!(tree.node_count(), 3);
1079
1080 tree.delete("/child1").unwrap();
1082 assert_eq!(tree.node_count(), 2);
1083 }
1084
1085 #[test]
1086 fn test_tree_validation() {
1087 let config = HTTConfig::default();
1088 let tree = HyperbolicTreeTensor::new(config);
1089
1090 assert!(tree.validate());
1092
1093 tree.insert("/", vec![], None).unwrap();
1095 tree.insert("/child", b"child data".to_vec(), None).unwrap();
1096
1097 assert!(tree.validate());
1099 }
1100
1101 #[test]
1102 fn test_id_to_path_mapping() {
1103 let config = HTTConfig::default();
1104 let tree = HyperbolicTreeTensor::new(config);
1105
1106 tree.insert("/", vec![], None).unwrap();
1107 tree.insert("/test", b"test".to_vec(), None).unwrap();
1108
1109 let uid = tree.path_map.get("/test").unwrap().value().unique_id();
1111 let resolved_path = tree.path_for_id(&uid);
1112 assert_eq!(resolved_path, Some("/test".to_string()));
1113 }
1114
1115 #[test]
1116 fn test_find_nearest() {
1117 let config = HTTConfig::default();
1118 let tree = HyperbolicTreeTensor::new(config);
1119
1120 tree.insert("/", vec![], None).unwrap();
1121 tree.insert("/a", b"a".to_vec(), None).unwrap();
1122 tree.insert("/b", b"b".to_vec(), None).unwrap();
1123 tree.insert("/c", b"c".to_vec(), None).unwrap();
1124 tree.insert("/a/child", b"ac".to_vec(), None).unwrap();
1125
1126 let nearest = tree.find_nearest("/a", 3).unwrap();
1128 assert!(!nearest.is_empty());
1129 assert!(nearest.len() <= 3);
1130
1131 let paths: Vec<&str> = nearest.iter().map(|(p, _)| p.as_str()).collect();
1133 assert!(!paths.contains(&"/a"));
1134
1135 for i in 1..nearest.len() {
1137 assert!(nearest[i].1 >= nearest[i - 1].1);
1138 }
1139 }
1140
1141 #[test]
1142 fn test_find_in_radius() {
1143 use g_math::fixed_point::FixedPoint;
1144
1145 let config = HTTConfig::default();
1146 let tree = HyperbolicTreeTensor::new(config);
1147
1148 tree.insert("/", vec![], None).unwrap();
1149 tree.insert("/a", b"a".to_vec(), None).unwrap();
1150 tree.insert("/b", b"b".to_vec(), None).unwrap();
1151
1152 let large_radius = FixedPoint::from_int(10);
1154 let results = tree.find_in_radius("/", large_radius).unwrap();
1155 assert!(results.len() >= 2, "Expected at least 2 nodes within large radius, got {}", results.len());
1156
1157 let tiny_radius = FixedPoint::from_int(1) / FixedPoint::from_int(10000);
1159 let results = tree.find_in_radius("/", tiny_radius).unwrap();
1160 assert!(results.len() <= 2);
1163 }
1164
1165 #[test]
1166 fn test_delete_unregisters_spatial() {
1167 let config = HTTConfig::default();
1168 let tree = HyperbolicTreeTensor::new(config);
1169
1170 tree.insert("/", vec![], None).unwrap();
1171 tree.insert("/leaf", b"leaf".to_vec(), None).unwrap();
1172
1173 let unique_id = tree.path_map.get("/leaf").unwrap().value().unique_id();
1175
1176 assert!(tree.tensor_network().get_point(&unique_id).is_some());
1178
1179 tree.delete("/leaf").unwrap();
1181
1182 assert!(tree.tensor_network().get_point(&unique_id).is_none());
1184 assert!(tree.path_for_id(&unique_id).is_none());
1185 }
1186}