1use crate::details::common::norm_sim_to_norm_dist;
2use crate::HashableChar;
3
4pub trait MetricUsize2 {
5 fn maximum(&self, len1: usize, len2: usize) -> usize;
6
7 fn _distance<Iter1, Iter2>(
8 &self,
9 s1: Iter1,
10 len1: usize,
11 s2: Iter2,
12 len2: usize,
13 score_cutoff: Option<usize>,
14 score_hint: Option<usize>,
15 ) -> Option<usize>
16 where
17 Iter1: DoubleEndedIterator + Clone,
18 Iter2: DoubleEndedIterator + Clone,
19 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
20 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
21 {
22 let maximum = self.maximum(len1, len2);
23
24 let cutoff_similarity = score_cutoff.map(|x| if maximum >= x { maximum - x } else { 0 });
25 let hint_similarity = score_hint.map(|x| if maximum >= x { maximum - x } else { 0 });
26
27 let sim = self._similarity(s1, len1, s2, len2, cutoff_similarity, hint_similarity)?;
28 let dist = maximum - sim;
29
30 if let Some(cutoff) = score_cutoff {
31 if dist > cutoff {
32 return None;
33 }
34 }
35 Some(dist)
36 }
37
38 fn _similarity<Iter1, Iter2>(
39 &self,
40 s1: Iter1,
41 len1: usize,
42 s2: Iter2,
43 len2: usize,
44 score_cutoff: Option<usize>,
45 mut score_hint: Option<usize>,
46 ) -> Option<usize>
47 where
48 Iter1: DoubleEndedIterator + Clone,
49 Iter2: DoubleEndedIterator + Clone,
50 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
51 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
52 {
53 let maximum = self.maximum(len1, len2);
54 if let Some(cutoff) = score_cutoff {
55 if maximum < cutoff {
56 return None;
57 }
58
59 if let Some(hint) = score_hint {
60 score_hint = Some(hint.min(cutoff));
61 }
62 }
63
64 let cutoff_distance = score_cutoff.map(|x| maximum - x);
65 let hint_distance = score_hint.map(|x| maximum - x);
66 let dist = self._distance(s1, len1, s2, len2, cutoff_distance, hint_distance)?;
67 let sim = maximum - dist;
68 if let Some(cutoff) = score_cutoff {
69 if sim < cutoff {
70 return None;
71 }
72 }
73 Some(sim)
74 }
75
76 fn _normalized_distance<Iter1, Iter2>(
77 &self,
78 s1: Iter1,
79 len1: usize,
80 s2: Iter2,
81 len2: usize,
82 mut score_cutoff: Option<f64>,
83 score_hint: Option<f64>,
84 ) -> Option<f64>
85 where
86 Iter1: DoubleEndedIterator + Clone,
87 Iter2: DoubleEndedIterator + Clone,
88 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
89 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
90 {
91 let maximum = self.maximum(len1, len2);
92
93 let cutoff_distance;
94 if let Some(mut cutoff) = score_cutoff {
95 cutoff = cutoff.clamp(0.0, 1.0);
96 score_cutoff = Some(cutoff);
97 cutoff_distance = Some((maximum as f64 * cutoff).ceil() as usize);
98 } else {
99 cutoff_distance = None;
100 }
101
102 let hint_distance;
103 if let Some(mut cutoff) = score_hint {
104 cutoff = cutoff.clamp(0.0, 1.0);
105 hint_distance = Some((maximum as f64 * cutoff).ceil() as usize);
106 } else {
107 hint_distance = None;
108 }
109
110 let dist = self._distance(s1, len1, s2, len2, cutoff_distance, hint_distance)?;
111 let norm_dist = if maximum == 0 {
112 0.0
113 } else {
114 dist as f64 / maximum as f64
115 };
116 if let Some(cutoff) = score_cutoff {
117 if norm_dist > cutoff {
118 return None;
119 }
120 }
121 Some(norm_dist)
122 }
123
124 fn _normalized_similarity<Iter1, Iter2>(
125 &self,
126 s1: Iter1,
127 len1: usize,
128 s2: Iter2,
129 len2: usize,
130 score_cutoff: Option<f64>,
131 score_hint: Option<f64>,
132 ) -> Option<f64>
133 where
134 Iter1: DoubleEndedIterator + Clone,
135 Iter2: DoubleEndedIterator + Clone,
136 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
137 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
138 {
139 let cutoff_score = score_cutoff.map(norm_sim_to_norm_dist);
140 let hint_score = score_hint.map(norm_sim_to_norm_dist);
141
142 let norm_dist = self._normalized_distance(s1, len1, s2, len2, cutoff_score, hint_score)?;
143 let norm_sim = 1.0 - norm_dist;
144
145 if let Some(cutoff) = score_cutoff {
146 if norm_sim < cutoff {
147 return None;
148 }
149 }
150 Some(norm_sim)
151 }
152}
153
154pub trait MetricUsize {
155 fn maximum(&self, len1: usize, len2: usize) -> usize;
156
157 fn _distance<Iter1, Iter2>(
158 &self,
159 s1: Iter1,
160 len1: usize,
161 s2: Iter2,
162 len2: usize,
163 score_cutoff: Option<usize>,
164 score_hint: Option<usize>,
165 ) -> usize
166 where
167 Iter1: DoubleEndedIterator + Clone,
168 Iter2: DoubleEndedIterator + Clone,
169 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
170 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
171 {
172 let maximum = self.maximum(len1, len2);
173
174 let cutoff_similarity = score_cutoff.map(|x| if maximum >= x { maximum - x } else { 0 });
175 let hint_similarity = score_hint.map(|x| if maximum >= x { maximum - x } else { 0 });
176
177 let sim = self._similarity(s1, len1, s2, len2, cutoff_similarity, hint_similarity);
178 maximum - sim
179 }
180
181 fn _similarity<Iter1, Iter2>(
182 &self,
183 s1: Iter1,
184 len1: usize,
185 s2: Iter2,
186 len2: usize,
187 score_cutoff: Option<usize>,
188 mut score_hint: Option<usize>,
189 ) -> usize
190 where
191 Iter1: DoubleEndedIterator + Clone,
192 Iter2: DoubleEndedIterator + Clone,
193 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
194 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
195 {
196 let maximum = self.maximum(len1, len2);
197 if let Some(cutoff) = score_cutoff {
198 if cutoff > maximum {
199 return maximum;
200 }
201
202 if let Some(hint) = score_hint {
203 score_hint = Some(hint.min(cutoff));
204 }
205 }
206
207 let cutoff_distance = score_cutoff.map(|x| maximum - x);
208 let hint_distance = score_hint.map(|x| maximum - x);
209 let dist = self._distance(s1, len1, s2, len2, cutoff_distance, hint_distance);
210 maximum - dist
211 }
212
213 fn _normalized_distance<Iter1, Iter2>(
214 &self,
215 s1: Iter1,
216 len1: usize,
217 s2: Iter2,
218 len2: usize,
219 score_cutoff: Option<f64>,
220 score_hint: Option<f64>,
221 ) -> f64
222 where
223 Iter1: DoubleEndedIterator + Clone,
224 Iter2: DoubleEndedIterator + Clone,
225 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
226 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
227 {
228 let maximum = self.maximum(len1, len2);
229
230 let cutoff_distance;
231 if let Some(mut cutoff) = score_cutoff {
232 cutoff = cutoff.clamp(0.0, 1.0);
233 cutoff_distance = Some((maximum as f64 * cutoff).ceil() as usize);
234 } else {
235 cutoff_distance = None;
236 }
237
238 let hint_distance;
239 if let Some(mut cutoff) = score_hint {
240 cutoff = cutoff.clamp(0.0, 1.0);
241 hint_distance = Some((maximum as f64 * cutoff).ceil() as usize);
242 } else {
243 hint_distance = None;
244 }
245
246 let dist = self._distance(s1, len1, s2, len2, cutoff_distance, hint_distance);
247 if maximum == 0 {
248 0.0
249 } else {
250 dist as f64 / maximum as f64
251 }
252 }
253
254 fn _normalized_similarity<Iter1, Iter2>(
255 &self,
256 s1: Iter1,
257 len1: usize,
258 s2: Iter2,
259 len2: usize,
260 score_cutoff: Option<f64>,
261 score_hint: Option<f64>,
262 ) -> f64
263 where
264 Iter1: DoubleEndedIterator + Clone,
265 Iter2: DoubleEndedIterator + Clone,
266 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
267 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
268 {
269 let cutoff_score = score_cutoff.map(norm_sim_to_norm_dist);
270 let hint_score = score_hint.map(norm_sim_to_norm_dist);
271
272 let norm_dist = self._normalized_distance(s1, len1, s2, len2, cutoff_score, hint_score);
273 1.0 - norm_dist
274 }
275}
276
277pub trait Metricf64 {
278 fn maximum(&self, len1: usize, len2: usize) -> f64;
279
280 fn _distance<Iter1, Iter2>(
281 &self,
282 s1: Iter1,
283 len1: usize,
284 s2: Iter2,
285 len2: usize,
286 score_cutoff: Option<f64>,
287 score_hint: Option<f64>,
288 ) -> f64
289 where
290 Iter1: DoubleEndedIterator + Clone,
291 Iter2: DoubleEndedIterator + Clone,
292 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
293 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
294 {
295 let maximum = self.maximum(len1, len2);
296
297 let cutoff_similarity = score_cutoff.map(|x| if maximum >= x { maximum - x } else { 0.0 });
298 let hint_similarity = score_hint.map(|x| if maximum >= x { maximum - x } else { 0.0 });
299
300 let sim = self._similarity(s1, len1, s2, len2, cutoff_similarity, hint_similarity);
301 maximum - sim
302 }
303
304 fn _similarity<Iter1, Iter2>(
305 &self,
306 s1: Iter1,
307 len1: usize,
308 s2: Iter2,
309 len2: usize,
310 score_cutoff: Option<f64>,
311 mut score_hint: Option<f64>,
312 ) -> f64
313 where
314 Iter1: DoubleEndedIterator + Clone,
315 Iter2: DoubleEndedIterator + Clone,
316 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
317 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
318 {
319 let maximum = self.maximum(len1, len2);
320 if let Some(cutoff) = score_cutoff {
321 if cutoff > maximum {
322 return maximum;
323 }
324
325 if let Some(hint) = score_hint {
326 score_hint = Some(hint.min(cutoff));
327 }
328 }
329
330 let cutoff_distance = score_cutoff.map(|x| maximum - x);
331 let hint_distance = score_hint.map(|x| maximum - x);
332 let dist = self._distance(s1, len1, s2, len2, cutoff_distance, hint_distance);
333 maximum - dist
334 }
335
336 fn _normalized_distance<Iter1, Iter2>(
337 &self,
338 s1: Iter1,
339 len1: usize,
340 s2: Iter2,
341 len2: usize,
342 score_cutoff: Option<f64>,
343 score_hint: Option<f64>,
344 ) -> f64
345 where
346 Iter1: DoubleEndedIterator + Clone,
347 Iter2: DoubleEndedIterator + Clone,
348 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
349 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
350 {
351 let maximum = self.maximum(len1, len2);
352
353 let cutoff_distance = score_cutoff.map(|x| maximum * x);
354 let hint_distance = score_hint.map(|x| maximum * x);
355
356 let dist = self._distance(s1, len1, s2, len2, cutoff_distance, hint_distance);
357 if maximum > 0.0 {
358 dist / maximum
359 } else {
360 0.0
361 }
362 }
363
364 fn _normalized_similarity<Iter1, Iter2>(
365 &self,
366 s1: Iter1,
367 len1: usize,
368 s2: Iter2,
369 len2: usize,
370 score_cutoff: Option<f64>,
371 score_hint: Option<f64>,
372 ) -> f64
373 where
374 Iter1: DoubleEndedIterator + Clone,
375 Iter2: DoubleEndedIterator + Clone,
376 Iter1::Item: PartialEq<Iter2::Item> + HashableChar + Copy,
377 Iter2::Item: PartialEq<Iter1::Item> + HashableChar + Copy,
378 {
379 let cutoff_score = score_cutoff.map(norm_sim_to_norm_dist);
380 let hint_score = score_hint.map(norm_sim_to_norm_dist);
381
382 let norm_dist = self._normalized_distance(s1, len1, s2, len2, cutoff_score, hint_score);
383 1.0 - norm_dist
384 }
385}