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 cosine similarities for vector pairs in input order.
94 /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for batch-dispatch behavior.
95 #[inline]
96 pub fn batch_cosine_similarity(pairs: &[(&[f32], &[f32])]) -> Vec<f32> {
97 simd::batch_cosine_similarity(pairs)
98 }
99
100 /// **Stable**: external consumers may depend on this; breaking changes require a SemVer bump.
101 ///
102 /// Computes dot products for vector pairs in input order.
103 /// See [`docs/design.md`](../docs/design.md#vector-utility-facade) for batch-dispatch behavior.
104 #[inline]
105 pub fn batch_dot_product(pairs: &[(&[f32], &[f32])]) -> Vec<f32> {
106 simd::batch_dot_product(pairs)
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_cosine_similarity_identical() {
116 let a = vec![1.0, 2.0, 3.0];
117 let b = vec![1.0, 2.0, 3.0];
118 let sim = utils::cosine_similarity(&a, &b);
119 assert!((sim - 1.0).abs() < 0.0001);
120 }
121
122 #[test]
123 fn test_cosine_similarity_orthogonal() {
124 let a = vec![1.0, 0.0];
125 let b = vec![0.0, 1.0];
126 let sim = utils::cosine_similarity(&a, &b);
127 assert!(sim.abs() < 0.0001);
128 }
129
130 #[test]
131 fn test_cosine_similarity_opposite() {
132 let a = vec![1.0, 0.0];
133 let b = vec![-1.0, 0.0];
134 let sim = utils::cosine_similarity(&a, &b);
135 assert!((sim + 1.0).abs() < 0.0001);
136 }
137
138 #[test]
139 fn test_normalize() {
140 let mut v = vec![3.0, 4.0];
141 utils::normalize(&mut v);
142 let magnitude: f32 = v.iter().map(|x| x * x).sum::<f32>().sqrt();
143 assert!((magnitude - 1.0).abs() < 0.0001);
144 }
145
146 #[test]
147 fn test_euclidean_distance() {
148 let a = vec![0.0, 0.0, 0.0];
149 let b = vec![1.0, 0.0, 0.0];
150 let dist = utils::euclidean_distance(&a, &b);
151 assert!((dist - 1.0).abs() < 0.0001);
152 }
153
154 #[test]
155 fn test_model_default() {
156 let model = EmbeddingModel::default();
157 assert_eq!(model.dimensions(), 384);
158 }
159}