Skip to main content

HyperbolicTensorNetwork

Struct HyperbolicTensorNetwork 

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

Hyperbolic Tensor Network for tree data representation.

Embeds hierarchical data into the Poincaré disk model using Sarkar’s cone-based construction. Each node occupies a point in hyperbolic space, with children placed at hyperbolic distance τ from their parent using Möbius reflections to preserve the tree structure as a Delaunay graph.

Internal maps use DashMap for lock-free concurrent reads, preparing for multi-threaded access in later phases.

Implementations§

Source§

impl HyperbolicTensorNetwork

Source

pub fn new(dimension: usize, tau: FixedPoint) -> Self

Create a new hyperbolic tensor network with the given Sarkar scale factor τ.

Source

pub fn add_node_data_only( &self, metadata: NodeMetadata, value: Vec<u8>, _level: u32, ) -> String

Add a node to the DashMap without computing geometric embedding.

Creates a key-derived unique_id for path_map/id_to_path lookups. Semantic queries (nearest_semantic, neighbors_semantic, get/set) work normally. Spatial queries (nearest, neighbors) will not find this node until it is embedded.

Source

pub fn add_node( &self, metadata: NodeMetadata, value: Vec<u8>, parent_signature: Option<&GeometricSignature>, level: u32, ) -> Option<GeometricSignature>

Add a node to the tensor network.

Computes a position in the Poincaré disk using Sarkar’s cone construction: children are placed at hyperbolic distance τ from their parent, at golden-angle-spaced angles in the parent’s reflected frame.

Source

pub fn add_node_positioned( &self, metadata: NodeMetadata, value: Vec<u8>, parent_signature: Option<&GeometricSignature>, level: u32, child_index: u32, ) -> Option<GeometricSignature>

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

Used during snapshot replay: the stored child_index ensures the node gets the same geometric position regardless of replay order.

Source

pub fn max_degree(&self) -> u32

The largest node degree for which PROOF.md’s Delaunay hypothesis holds at this network’s tau. Exceeding it is a spacing-quality matter, not a correctness one — see docs/GEOMETRY_TRACK.md.

Source

pub fn get_node_by_signature( &self, signature: &GeometricSignature, ) -> Option<CompressedNode>

Get a node by its signature (returns cloned value).

Source

pub fn update_node_value(&self, unique_id: &str, value: Vec<u8>) -> bool

Update the value of a node by its unique_id.

Source

pub fn set_node_metadata_entry( &self, unique_id: &str, key: &str, val: &str, ) -> bool

Set a metadata key-value pair on a node by its unique_id.

Source

pub fn set_node_semantic(&self, unique_id: &str, coords: Vec<u8>) -> bool

Set semantic coordinates on a node by its unique_id.

Source

pub fn get_node_semantic(&self, unique_id: &str) -> Option<Vec<u8>>

Get semantic coordinates for a node by its unique_id.

Source

pub fn root_node(&self) -> Option<CompressedNode>

Get the root node (cloned).

Source

pub fn root_signature(&self) -> Option<GeometricSignature>

Get the root node signature (cloned).

Source

pub fn children_of(&self, signature: &GeometricSignature) -> Vec<CompressedNode>

Get the children of a node by its signature (cloned).

Source

pub fn get_point(&self, unique_id: &str) -> Option<HyperbolicPoint>

Get the hyperbolic point for a node (cloned).

Source

pub fn semantic_epoch(&self) -> u64

Monotone counter of semantic-relevant mutations (coordinate writes, inserts, deletes). External caches — like the semantic disk’s derived-position index — use it exactly as the internal per-slice cache does: tag on build, rebuild when it has advanced.

Source

pub fn tau(&self) -> FixedPoint

The Sarkar scale factor: the hyperbolic distance from any node to each of its children.

Source

pub fn cell_index(&self) -> &CellIndex

The spatial index, for tests that compare it against brute force.

Source

pub fn node_count(&self) -> usize

Get the number of nodes in the network.

Source

pub fn remove_detached_node(&self, unique_id: &str)

Remove a node-map entry that has NO geometric registration — the data-only entry retired by embed_existing after its embedded replacement went live under a new signature-derived id. Not for embedded nodes: those need Self::unregister_node_with_parent.

Source

pub fn unregister_node(&self, unique_id: &str)

Unregister a node from the spatial index (for deletion).

Prefer Self::unregister_node_with_parent: the parent is not derivable here, so the parent’s child list keeps a dangling entry.

Source

pub fn unregister_node_with_parent( &self, unique_id: &str, parent_uid: Option<&str>, )

