Skip to main content

lattice_embed/
lib.rs

1//! # lattice-embed
2//!
3//! Pure-Rust local embedding generation, caching, SIMD vector operations, and model migration.
4//! Most of the crate, including model loading and SIMD dispatch, is **Unstable**; consumers
5//! should normally use it through `lattice-engine`.
6//!
7//! The exception is the stable 0.4.x ANN contract in `simd`: squared/ordinary L2 distance,
8//! dot product, and cosine similarity retain their `(&[f32], &[f32]) -> f32` APIs and
9//! documented degenerate-input behavior. SIMD is not bit-identical to scalar, so near-tie
10//! ordering is not guaranteed.
11//!
12//! See `docs/design.md` for the architecture, service lifecycle, cache identity, and migration
13//! boundaries; use `docs/INDEX.md` to find subsystem references.
14
15#![warn(missing_docs)]
16#![allow(clippy::clone_on_copy)]
17
18pub mod backfill;
19mod cache;
20mod error;
21pub mod migration;
22mod model;
23pub mod service;
24pub mod simd;
25pub mod types;
26#[cfg(feature = "native")]
27pub mod vision;
28// Keep this gate aligned with wasm-bindgen's wasm32-only dependency — see docs/design.md.
29#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
30pub mod wasm;
31
32pub use cache::{CacheStats, DEFAULT_CACHE_CAPACITY, EmbeddingCache, ShardStats};
33pub use error::{EmbedError, Result};
34pub use model::{EmbeddingModel, MIN_MRL_OUTPUT_DIM, ModelConfig, ModelProvenance};
35#[allow(deprecated)]
36pub use service::MAX_TEXT_CHARS;
37pub use service::{DEFAULT_MAX_BATCH_SIZE, EmbeddingRole, EmbeddingService, MAX_TEXT_BYTES};
38pub use simd::{SimdConfig, simd_config};
39
40#[cfg(feature = "native")]
41pub use service::{CachedEmbeddingService, NativeEmbeddingService};
42
43/// Utility functions for vector operations.
44///
45/// All functions in this module are SIMD-accelerated when available (AVX2 on x86_64, NEON on aarch64).
46/// Runtime feature detection ensures automatic fallback to scalar implementations
47/// on systems without SIMD support.
48pub mod utils {
49    use crate::simd;
50
51    /// **Stable**: external consumers may depend on this; breaking changes require a SemVer bump.
52    ///
53    /// Computes cosine similarity through the SIMD dispatcher.
54    /// Returns `0.0` for empty, unequal-length, or zero-norm vectors.
55    /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for dispatch and performance details.
56    #[inline]
57    pub fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
58        simd::cosine_similarity(a, b)
59    }
60
61    /// **Stable**: external consumers may depend on this; breaking changes require a SemVer bump.
62    ///
63    /// Computes the dot product of two vectors through the SIMD dispatcher.
64    /// Returns `0.0` for unequal-length vectors; for unit vectors it equals cosine similarity.
65    /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for dispatch and performance details.
66    #[inline]
67    pub fn dot_product(a: &[f32], b: &[f32]) -> f32 {
68        simd::dot_product(a, b)
69    }
70
71    /// **Stable**: external consumers may depend on this; breaking changes require a SemVer bump.
72    ///
73    /// L2-normalizes a vector in place through the SIMD dispatcher.
74    /// Leaves zero- or NaN-norm vectors unchanged.
75    /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for dispatch and examples.
76    #[inline]
77    pub fn normalize(vector: &mut [f32]) {
78        simd::normalize(vector)
79    }
80
81    /// **Stable**: external consumers may depend on this; breaking changes require a SemVer bump.
82    ///
83    /// Computes Euclidean distance between two vectors through the SIMD dispatcher.
84    /// Returns `f32::MAX` for unequal-length vectors.
85    /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for dispatch and examples.
86    #[inline]
87    pub fn euclidean_distance(a: &[f32], b: &[f32]) -> f32 {
88        simd::euclidean_distance(a, b)
89    }
90
91    /// **Stable**: external consumers may depend on this; breaking changes require a SemVer bump.
92    ///
93    /// Computes Manhattan (L1) distance between two vectors through the SIMD dispatcher.
94    /// Returns `f32::MAX` for unequal-length vectors, matching [`euclidean_distance`].
95    /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for dispatch and examples.
96    #[inline]
97    pub fn manhattan_distance(a: &[f32], b: &[f32]) -> f32 {
98        simd::manhattan_distance(a, b)
99    }
100
101    /// **Stable**: external consumers may depend on this; breaking changes require a SemVer bump.
102    ///
103    /// Computes cosine similarities for vector pairs in input order.
104    /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for batch-dispatch behavior.
105    #[inline]
106    pub fn batch_cosine_similarity(pairs: &[(&[f32], &[f32])]) -> Vec<f32> {
107        simd::batch_cosine_similarity(pairs)
108    }
109
110    /// **Stable**: external consumers may depend on this; breaking changes require a SemVer bump.
111    ///
112    /// Computes dot products for vector pairs in input order.
113    /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for batch-dispatch behavior.
114    #[inline]
115    pub fn batch_dot_product(pairs: &[(&[f32], &[f32])]) -> Vec<f32> {
116        simd::batch_dot_product(pairs)
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_cosine_similarity_identical() {
126        let a = vec![1.0, 2.0, 3.0];
127        let b = vec![1.0, 2.0, 3.0];
128        let sim = utils::cosine_similarity(&a, &b);
129        assert!((sim - 1.0).abs() < 0.0001);
130    }
131
132    #[test]
133    fn test_cosine_similarity_orthogonal() {
134        let a = vec![1.0, 0.0];
135        let b = vec![0.0, 1.0];
136        let sim = utils::cosine_similarity(&a, &b);
137        assert!(sim.abs() < 0.0001);
138    }
139
140    #[test]
141    fn test_cosine_similarity_opposite() {
142        let a = vec![1.0, 0.0];
143        let b = vec![-1.0, 0.0];
144        let sim = utils::cosine_similarity(&a, &b);
145        assert!((sim + 1.0).abs() < 0.0001);
146    }
147
148    #[test]
149    fn test_normalize() {
150        let mut v = vec![3.0, 4.0];
151        utils::normalize(&mut v);
152        let magnitude: f32 = v.iter().map(|x| x * x).sum::<f32>().sqrt();
153        assert!((magnitude - 1.0).abs() < 0.0001);
154    }
155
156    #[test]
157    fn test_euclidean_distance() {
158        let a = vec![0.0, 0.0, 0.0];
159        let b = vec![1.0, 0.0, 0.0];
160        let dist = utils::euclidean_distance(&a, &b);
161        assert!((dist - 1.0).abs() < 0.0001);
162    }
163
164    #[test]
165    fn test_model_default() {
166        let model = EmbeddingModel::default();
167        assert_eq!(model.dimensions(), 384);
168    }
169}