Skip to main content

trit_vsa/
lib.rs

1//! Balanced ternary arithmetic library with bitsliced storage and VSA operations.
2//!
3//! This crate provides efficient representations and operations for balanced ternary
4//! values {-1, 0, +1}. It supports both dense (bitsliced) and sparse storage formats,
5//! along with Vector Symbolic Architecture (VSA) operations for hyperdimensional computing.
6//!
7//! # Features
8//!
9//! - **Core Types**: `Trit`, `Tryte3` (3 trits), `Word6` (6 trits)
10//! - **Vector Storage**: `PackedTritVec` (bitsliced), `SparseVec` (COO format)
11//! - **VSA Operations**: Bundle (majority), Bind (XOR-like), Similarity
12//! - **SIMD**: Optional AVX2/NEON acceleration with the `simd` feature
13//!
14//! # Quick Start
15//!
16//! ```rust
17//! use trit_vsa::{Trit, PackedTritVec, vsa};
18//!
19//! // Create a ternary vector
20//! let mut vec = PackedTritVec::new(1000);
21//! vec.set(0, Trit::P);   // +1
22//! vec.set(1, Trit::N);   // -1
23//! vec.set(2, Trit::Z);   // 0
24//!
25//! // Compute dot product
26//! let other = PackedTritVec::new(1000);
27//! let dot = vec.dot(&other);
28//!
29//! // VSA operations
30//! let bundled = vsa::bundle(&vec, &other);
31//! let similarity = vsa::cosine_similarity(&vec, &other);
32//! ```
33//!
34//! # Representation
35//!
36//! Ternary values are stored using a bitsliced representation with two planes:
37//!
38//! ```text
39//! Value | +plane | -plane
40//! ------+--------+-------
41//!   +1  |   1    |   0
42//!    0  |   0    |   0
43//!   -1  |   0    |   1
44//! ```
45//!
46//! This enables efficient popcount-based operations like dot products.
47//!
48//! # Feature Flags
49//!
50//! - `default`: No additional features
51//! - `simd`: Enable AVX2/NEON SIMD optimizations
52//! - `cuda`: Enable GPU acceleration via CubeCL
53
54#![warn(missing_docs)]
55#![warn(clippy::pedantic)]
56#![allow(clippy::module_name_repetitions)]
57#![allow(clippy::cast_possible_truncation)]
58#![allow(clippy::cast_possible_wrap)]
59#![allow(clippy::cast_sign_loss)]
60#![allow(clippy::cast_lossless)] // We use explicit casts for clarity
61
62pub mod arithmetic;
63pub mod dispatch;
64mod error;
65pub mod kernels;
66mod packed;
67pub mod simd;
68mod sparse;
69mod trit;
70mod tryte;
71pub mod vsa;
72mod word;
73
74#[cfg(feature = "cuda")]
75pub mod gpu;
76
77pub use dispatch::{DevicePreference, DispatchConfig, Format, Operation, TritVector};
78pub use error::{Result, TernaryError};
79pub use kernels::{
80    get_backend, get_backend_for_size, BackendConfig, BackendPreference, CpuBackend,
81    DynamicBackend, RandomConfig, TernaryBackend,
82};
83pub use packed::PackedTritVec;
84pub use sparse::SparseVec;
85pub use trit::Trit;
86pub use tryte::{Tryte3, TRYTE3_MAX, TRYTE3_MIN};
87pub use word::{Word6, WORD6_MAX, WORD6_MIN};
88
89#[cfg(feature = "cuda")]
90pub use gpu::{
91    warn_if_cpu, GpuBind, GpuBundle, GpuCosineSimilarity, GpuDispatchable, GpuDotSimilarity,
92    GpuError, GpuHammingDistance, GpuRandom, GpuResult, GpuUnbind, RandomInput,
93};
94
95#[cfg(feature = "cuda")]
96pub use kernels::CubeclBackend;
97
98/// Prelude module for convenient imports.
99///
100/// # Example
101///
102/// ```rust
103/// use trit_vsa::prelude::*;
104/// ```
105pub mod prelude {
106    pub use crate::arithmetic::{from_balanced_ternary, to_balanced_ternary};
107    pub use crate::kernels::{
108        get_backend, BackendConfig, BackendPreference, CpuBackend, TernaryBackend,
109    };
110    pub use crate::packed::PackedTritVec;
111    pub use crate::sparse::SparseVec;
112    pub use crate::trit::Trit;
113    pub use crate::tryte::Tryte3;
114    pub use crate::vsa::{bind, bundle, cosine_similarity, hamming_distance};
115    pub use crate::word::Word6;
116    pub use crate::{Result, TernaryError};
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_basic_workflow() {
125        // Create a ternary vector
126        let mut vec = PackedTritVec::new(100);
127
128        // Set some values
129        vec.set(0, Trit::P);
130        vec.set(1, Trit::N);
131        vec.set(50, Trit::P);
132
133        // Verify
134        assert_eq!(vec.get(0), Trit::P);
135        assert_eq!(vec.get(1), Trit::N);
136        assert_eq!(vec.get(2), Trit::Z);
137        assert_eq!(vec.count_nonzero(), 3);
138    }
139
140    #[test]
141    fn test_vsa_workflow() {
142        let mut a = PackedTritVec::new(64);
143        let mut b = PackedTritVec::new(64);
144
145        // Set up vectors
146        for i in 0..32 {
147            a.set(i, Trit::P);
148            b.set(i, Trit::P);
149        }
150
151        // Bundle should produce a similar vector
152        let bundled = vsa::bundle(&a, &b);
153        let sim = vsa::cosine_similarity(&a, &bundled);
154        assert!(sim > 0.9, "bundled vector should be similar to inputs");
155
156        // Bind should produce orthogonal vector
157        let bound = vsa::bind(&a, &b);
158        let recovered = vsa::unbind(&bound, &b);
159
160        // Recovered should match original
161        for i in 0..64 {
162            assert_eq!(recovered.get(i), a.get(i));
163        }
164    }
165
166    #[test]
167    fn test_sparse_workflow() {
168        let mut sparse = SparseVec::new(10000);
169        sparse.set(100, Trit::P);
170        sparse.set(5000, Trit::N);
171
172        assert_eq!(sparse.count_nonzero(), 2);
173        assert!(sparse.sparsity() > 0.99);
174
175        // Convert to packed for operations
176        let packed = sparse.to_packed();
177        assert_eq!(packed.get(100), Trit::P);
178        assert_eq!(packed.get(5000), Trit::N);
179    }
180
181    #[test]
182    fn test_tryte_arithmetic() {
183        let a = Tryte3::from_value(7).unwrap();
184        let b = Tryte3::from_value(5).unwrap();
185
186        let (sum, carry) = a + b;
187        let total = sum.value() + carry.value() as i32 * 27;
188        assert_eq!(total, 12);
189    }
190
191    #[test]
192    fn test_word_arithmetic() {
193        let a = Word6::from_value(100).unwrap();
194        let b = Word6::from_value(50).unwrap();
195
196        let (sum, carry) = a + b;
197        let total = sum.value() + carry.value() as i32 * 729;
198        assert_eq!(total, 150);
199    }
200}