pub struct EntangledHVec { /* private fields */ }Expand description
Entangled Sparse Hypervector.
Instead of a dense bitvec (~50% active), stores only sorted active indices.
Sparsity rho = 1/256 means ~D/256 active bits out of D total.
Indices are grouped into NUM_ENTANGLEMENTS entanglement groups,
each generated from a seeded hash.
Benefits:
- 256x less memory per vector at D=16384
- Hamming via sorted merge (O(k) where k = active count)
Implementations§
Source§impl EntangledHVec
impl EntangledHVec
Sourcepub fn new_deterministic(dim: usize, seed: u64) -> Self
pub fn new_deterministic(dim: usize, seed: u64) -> Self
Create a random entangled sparse hypervector.
Uses entanglement groups when dim is large enough, otherwise direct hash generation.
After dedup, if birthday collisions reduced the count below active_count,
deterministic backfill slots are generated until the exact count is reached.
pub fn new_with_density(dim: usize, density_denom: usize, seed: u64) -> Self
Sourcepub fn from_indices(indices: Vec<u32>, dim: usize) -> Self
pub fn from_indices(indices: Vec<u32>, dim: usize) -> Self
Create directly from a set of active indices.
Indices must be sorted, deduplicated, and within [0, dim).
Sourcepub fn from_dense(dense: &[f32], target_dim: usize) -> Self
pub fn from_dense(dense: &[f32], target_dim: usize) -> Self
Create from a dense float vector via sparse ternary sketching. Selects top rho*dim indices by Achlioptas ternary projection magnitude.
Sourcepub fn from_scalar(
value: f64,
min_val: f64,
max_val: f64,
target_dim: usize,
) -> Self
pub fn from_scalar( value: f64, min_val: f64, max_val: f64, target_dim: usize, ) -> Self
Encode a scalar into a sparse hypervector via permuted sliding window.
The normalized value selects a contiguous window of active_count
logical slots in [0, target_dim - active_count]. Each logical slot
is then scattered across the index space by multiplying with a prime
constant modulo target_dim (golden-ratio permutation). This gives:
- Nearby values share most window slots → high Jaccard
- Distant values share few slots → low Jaccard
- Monotonic: similarity decreases with scalar distance
Sourcepub fn to_deltas(&self) -> Vec<u32>
pub fn to_deltas(&self) -> Vec<u32>
Convert sorted indices to deltas (gaps between consecutive indices). First element is the absolute value.
Sourcepub fn from_deltas(deltas: &[u32], dim: usize) -> Self
pub fn from_deltas(deltas: &[u32], dim: usize) -> Self
Restore absolute indices from deltas.
Sourcepub fn hamming(&self, other: &Self) -> u32
pub fn hamming(&self, other: &Self) -> u32
Hamming distance via sorted-merge intersection count on sparse index sets.
Sourcepub fn similarity(&self, other: &Self) -> f64
pub fn similarity(&self, other: &Self) -> f64
Jaccard similarity: |A∩B| / |A∪B|. Proper metric for sparse index sets (ρ=1/256). The old 1−hamming/dim collapsed to ~0.992 for all sparse pairs.
Sourcepub fn bind(&self, other: &Self) -> Self
pub fn bind(&self, other: &Self) -> Self
Entangled bind: symmetric XOR of index sets. For sparse vectors, XOR of active sets = symmetric difference.
Sourcepub fn permute(&self, shifts: usize) -> Self
pub fn permute(&self, shifts: usize) -> Self
Permute by shifting all indices by shifts modulo dim.
Sourcepub fn hash_permute(&self, seed: u64) -> Self
pub fn hash_permute(&self, seed: u64) -> Self
Nonlinear index permutation via keyed hash.
Maps each active index through hash(idx, seed) % dim, producing a completely scrambled view. Unlike circular shift (permute), this destroys spatial correlation between indices, making containment values independent across different seeds.
Nearly density-preserving: hash collisions reduce count by ~0.1% at density 1/256.
Sourcepub fn bundle<V: Borrow<Self>>(vectors: &[V]) -> Self
pub fn bundle<V: Borrow<Self>>(vectors: &[V]) -> Self
Bundle multiple sparse vectors with threshold at rho. Counts per-index frequency, keeps only those above threshold.
Sourcepub fn bundle_bloom<V: Borrow<Self>>(vectors: &[V]) -> Self
pub fn bundle_bloom<V: Borrow<Self>>(vectors: &[V]) -> Self
Bloom-filter bundling: set UNION of all input vectors.
Instead of majority vote (which fails at K≥3 for sparse vectors with
density 1/256), takes the union of all active indices. The bundle grows
denser with more items. Use containment_similarity to query.
Validated by HyperCam (arxiv 2501.10547): Bloom filter bundling achieves 2 orders of magnitude reduction in encoding operations for sparse HDC.
Sourcepub fn containment_similarity(&self, other: &Self) -> f64
pub fn containment_similarity(&self, other: &Self) -> f64
Containment similarity: |A∩B| / |A|.
Measures what fraction of self’s active indices appear in other.
The correct metric for Bloom-filter bundles: if A was bundled into B,
containment(A, B) ≈ 1.0 regardless of how many other items are in B.
Sourcepub fn corrected_containment(&self, bloom_bundle: &Self) -> f64
pub fn corrected_containment(&self, bloom_bundle: &Self) -> f64
Density-corrected containment: (raw - density) / (1 - density).
Subtracts the expected noise floor (bundle density) and normalizes. Members: raw=1.0, corrected=1.0. Non-members: raw≈density, corrected≈0. This is the correct metric for large Bloom bundles where raw containment has a high floor due to bundle density.
Sourcepub fn bind_ordered(&self, other: &Self) -> Self
pub fn bind_ordered(&self, other: &Self) -> Self
Non-commutative binding: permute(self, 1) XOR other.
Captures order: bind_ordered(A, B) ≠ bind_ordered(B, A). ~2x cost of plain XOR (one permute + one XOR). Inverse: unbind B first (XOR), then inverse-permute to recover A.
Sourcepub fn unbind_ordered_left(&self, other: &Self) -> Self
pub fn unbind_ordered_left(&self, other: &Self) -> Self
Inverse of bind_ordered: given C = bind_ordered(A, B), recover A. A = permute_inv(C XOR B, 1)
Trait Implementations§
Source§impl Clone for EntangledHVec
impl Clone for EntangledHVec
Source§fn clone(&self) -> EntangledHVec
fn clone(&self) -> EntangledHVec
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for EntangledHVec
impl Debug for EntangledHVec
Source§impl<'de> Deserialize<'de> for EntangledHVec
impl<'de> Deserialize<'de> for EntangledHVec
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for EntangledHVec
impl RefUnwindSafe for EntangledHVec
impl Send for EntangledHVec
impl Sync for EntangledHVec
impl Unpin for EntangledHVec
impl UnsafeUnpin for EntangledHVec
impl UnwindSafe for EntangledHVec
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.