1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! Time series distance metrics and indexing.
//!
//! This module provides implementations for time series similarity measures,
//! particularly the Move-Split-Merge (MSM) metric, along with indexing structures
//! for efficient similarity search.
//!
//! # Move-Split-Merge (MSM) Metric
//!
//! The MSM metric, introduced by Stefan et al., is a metric for comparing time series
//! that is robust to time shifts and scaling. It defines three operations:
//!
//! - **Move**: Change a value by some amount. Cost = |change|
//! - **Split**: Duplicate a value into two consecutive identical elements. Cost = c (constant)
//! - **Merge**: Combine two consecutive equal-value elements into one. Cost = c (constant)
//!
//! ## Example
//!
//! ```rust
//! use liblevenshtein::time_series::MsmConfig;
//!
//! let config = MsmConfig::new(1.0); // c = 1.0
//! let x = vec![1.0, 2.0, 3.0, 2.0];
//! let y = vec![1.0, 2.5, 2.0];
//!
//! let distance = config.distance(&x, &y);
//! println!("MSM distance: {}", distance);
//! ```
//!
//! # MSM Automaton
//!
//! In addition to the standard DP algorithm, this module provides an automaton-based
//! implementation of MSM. The automaton approach enables:
//!
//! - Early termination when cost exceeds threshold
//! - Future integration with trie-based time series indexing
//! - Alternative computational model for research purposes
//!
//! ## Automaton Example
//!
//! ```rust
//! use liblevenshtein::time_series::{MsmConfig, msm_distance_wavefront};
//!
//! let config = MsmConfig::new(1.0);
//! let x = vec![1.0, 2.0, 3.0];
//! let y = vec![1.5, 2.5, 3.5];
//!
//! // With threshold (returns None if distance exceeds threshold)
//! let distance = msm_distance_wavefront(&x, &y, &config, 2.0);
//! assert!(distance.is_some());
//! ```
//!
//! # Time Series Indexing
//!
//! The module provides trie-based indexing for efficient similarity search:
//!
//! - **Quantization**: Encode continuous values as discrete bins
//! - **Trie storage**: Efficient prefix-sharing using DynamicDawg
//! - **Hybrid search**: Approximate filtering + exact MSM verification
//!
//! ## Indexing Example
//!
//! ```rust
//! use liblevenshtein::time_series::{
//! TimeSeriesIndex, HybridSearchIndex, QuantizationConfig, MsmConfig,
//! };
//!
//! // Simple quantized index
//! let config = QuantizationConfig::for_u8(0.0, 100.0);
//! let mut index = TimeSeriesIndex::from_series(config, &[
//! vec![10.0, 20.0, 30.0],
//! vec![15.0, 25.0, 35.0],
//! ]);
//!
//! // Approximate search
//! let results = index.search(&[12.0, 22.0, 32.0], 3);
//!
//! // Hybrid search with exact MSM verification
//! let quant_config = QuantizationConfig::for_u8(0.0, 100.0);
//! let msm_config = MsmConfig::new(1.0);
//! let mut hybrid = HybridSearchIndex::new(quant_config, msm_config);
//! hybrid.insert(0usize, &[10.0, 20.0, 30.0]);
//! let exact_results = hybrid.search_exact(&[12.0, 22.0, 32.0], 10.0);
//! ```
//!
//! # Encoding Options
//!
//! | Encoding | Precision | Use Case |
//! |----------|-----------|----------|
//! | Quantization (u8) | 256 levels | Fast approximate search |
//! | Quantization (u16) | 65K levels | Higher precision |
//! | Direct float bits | Exact | Exact matching |
//! | Delta encoding | Variable | Bounded local variation |
//! | SAX | Symbolic | Time series motifs |
//!
//! # Lower-Bound and Heuristic Pruning
//!
//! For efficient search over large databases, a proved lower bound can prune
//! candidates without computing the expensive full MSM distance. Prefix
//! Euclidean, L1, and Combined scores are also exported, but they are heuristics
//! for MSM: split/merge paths can be cheaper than pointwise prefix matching.
//!
//! ```rust
//! use liblevenshtein::time_series::{
//! MsmConfig, length_lb, euclidean_lb,
//! };
//!
//! let x = vec![1.0, 2.0, 3.0, 4.0];
//! let y = vec![1.5, 2.5, 3.5, 4.5];
//! let c = 1.0;
//!
//! // Correctness-preserving lower bound.
//! let lb_length = length_lb(&x, &y, c);
//!
//! // If the proved lower bound exceeds the threshold, skip exact MSM.
//! let threshold = 2.0;
//! if lb_length > threshold {
//! println!("Pruned: LB {} > threshold {}", lb_length, threshold);
//! } else {
//! let msm = MsmConfig::new(c).distance(&x, &y);
//! println!("MSM distance: {}", msm);
//! }
//!
//! // Heuristic scores can be useful for approximate workflows.
//! let _heuristic = euclidean_lb(&x, &y);
//! ```
//!
//! # References
//!
//! - Stefan, Alexandra, et al. "The move-split-merge metric for time series."
//! IEEE transactions on Knowledge and Data Engineering 25.6 (2012): 1425-1438.
// MSM metric exports
pub use ;
pub use ;
pub use MsmState;
pub use ;
// Encoding exports
pub use QuantizationConfig;
pub use ;
// Indexing exports
pub use ;
pub use MsmTransducer;
pub use ;
// Lower bound exports
pub use search_with_lb_parallel;
pub use ;