1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use smartnoise_validator::errors::*;
use crate::NodeArguments;
use smartnoise_validator::base::{Value, Array, ReleaseNode};
use crate::components::Evaluable;
use ndarray::{ArrayD, Axis, arr0};
use smartnoise_validator::{proto, Integer};
use smartnoise_validator::utilities::take_argument;
use std::collections::HashSet;
use crate::utilities::get_num_columns;
use std::iter::FromIterator;
use std::hash::Hash;
use noisy_float::types::n64;
impl Evaluable for proto::Count {
fn evaluate(&self, _privacy_definition: &Option<proto::PrivacyDefinition>, mut arguments: NodeArguments) -> Result<ReleaseNode> {
Ok(ReleaseNode::new(if self.distinct {
match take_argument(&mut arguments, "data")?.array()? {
Array::Bool(data) => count_distinct(&data)?.into(),
Array::Float(data) => count_distinct(&data.mapv(|v| n64(v as f64)))?.into(),
Array::Int(data) => count_distinct(&data)?.into(),
Array::Str(data) => count_distinct(&data)?.into()
}
} else {
match take_argument(&mut arguments, "data")? {
Value::Array(array) => match array {
Array::Bool(data) => count(&data)?.into(),
Array::Float(data) => count(&data)?.into(),
Array::Int(data) => count(&data)?.into(),
Array::Str(data) => count(&data)?.into()
},
Value::Dataframe(dataframe) => match dataframe.get_index(0) {
Some(value) => arr0(value.1.ref_array()?.num_records()? as Integer).into_dyn().into(),
None => return Err("indexmap may not be empty".into())
},
_ => return Err("Count is only implemented on arrays and dataframes".into())
}
}))
}
}
pub fn count<T>(data: &ArrayD<T>) -> Result<ArrayD<Integer>> {
Ok(ndarray::Array::from_shape_vec(vec![], vec![data.len_of(Axis(0)) as Integer])?)
}
pub fn count_distinct<T: Eq + Hash>(data: &ArrayD<T>) -> Result<ArrayD<Integer>> {
let counts = data.gencolumns().into_iter().map(|column| {
HashSet::<&T>::from_iter(column.iter()).len() as Integer
}).collect::<Vec<Integer>>();
let array = match data.ndim() {
1 => ndarray::Array::from_shape_vec(vec![], counts),
2 => ndarray::Array::from_shape_vec(vec![1 as usize, get_num_columns(&data)? as usize], counts),
_ => return Err("invalid data shape for Count".into())
};
match array {
Ok(array) => Ok(array),
Err(_) => Err("unable to package Count result into an array".into())
}
}