1use crate::data_manipulation::aggregation::truncate_to_domain;
2use crate::data_manipulation::anonymizable::{
3 Anonymizable, IntervalType, NominalType, OrdinalType, QuasiIdentifierType, QuasiIdentifierTypes,
4};
5use crate::noise::laplace::categorical_noiser::CategoricalNoiser;
6use crate::noise::laplace::numerical_noiser::NumericalNoiser;
7use crate::noise::noiser::Noiser;
8
9pub const LOC: f64 = 0.0;
11
12#[derive(Clone)]
14enum NoiserCategories {
15 NumericalNoiser(NumericalNoiser),
16 CategoricalNoiser(CategoricalNoiser),
17}
18
19#[derive(Clone)]
21pub enum CategoricalTypes {
22 Nominal(NominalType),
23 Ordinal(OrdinalType),
24}
25
26#[derive(Default, Clone)]
29pub struct LaplaceNoiser {
30 eps: f64, k: usize, noise_thr: f64, qi_noisers: Vec<NoiserCategories>, }
35
36impl LaplaceNoiser {
37 pub fn new(eps: f64, k: usize, noise_thr: f64) -> Self {
38 Self {
39 eps,
40 k,
41 noise_thr,
42 ..Default::default()
43 }
44 }
45
46 fn generate_noise_interval(
48 &mut self,
49 interval: IntervalType,
50 qi_len: usize,
51 index: usize,
52 ) -> QuasiIdentifierTypes {
53 match self.qi_noisers.get_mut(index) {
54 None => {
55 let mut noiser =
56 NumericalNoiser::initialize(self.eps, self.k, qi_len as f64, &interval);
57 let noise = noiser.generate_noise(&interval);
58 self.qi_noisers
59 .push(NoiserCategories::NumericalNoiser(noiser));
60 QuasiIdentifierTypes::Interval(self.add_noise_interval(noise, interval))
61 }
62 Some(category) => match category {
63 NoiserCategories::NumericalNoiser(noiser) => {
64 let noise = noiser.generate_noise(&interval);
65 QuasiIdentifierTypes::Interval(self.add_noise_interval(noise, interval))
66 }
67 _ => panic!("wrong noiser type detected"),
68 },
69 }
70 }
71
72 fn generate_noise_ordinal(
74 &mut self,
75 ordinal: OrdinalType,
76 stream_weight: usize,
77 index: usize,
78 ) -> QuasiIdentifierTypes {
79 match self.qi_noisers.get_mut(index) {
80 None => {
81 let mut noiser = CategoricalNoiser::initialize(self.noise_thr, stream_weight);
82 let noise = noiser.generate_noise(CategoricalTypes::Ordinal(ordinal));
83 self.qi_noisers
84 .push(NoiserCategories::CategoricalNoiser(noiser));
85 QuasiIdentifierTypes::Ordinal(self.add_noise_ordinal(noise, ordinal))
86 }
87 Some(category) => match category {
88 NoiserCategories::CategoricalNoiser(noiser) => {
89 let noise = noiser.generate_noise(CategoricalTypes::Ordinal(ordinal));
90 QuasiIdentifierTypes::Ordinal(self.add_noise_ordinal(noise, ordinal))
91 }
92 _ => panic!("wrong noiser type detected"),
93 },
94 }
95 }
96
97 fn generate_noise_nominal(
99 &mut self,
100 nominal: NominalType,
101 stream_weight: usize,
102 index: usize,
103 ) -> QuasiIdentifierTypes {
104 match self.qi_noisers.get_mut(index) {
105 None => {
106 let mut noiser = CategoricalNoiser::initialize(self.noise_thr, stream_weight);
107 let noise = noiser.generate_noise(CategoricalTypes::Nominal(nominal));
108 self.qi_noisers
109 .push(NoiserCategories::CategoricalNoiser(noiser));
110 QuasiIdentifierTypes::Nominal(self.add_noise_nominal(noise, nominal))
111 }
112 Some(categorical) => match categorical {
113 NoiserCategories::CategoricalNoiser(noiser) => {
114 let noise = noiser.generate_noise(CategoricalTypes::Nominal(nominal));
115 QuasiIdentifierTypes::Nominal(self.add_noise_nominal(noise, nominal))
116 }
117 _ => panic!("wrong noiser type detected"),
118 },
119 }
120 }
121
122 pub fn add_noise_interval(&self, noise: f64, interval: IntervalType) -> IntervalType {
124 match interval {
125 (
126 QuasiIdentifierType::Float(value),
127 QuasiIdentifierType::Float(min_value),
128 QuasiIdentifierType::Float(max_value),
129 weight,
130 ) => (
131 QuasiIdentifierType::Float(truncate_to_domain(value + noise, min_value, max_value)),
132 QuasiIdentifierType::Float(min_value),
133 QuasiIdentifierType::Float(max_value),
134 weight,
135 ),
136 (
137 QuasiIdentifierType::Integer(value),
138 QuasiIdentifierType::Integer(min_value),
139 QuasiIdentifierType::Integer(max_value),
140 weight,
141 ) => (
142 QuasiIdentifierType::Integer(truncate_to_domain(
143 (value as f64 + noise) as i32,
144 min_value,
145 max_value,
146 )),
147 QuasiIdentifierType::Integer(min_value),
148 QuasiIdentifierType::Integer(max_value),
149 weight,
150 ),
151 _ => {
152 panic!("Wrong typing combination when adding noise to interval value")
153 }
154 }
155 }
156
157 fn add_noise_nominal(&self, noise: i32, nominal: NominalType) -> NominalType {
159 let (_, max_value, weight) = nominal;
160 (noise, max_value, weight)
161 }
162
163 fn add_noise_ordinal(&self, noise: i32, ordinal: OrdinalType) -> OrdinalType {
165 let (_, max_rank, weight) = ordinal;
166 (noise, max_rank, weight)
167 }
168
169 fn calculate_stream_weight(&self, qi: &[QuasiIdentifierTypes]) -> usize {
171 qi.iter()
172 .map(|x| match x {
173 QuasiIdentifierTypes::Interval((_, _, _, weight)) => weight,
174 QuasiIdentifierTypes::Ordinal((_, _, weight)) => weight,
175 QuasiIdentifierTypes::Nominal((_, _, weight)) => weight,
176 })
177 .sum()
178 }
179}
180
181impl Noiser for LaplaceNoiser {
182 fn add_noise<M: Anonymizable>(&mut self, value: &M) -> Vec<QuasiIdentifierTypes> {
183 let qi = value.quasi_identifiers();
184 let qi_len = qi.len();
185 let stream_weight = match self.qi_noisers.is_empty() {
186 true => self.calculate_stream_weight(&qi),
187 false => 0,
188 };
189
190 qi.into_iter()
191 .enumerate()
192 .map(|(index, x)| match x {
193 QuasiIdentifierTypes::Interval(interval) => {
194 self.generate_noise_interval(interval, qi_len, index)
195 }
196 QuasiIdentifierTypes::Ordinal(ordinal) => {
197 self.generate_noise_ordinal(ordinal, stream_weight, index)
198 }
199 QuasiIdentifierTypes::Nominal(nominal) => {
200 self.generate_noise_nominal(nominal, stream_weight, index)
201 }
202 })
203 .collect::<Vec<QuasiIdentifierTypes>>()
204 }
205}