pgm_extra/index/
builder.rs

1use crate::error::Error;
2use crate::index::external;
3use crate::index::key::Indexable;
4#[cfg(feature = "std")]
5use crate::index::owned;
6
7/// Builder for constructing PGM indices with custom parameters.
8///
9/// # Example
10///
11/// ```
12/// use pgm_extra::index::Builder;
13///
14/// let data: Vec<u64> = (0..10000).collect();
15///
16/// let index = Builder::new()
17///     .epsilon(128)
18///     .epsilon_recursive(8)
19///     .build(&data)
20///     .unwrap();
21///
22/// assert_eq!(index.epsilon(), 128);
23/// ```
24#[derive(Clone, Debug)]
25pub struct Builder {
26    epsilon: usize,
27    epsilon_recursive: usize,
28    #[cfg(feature = "parallel")]
29    parallel: bool,
30}
31
32impl Default for Builder {
33    fn default() -> Self {
34        Self {
35            epsilon: 64,
36            epsilon_recursive: 4,
37            #[cfg(feature = "parallel")]
38            parallel: false,
39        }
40    }
41}
42
43impl Builder {
44    pub fn new() -> Self {
45        Self::default()
46    }
47
48    /// Set the epsilon (error bound) for the bottom level.
49    pub fn epsilon(mut self, epsilon: usize) -> Self {
50        self.epsilon = epsilon.max(1);
51        self
52    }
53
54    /// Set the epsilon (error bound) for the upper levels.
55    pub fn epsilon_recursive(mut self, epsilon_recursive: usize) -> Self {
56        self.epsilon_recursive = epsilon_recursive;
57        self
58    }
59
60    #[cfg(feature = "parallel")]
61    pub fn parallel(mut self, parallel: bool) -> Self {
62        self.parallel = parallel;
63        self
64    }
65
66    pub fn build<T: Indexable>(&self, data: &[T]) -> Result<external::Static<T>, Error>
67    where
68        T::Key: Ord,
69    {
70        #[cfg(feature = "parallel")]
71        {
72            if self.parallel {
73                return external::Static::new_parallel(data, self.epsilon, self.epsilon_recursive);
74            }
75        }
76
77        external::Static::new(data, self.epsilon, self.epsilon_recursive)
78    }
79
80    pub fn build_one_level<T: Indexable>(&self, data: &[T]) -> Result<external::OneLevel<T>, Error>
81    where
82        T::Key: Ord,
83    {
84        external::OneLevel::new(data, self.epsilon)
85    }
86
87    #[cfg(feature = "std")]
88    pub fn build_dynamic<T: Indexable + Ord + Copy>(
89        &self,
90        data: Vec<T>,
91    ) -> Result<owned::Dynamic<T>, Error>
92    where
93        T::Key: Ord,
94    {
95        owned::Dynamic::from_sorted(data, self.epsilon, self.epsilon_recursive)
96    }
97
98    #[cfg(feature = "std")]
99    pub fn build_dynamic_empty<T: Indexable + Ord + Copy>(&self) -> owned::Dynamic<T>
100    where
101        T::Key: Ord,
102    {
103        owned::Dynamic::new(self.epsilon, self.epsilon_recursive)
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110    use alloc::vec::Vec;
111
112    #[test]
113    fn test_builder_default() {
114        let builder = Builder::new();
115        let data: Vec<u64> = (0..1000).collect();
116        let index = builder.build(&data).unwrap();
117
118        assert_eq!(index.epsilon(), 64);
119    }
120
121    #[test]
122    fn test_builder_custom_epsilon() {
123        let builder = Builder::new().epsilon(128).epsilon_recursive(8);
124        let data: Vec<u64> = (0..1000).collect();
125        let index = builder.build(&data).unwrap();
126
127        assert_eq!(index.epsilon(), 128);
128        assert_eq!(index.epsilon_recursive(), 8);
129    }
130
131    #[test]
132    fn test_builder_one_level() {
133        let builder = Builder::new().epsilon(32);
134        let data: Vec<u64> = (0..1000).collect();
135        let index = builder.build_one_level(&data).unwrap();
136
137        assert_eq!(index.epsilon(), 32);
138    }
139
140    #[cfg(feature = "std")]
141    #[test]
142    fn test_builder_dynamic() {
143        let builder = Builder::new();
144        let data: Vec<u64> = (0..100).collect();
145        let index = builder.build_dynamic(data).unwrap();
146
147        assert_eq!(index.len(), 100);
148    }
149}