oxigdal_security/anonymization/
generalization.rs1use std::collections::{HashMap, HashSet};
4
5pub struct KAnonymity {
7 k: usize,
8}
9
10impl KAnonymity {
11 pub fn new(k: usize) -> Self {
13 Self { k }
14 }
15
16 pub fn check(&self, records: &[Vec<String>], quasi_identifiers: &[usize]) -> bool {
18 let mut groups: HashMap<Vec<String>, usize> = HashMap::new();
19
20 for record in records {
21 let qi: Vec<String> = quasi_identifiers
22 .iter()
23 .filter_map(|&i| record.get(i).cloned())
24 .collect();
25 *groups.entry(qi).or_insert(0) += 1;
26 }
27
28 groups.values().all(|&count| count >= self.k)
29 }
30
31 pub fn min_group_size(&self, records: &[Vec<String>], quasi_identifiers: &[usize]) -> usize {
33 let mut groups: HashMap<Vec<String>, usize> = HashMap::new();
34
35 for record in records {
36 let qi: Vec<String> = quasi_identifiers
37 .iter()
38 .filter_map(|&i| record.get(i).cloned())
39 .collect();
40 *groups.entry(qi).or_insert(0) += 1;
41 }
42
43 groups.values().copied().min().unwrap_or(0)
44 }
45}
46
47pub struct LDiversity {
49 l: usize,
50}
51
52impl LDiversity {
53 pub fn new(l: usize) -> Self {
55 Self { l }
56 }
57
58 pub fn check(
60 &self,
61 records: &[Vec<String>],
62 quasi_identifiers: &[usize],
63 sensitive_attr: usize,
64 ) -> bool {
65 let mut groups: HashMap<Vec<String>, HashSet<String>> = HashMap::new();
66
67 for record in records {
68 let qi: Vec<String> = quasi_identifiers
69 .iter()
70 .filter_map(|&i| record.get(i).cloned())
71 .collect();
72
73 if let Some(sensitive) = record.get(sensitive_attr) {
74 groups.entry(qi).or_default().insert(sensitive.clone());
75 }
76 }
77
78 groups.values().all(|values| values.len() >= self.l)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_k_anonymity() {
88 let checker = KAnonymity::new(2);
89
90 let records = vec![
91 vec![
92 "Alice".to_string(),
93 "30".to_string(),
94 "Engineer".to_string(),
95 ],
96 vec!["Bob".to_string(), "30".to_string(), "Doctor".to_string()],
97 vec![
98 "Charlie".to_string(),
99 "40".to_string(),
100 "Teacher".to_string(),
101 ],
102 vec!["David".to_string(), "40".to_string(), "Lawyer".to_string()],
103 ];
104
105 assert!(checker.check(&records, &[1]));
107 }
108}