1use matchete::{Assessor, Resemblance};
2
3#[derive(Debug)]
4struct LevenshteinResembler;
5
6impl Resemblance<String, String> for LevenshteinResembler {
7 fn resemblance(&self, query: &String, candidate: &String) -> f64 {
8 let distance = levenshtein_distance(query, candidate);
9 let max_len = query.len().max(candidate.len());
10 if max_len == 0 { 1.0 } else { 1.0 - (distance as f64 / max_len as f64) }
11 }
12
13 fn perfect(&self, query: &String, candidate: &String) -> bool {
14 query == candidate
15 }
16}
17
18#[derive(Debug)]
19struct JaccardResembler;
20
21impl Resemblance<String, String> for JaccardResembler {
22 fn resemblance(&self, query: &String, candidate: &String) -> f64 {
23 let query_chars: std::collections::HashSet<char> = query.chars().collect();
24 let item_chars: std::collections::HashSet<char> = candidate.chars().collect();
25
26 let intersection = query_chars.intersection(&item_chars).count();
27 let union = query_chars.union(&item_chars).count();
28
29 if union == 0 { 1.0 } else { intersection as f64 / union as f64 }
30 }
31
32 fn perfect(&self, query: &String, candidate: &String) -> bool {
33 query == candidate
34 }
35}
36
37fn levenshtein_distance(a: &str, b: &str) -> usize {
38 let len_a = a.len();
39 let len_b = b.len();
40
41 if len_a == 0 { return len_b; }
42 if len_b == 0 { return len_a; }
43
44 let mut matrix = vec![vec![0; len_b + 1]; len_a + 1];
45
46 for i in 0..=len_a { matrix[i][0] = i; }
47 for j in 0..=len_b { matrix[0][j] = j; }
48
49 for i in 1..=len_a {
50 for j in 1..=len_b {
51 let cost = if a.chars().nth(i - 1) == b.chars().nth(j - 1) { 0 } else { 1 };
52 matrix[i][j] = (matrix[i - 1][j] + 1)
53 .min(matrix[i][j - 1] + 1)
54 .min(matrix[i - 1][j - 1] + cost);
55 }
56 }
57
58 matrix[len_a][len_b]
59}
60
61fn main() {
62 let assessor = Assessor::<String, String>::new()
63 .with(LevenshteinResembler, 0.7)
64 .with(JaccardResembler, 0.3)
65 .floor(0.5);
66
67 let query = String::from("test");
68 let candidate = String::from("tent");
69
70 println!("Detailed Analysis Example");
71 println!("========================");
72
73 let verdict = assessor.verdict(&query, &candidate);
74 println!("Query: {}", verdict.query);
75 println!("Candidate: {}", verdict.candidate);
76 println!("Overall resemblance: {:.2}", verdict.resemblance);
77 println!("Perfect match: {}", verdict.perfect);
78 println!("Is viable: {}", assessor.viable(&query, &candidate));
79 println!("Disposition: {:?}", assessor.disposition(&query, &candidate));
80 println!("Individual resembler facets:");
81
82 let resembler_names: Vec<String> = assessor.resemblers.iter()
84 .map(|resembler| format!("{:?}", resembler))
85 .collect();
86
87 for (i, facet) in verdict.facets.iter().enumerate() {
88 println!(" Resembler {}: {}", i + 1, resembler_names[i]);
89 println!(" Raw resemblance: {:.2}", facet.resemblance);
90 println!(" Influence magnitude: {:.2}", facet.influence.magnitude);
91 println!(" Contribution: {:.2}", facet.contribution);
92 }
93
94 println!("\nBest Match Example");
96 println!("==================");
97
98 let candidates = vec![
99 String::from("tent"),
100 String::from("test"),
101 String::from("toast"),
102 String::from("rest"),
103 ];
104
105 if let Some(champion) = assessor.champion(&query, &candidates) {
106 println!("Champion: {} (resemblance: {:.2})", champion.candidate, champion.resemblance);
107 }
108
109 println!("\nShortlist Example");
111 println!("=================");
112
113 let shortlist = assessor.shortlist(&query, &candidates);
114 for (i, verdict) in shortlist.iter().enumerate() {
115 println!("{}. {} (resemblance: {:.2})", i + 1, verdict.candidate, verdict.resemblance);
116 }
117}