use crate::errors::*;
mod transforms;
mod cast;
mod clamp;
mod count;
mod covariance;
mod column_bind;
mod digitize;
mod dp_count;
mod dp_variance;
mod dp_covariance;
mod dp_gumbel_median;
mod dp_histogram;
mod dp_linear_regression;
mod dp_maximum;
mod dp_median;
mod dp_minimum;
mod dp_mean;
mod dp_quantile;
mod dp_raw_moment;
mod dp_sum;
mod filter;
mod histogram;
mod impute;
pub mod index;
mod raw_moment;
mod literal;
mod map;
mod materialize;
pub mod partition;
mod quantile;
mod reshape;
mod mean;
mod exponential_mechanism;
pub mod gaussian_mechanism;
mod laplace_mechanism;
mod simple_geometric_mechanism;
pub mod snapping_mechanism;
mod resize;
mod theil_sen;
mod to_dataframe;
mod sum;
mod union;
mod variance;
use crate::base::{IndexKey, Value, NodeProperties, SensitivitySpace, ValueProperties};
use crate::{proto, Warnable, base};
use crate::utilities::json::{JSONRelease};
use crate::utilities::set_node_id;
use indexmap::map::IndexMap;
pub trait Component {
fn propagate_property(
&self,
privacy_definition: &Option<proto::PrivacyDefinition>,
public_arguments: IndexMap<base::IndexKey, &Value>,
properties: NodeProperties,
_node_id: u32,
) -> Result<Warnable<ValueProperties>>;
}
pub trait Expandable {
fn expand_component(
&self,
privacy_definition: &Option<proto::PrivacyDefinition>,
component: &proto::Component,
public_arguments: &IndexMap<base::IndexKey, &Value>,
properties: &NodeProperties,
component_id: u32,
maximum_id: u32,
) -> Result<base::ComponentExpansion>;
}
pub trait Mechanism {
fn get_privacy_usage(
&self,
privacy_definition: &proto::PrivacyDefinition,
release_usage: Option<&Vec<proto::PrivacyUsage>>,
properties: &NodeProperties
) -> Result<Option<Vec<proto::PrivacyUsage>>>;
}
pub trait Sensitivity {
fn compute_sensitivity(
&self,
privacy_definition: &proto::PrivacyDefinition,
properties: &NodeProperties,
sensitivity_type: &SensitivitySpace,
) -> Result<Value>;
}
pub trait Accuracy {
fn accuracy_to_privacy_usage(
&self,
accuracies: &proto::Accuracies,
public_arguments: IndexMap<base::IndexKey, &Value>
) -> Result<Option<Vec<proto::PrivacyUsage>>>;
fn privacy_usage_to_accuracy(
&self,
public_arguments: IndexMap<base::IndexKey, &Value>,
alpha: f64,
) -> Result<Option<Vec<proto::Accuracy>>>;
}
pub trait Report {
fn summarize(
&self,
node_id: u32,
component: &proto::Component,
public_arguments: IndexMap<base::IndexKey, &Value>,
properties: NodeProperties,
release: &Value,
variable_names: Option<&Vec<base::IndexKey>>,
) -> Result<Option<Vec<JSONRelease>>>;
}
pub trait Named {
fn get_names(
&self,
public_arguments: IndexMap<base::IndexKey, &Value>,
argument_variables: IndexMap<base::IndexKey, Vec<IndexKey>>,
release: Option<&Value>,
) -> Result<Vec<IndexKey>>;
}
impl Component for proto::Component {
fn propagate_property(
&self,
privacy_definition: &Option<proto::PrivacyDefinition>,
public_arguments: IndexMap<base::IndexKey, &Value>,
properties: NodeProperties,
node_id: u32,
) -> Result<Warnable<ValueProperties>> {
let variant = self.variant.as_ref()
.ok_or_else(|| "variant: must be defined")?;
macro_rules! propagate_property {
($( $variant:ident ),*) => {
{
$(
if let proto::component::Variant::$variant(x) = variant {
let Warnable(mut property, warnings) = x.propagate_property(
privacy_definition, public_arguments, properties, node_id)
.chain_err(|| format!("node specification {:?}:", variant))?;
set_node_id(&mut property, node_id);
return Ok(Warnable(property, warnings));
}
)*
}
}
}
propagate_property!(
Cast, Clamp, ColumnBind, Count, Covariance, Digitize,
Filter, Histogram, Impute, Index, Literal, Materialize, Mean,
Partition, Quantile, RawMoment, Reshape, Resize, Sum, ToDataframe, Union, Variance,
ExponentialMechanism, GaussianMechanism, LaplaceMechanism,
SimpleGeometricMechanism, SnappingMechanism,
Abs, Add, LogicalAnd, Divide, Equal, GreaterThan, LessThan, Log, Modulo, Multiply,
Negate, Negative, LogicalOr, Power, RowMax, RowMin, Subtract, TheilSen, DpGumbelMedian
);
Err(format!("proto component {:?} is missing its Component trait", variant).into())
}
}
impl Expandable for proto::Component {
fn expand_component(
&self,
privacy_definition: &Option<proto::PrivacyDefinition>,
component: &proto::Component,
public_arguments: &IndexMap<base::IndexKey, &Value>,
properties: &NodeProperties,
component_id: u32,
maximum_id: u32,
) -> Result<base::ComponentExpansion> {
let variant = self.variant.as_ref()
.ok_or_else(|| "variant: must be defined")?;
macro_rules! expand_component {
($( $variant:ident ),*) => {
{
$(
if let proto::component::Variant::$variant(x) = variant {
let expansion = x.expand_component(
privacy_definition, component, public_arguments,
properties, component_id, maximum_id)
.chain_err(|| format!("node specification {:?}:", variant))?;
expansion.is_valid(component_id)?;
return Ok(expansion)
}
)*
}
}
}
if let proto::component::Variant::Index(_) = variant {
return Ok(base::ComponentExpansion::default())
}
if let proto::component::Variant::Union(_) = variant {
return Ok(base::ComponentExpansion::default())
}
expand_component!(Map);
if properties.values().any(|props| props.partitions().is_ok()) {
let mut component_expansion = base::ComponentExpansion::default();
component_expansion.computation_graph.insert(component_id, proto::Component {
arguments: component.arguments.clone(),
variant: Some(proto::component::Variant::Map(Box::new(proto::Map {
component: Some(Box::from(component.clone()))
}))),
omit: component.omit,
submission: component.submission,
});
component_expansion.traversal.push(component_id);
return Ok(component_expansion);
}
expand_component!(
Clamp, Digitize, Histogram, Impute, Map, Maximum, Median, Minimum, Partition, Resize,
DpCount, DpCovariance, DpHistogram, DpLinearRegression, DpMaximum, DpMean, DpMedian,
DpMinimum, DpQuantile, DpRawMoment, DpSum, DpVariance,
ExponentialMechanism, GaussianMechanism, LaplaceMechanism,
SimpleGeometricMechanism, SnappingMechanism, DpGumbelMedian,
ToBool, ToFloat, ToInt, ToString
);
Ok(base::ComponentExpansion::default())
}
}
impl Mechanism for proto::Component {
fn get_privacy_usage(
&self,
privacy_definition: &proto::PrivacyDefinition,
release_usage: Option<&Vec<proto::PrivacyUsage>>,
properties: &NodeProperties
) -> Result<Option<Vec<proto::PrivacyUsage>>> {
let variant = self.variant.as_ref()
.ok_or_else(|| "variant: must be defined")?;
macro_rules! get_privacy_usage {
($( $variant:ident ),*) => {
{
$(
if let proto::component::Variant::$variant(x) = variant {
return x.get_privacy_usage(privacy_definition, release_usage, properties)
.chain_err(|| format!("node specification {:?}:", variant))
}
)*
}
}
}
get_privacy_usage!(
ExponentialMechanism, GaussianMechanism, LaplaceMechanism,
SimpleGeometricMechanism, SnappingMechanism
);
Ok(None)
}
}
impl Sensitivity for proto::component::Variant {
fn compute_sensitivity(
&self,
privacy_definition: &proto::PrivacyDefinition,
properties: &NodeProperties,
sensitivity_type: &SensitivitySpace,
) -> Result<Value> {
macro_rules! compute_sensitivity {
($( $variant:ident ),*) => {
{
$(
if let proto::component::Variant::$variant(x) = self {
return x.compute_sensitivity(privacy_definition, properties, sensitivity_type)
.chain_err(|| format!("node specification {:?}:", self))
}
)*
}
}
}
compute_sensitivity!(
Count, Covariance, Histogram, Mean, Quantile, RawMoment, Sum, Union, Variance
);
Err(format!("sensitivity is not implemented for proto component {:?}", self).into())
}
}
impl Accuracy for proto::Component {
fn accuracy_to_privacy_usage(
&self,
accuracy: &proto::Accuracies,
public_arguments: IndexMap<base::IndexKey, &Value>
) -> Result<Option<Vec<proto::PrivacyUsage>>> {
let variant = self.variant.as_ref()
.ok_or_else(|| "variant: must be defined")?;
macro_rules! accuracy_to_privacy_usage {
($( $variant:ident ),*) => {
{
$(
if let proto::component::Variant::$variant(x) = variant {
return x.accuracy_to_privacy_usage(accuracy, public_arguments)
.chain_err(|| format!("node specification {:?}:", variant))
}
)*
}
}
}
accuracy_to_privacy_usage!(
LaplaceMechanism,
GaussianMechanism,
SimpleGeometricMechanism,
SnappingMechanism
);
Ok(None)
}
fn privacy_usage_to_accuracy(
&self,
public_arguments: IndexMap<base::IndexKey, &Value>,
alpha: f64,
) -> Result<Option<Vec<proto::Accuracy>>> {
let variant = self.variant.as_ref()
.ok_or_else(|| "variant: must be defined")?;
macro_rules! privacy_usage_to_accuracy {
($( $variant:ident ),*) => {
{
$(
if let proto::component::Variant::$variant(x) = variant {
return x.privacy_usage_to_accuracy(public_arguments, alpha)
.chain_err(|| format!("node specification {:?}:", variant))
}
)*
}
}
}
privacy_usage_to_accuracy!(
LaplaceMechanism,
GaussianMechanism,
SimpleGeometricMechanism,
SnappingMechanism
);
Ok(None)
}
}
impl Report for proto::Component {
fn summarize(
&self,
node_id: u32,
component: &proto::Component,
public_arguments: IndexMap<base::IndexKey, &Value>,
properties: NodeProperties,
release: &Value,
variable_names: Option<&Vec<base::IndexKey>>,
) -> Result<Option<Vec<JSONRelease>>> {
let variant = self.variant.as_ref()
.ok_or_else(|| "variant: must be defined")?;
macro_rules! summarize {
($( $variant:ident ),*) => {
{
$(
if let proto::component::Variant::$variant(x) = variant {
return x.summarize(node_id, component, public_arguments,
properties, release, variable_names)
.chain_err(|| format!("node specification: {:?}:", variant))
}
)*
}
}
}
summarize!(
DpCount, DpCovariance, DpHistogram, DpMaximum, DpMean, DpMinimum, DpQuantile,
DpRawMoment, DpSum, DpVariance
);
Ok(None)
}
}
impl Named for proto::Component {
fn get_names(
&self,
public_arguments: IndexMap<base::IndexKey, &Value>,
argument_variables: IndexMap<base::IndexKey, Vec<IndexKey>>,
release: Option<&Value>,
) -> Result<Vec<IndexKey>> {
let variant = self.variant.as_ref()
.ok_or_else(|| "variant: must be defined")?;
macro_rules! get_names {
($( $variant:ident ),*) => {
{
$(
if let proto::component::Variant::$variant(x) = variant {
return x.get_names(public_arguments, argument_variables, release)
.chain_err(|| format!("node specification {:?}:", variant))
}
)*
}
}
}
get_names!(
ToDataframe, Index, Literal, Materialize
);
match argument_variables.get(&IndexKey::from("data")) {
Some(variable_names) => Ok(variable_names.clone()),
None => Err(format!("names are not implemented for proto component {:?}", variant).into())
}
}
}