analysis/
analysis.rs

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    // Get resembler names using Debug trait
83    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    // Example of finding best match from multiple candidates
95    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    // Example of getting shortlist
110    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}