Unregister a node, removing it from the node map and from its parent’s child list. The caller supplies parent_uid; it is resolved from the path map, which is authoritative for parentage.

Source

pub fn find_descendants_spatial( &self, signature: &GeometricSignature, ) -> Vec<(String, FixedPoint)>

Find all descendants of a node using the spatial index.

Uses the parent’s stored point + a τ-based radius to find all nodes within the Sarkar cone. Radius = 3·τ covers ~3 levels of descendants.

Source

pub fn nearest_neighbor_point( &self, query_poincare: &HyperbolicPoint, ) -> Option<(String, FixedPoint)>

The nearest stored node to an arbitrary point, exactly.

Delegates to the cell index: the cell is computed from the query’s coordinates, and the ring expands until a proven lower bound says nothing closer remains. No candidate cap, no window, no count-based stopping rule.

Complexity: O(1) cell lookup plus a bounded ring. Measured on 5 461 nodes: 1.7 cells and ~27 points scanned per k=1 query, against 7 563 µs for the bucket layer this replaced.

Source

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

The k nearest stored nodes to an arbitrary point, ascending by (distance, unique_id).

Source

pub fn nodes_in_radius( &self, centre: &HyperbolicPoint, radius: FixedPoint, ) -> Vec<(String, FixedPoint)>

Every stored node within radius of centre, ascending by (distance, unique_id). Same expansion as nearest_neighbor_point_k with a fixed threshold instead of a moving k-th distance.

Source

pub fn semantic_distance( coords_a: &[u8], coords_b: &[u8], dim_range: &Range<usize>, ) -> FixedPoint

Compute Euclidean distance between two semantic coordinate vectors across a dimensional slice (specified dimension range).

Each dimension is 16 bytes (i128 LE, Q64.64 fixed-point). Dimensions outside the vectors are treated as zero.

Uses gMath’s fused kernel: differences, squares, and the accumulator all live at the compute tier, so the sum cannot wrap the way a storage-tier Q64.64 accumulator would for large coordinates or many dimensions.

Source

pub fn decode_semantic_slice( coords: &[u8], dim_range: &Range<usize>, ) -> Vec<FixedPoint>

Decode a dimension slice of a raw Q64.64 coordinate vector.

Dimensions beyond the end of coords decode as zero — short vectors are zero-extended, matching Self::semantic_distance semantics.

Source

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

Find the k nearest nodes by Euclidean distance in semantic dimension space.

query_coords: raw Q64.64 byte vector representing the query point. k: number of nearest neighbors to return. dim_range: which semantic dimensions to compare (the “dimensional slice”).

Returns Vec<(key, distance)> sorted ascending by (distance, key) — ties break deterministically by the user-visible node key, both for ordering and for which ties survive the k-boundary.

Routing (docs/SEMANTIC_INDEX.md): stores below constants::SEMANTIC_INDEX_MIN_NODES use the brute-force scan; larger stores query a lazily built per-dim_range VP-tree, rebuilt when the semantic epoch has advanced (any coord write, insert, or delete). Warm-index queries are O(log n) expected on low-dimensional slices; the first query for a slice after a mutation pays the O(n log n) build. Results are identical to the scan path.

Source

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

Reference brute-force path for Self::nearest_semantic: O(n × d) scan over every node with semantic coordinates.

Same ordering contract as the indexed path — ascending (distance, key). Public so tests and benchmarks can compare the two paths directly; prefer nearest_semantic, which picks.

Source

pub fn validate_network(&self) -> bool

Check if the network has a valid structure.

Verifies structural invariants across all internal data structures: nodes, point_map, child_counts, and the spatial index.

Source

pub fn verify_index_locates_all_nodes(&self) -> bool

Functional integrity: can the spatial index actually answer a query about what it holds?

Every other check in this file is referential — it asks whether these maps point at things that exist. A structure can pass all of them and still be unable to find anything, which is exactly what happened: the bucket layer was referentially perfect while nearest returned the wrong node for 25 of 42 nodes in a deep tree. No check asked it to locate a node it had itself indexed.

This one does. point_map is the authority on where a node is; the index is derived from it. Querying at a node’s own stored position must return that node, because distance 0 is the global minimum of a metric — an expected answer known without any oracle.

Ties are respected: several nodes may share a position, so the check is that something at distance zero comes back, not that a particular id does.

O(n) queries, so it is a diagnostic rather than a hot path.

Trait Implementations§

Source§

impl Debug for HyperbolicTensorNetwork

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.