Skip to main content

HyperbolicTreeTensor

Struct HyperbolicTreeTensor 

Source
pub struct HyperbolicTreeTensor { /* private fields */ }
Expand description

Hyperbolic Tree Tensor - core data structure.

Path access is hash-map cost; spatial queries go through the cell index. Nodes are embedded in the Poincare disk, and their positions are derived from tree shape rather than stored.

Path maps use DashMap for lock-free concurrent reads.

Implementations§

Source§

impl HyperbolicTreeTensor

Source

pub fn new(config: HTTConfig) -> Self

Create a new Hyperbolic Tree Tensor.

Source

pub fn insert_data_only( &self, path: &str, value: Vec<u8>, content_type: Option<String>, ) -> IntegrationResult<()>

Insert a node without geometric embedding (data + semantic only).

Much faster than insert() — skips Sarkar embedding, VP-tree, power diagram, and point location grid. Use for bulk loading when spatial queries are not needed (semantic queries still work).

Source

pub fn insert( &self, path: &str, value: Vec<u8>, content_type: Option<String>, ) -> IntegrationResult<()>

Insert a node at the specified path.

Acquires a striped parent lock to serialize writes to the same parent while allowing parallel writes to different parents.

Source

pub fn insert_positioned( &self, path: &str, value: Vec<u8>, content_type: Option<String>, child_index: u32, ) -> IntegrationResult<()>

Insert a node with an explicit child_index for deterministic Sarkar reconstruction.

Same as insert() but passes the child_index through to the tensor network so the node gets the same geometric position regardless of insertion order.

Source

pub fn embed_existing(&self, path: &str) -> IntegrationResult<bool>

Upgrade a data-only node to a full geometric embedding, in place.

Data-only nodes (insert_data_only) live under a stub signature with no Poincaré position — semantic queries see them, spatial queries do not. This computes their Sarkar placement on demand: missing ancestors are embedded first (placement needs an embedded parent; recursion is bounded by the ~44/τ depth budget), then the node is re-registered under its position-derived signature with its identity preserved — key, value, user metadata, timestamps, and semantic coordinates all carry over.

Returns Ok(true) when this call performed the upgrade, Ok(false) when the node was already embedded (idempotent), NotFound for missing paths.

Concurrency: takes the same parent stripe lock as insert, so embeds serialize with sibling inserts and deletes; racing embeds of the same node resolve to one upgrade (double-checked under the lock). Readers never observe the node missing: the embedded replacement (with coordinates already copied) goes live in path_map before the data-only entry is retired — a concurrent semantic query may transiently see the key twice (same key, same coordinates) inside that window.

Geometric positions are derived state and are NOT persisted: the position depends on the sibling order at embed time, so it is deterministic for a fixed operation sequence but not stable across sessions. Callers re-embed after reopening a lazily-loaded store.

Source

pub fn get(&self, path: &str) -> IntegrationResult<CompressedNode>

Get a node by path (returns cloned value).

Source

pub fn update_value(&self, path: &str, value: Vec<u8>) -> IntegrationResult<()>

Update the value of a node at the specified path.

Source

pub fn set_node_metadata( &self, path: &str, key: &str, value: &str, ) -> IntegrationResult<()>

Set a metadata key-value pair on a node.

Source

pub fn set_semantic(&self, path: &str, coords: Vec<u8>) -> IntegrationResult<()>

Set semantic coordinates on a node (raw Q64.64 bytes, 16 bytes per dimension).

Source

pub fn get_semantic(&self, path: &str) -> IntegrationResult<Vec<u8>>

Get semantic coordinates for a node (raw Q64.64 bytes).

Source

pub fn delete(&self, path: &str) -> IntegrationResult<()>

Delete a node at the specified path.

A node with live children cannot be deleted (that would orphan them). The check and the removal run under two stripe locks — the node’s own (which blocks a concurrent insert of a child under it, closing the has-no-children TOCTOU) and its parent’s (which serializes the parent’s child-list mutation against sibling inserts/deletes). The two stripes are taken in canonical order, so this never deadlocks against a concurrent delete.

Source

pub fn list_children( &self, path: &str, ) -> IntegrationResult<Vec<CompressedNode>>

List children of a node at the specified path (cloned).

Source

pub fn list_subtree(&self, path: &str) -> IntegrationResult<Vec<String>>

List all node paths under a specified path.

Source

pub fn exists(&self, path: &str) -> bool

Check if a path exists.

Source

pub fn node_count(&self) -> usize

Get the number of nodes in the tree.

Source

pub fn stats(&self) -> HashMap<String, String>

Get tree statistics.

Source

pub fn validate(&self) -> bool

Validate the tree structure.

Checks all structural invariants: parent-child consistency, path_map ↔ id_to_path bidirectionality, and tensor network integrity.

Source

pub fn tensor_network(&self) -> &HyperbolicTensorNetwork

Get the underlying tensor network (for spatial queries).

Source

pub fn path_for_id(&self, unique_id: &str) -> Option<String>

Resolve a unique_id to a path.

Source

pub fn position(&self, path: &str) -> IntegrationResult<HyperbolicPoint>

The hyperbolic (Poincaré) position of a stored node.

Errors with NotFound for unknown paths and OperationFailed for data-only nodes, which have no geometric embedding.

Source

pub fn path_ops(&self) -> &dyn PathOperations

Get the path operations.

Source

pub fn nearest_neighbor_point( &self, query: &HyperbolicPoint, ) -> IntegrationResult<(String, FixedPoint)>

Find the nearest stored node to an arbitrary Poincaré disk point.

Answered exactly by the cell index. Returns (path, hyperbolic_distance). Errors when the index holds nothing.

Source

pub fn nearest_neighbor_point_k( &self, query: &HyperbolicPoint, k: usize, ) -> IntegrationResult<Vec<(String, FixedPoint)>>

Find the k nearest stored nodes to an arbitrary Poincaré disk point.

Returns (path, hyperbolic_distance) sorted by ascending distance.

k == 0 is a request for nothing and is answered with nothing — the same as Self::find_nearest. Only an index that holds no nodes is an error. Conflating the two used to make nearest_k(q, 0) report “no nodes in tree” against a fully populated store, which is simply untrue.

Source

pub fn find_nearest( &self, path: &str, k: usize, ) -> IntegrationResult<Vec<(String, FixedPoint)>>

Find the k nearest stored nodes to the given path’s position in hyperbolic space. Returns paths sorted by ascending hyperbolic distance.

Source

pub fn nearest_semantic( &self, query_coords: &[u8], k: usize, dim_range: &Range<usize>, ) -> IntegrationResult<Vec<(String, FixedPoint)>>

Find the k nearest nodes by Euclidean distance across a dimensional slice of the semantic coordinate space.

query_coords: raw Q64.64 bytes representing the query point. k: number of results. dim_range: which dimensions to compare (e.g., 16..33 for category axes).

Returns (path, distance) sorted by distance ascending.

Source

pub fn neighbors_semantic( &self, path: &str, k: usize, dim_range: &Range<usize>, ) -> IntegrationResult<Vec<(String, FixedPoint)>>

Find the k nearest nodes to an existing node by semantic dimensional distance.

Convenience wrapper: reads the node’s semantic coordinates, then calls nearest_semantic. The queried node is excluded from results.

Source

pub fn find_in_radius( &self, path: &str, radius: FixedPoint, ) -> IntegrationResult<Vec<(String, FixedPoint)>>

Find all stored nodes within hyperbolic radius of the given path. Returns paths and their distances.

Trait Implementations§

Source§

impl Debug for HyperbolicTreeTensor

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.