#[cfg(feature = "contrib")]
mod non_adaptive;
#[cfg(feature = "contrib")]
pub use non_adaptive::*;
#[cfg(feature = "contrib")]
mod adaptive;
#[cfg(feature = "contrib")]
pub use adaptive::*;
#[cfg(feature = "contrib")]
mod fully_adaptive;
#[cfg(feature = "contrib")]
pub use fully_adaptive::*;
use opendp_derive::proven;
#[cfg(feature = "ffi")]
mod ffi;
use crate::{
core::{Function, Measure},
error::Fallible,
measures::{Approximate, MaxDivergence, RenyiDivergence, ZeroConcentratedDivergence},
traits::InfAdd,
};
#[derive(Debug)]
pub enum Adaptivity {
NonAdaptive,
Adaptive,
FullyAdaptive,
}
#[derive(Debug)]
pub enum Composability {
Sequential,
Concurrent,
}
pub trait CompositionMeasure: Measure {
fn composability(&self, adaptivity: Adaptivity) -> Fallible<Composability>;
fn compose(&self, d_mids: Vec<Self::Distance>) -> Fallible<Self::Distance>;
}
#[proven(
proof_path = "combinators/sequential_composition/CompositionMeasure_for_MaxDivergence.tex"
)]
impl CompositionMeasure for MaxDivergence {
fn composability(&self, _adaptivity: Adaptivity) -> Fallible<Composability> {
Ok(Composability::Concurrent)
}
fn compose(&self, d_mids: Vec<Self::Distance>) -> Fallible<Self::Distance> {
d_mids.iter().try_fold(0.0, |sum, d_i| sum.inf_add(d_i))
}
}
#[proven(
proof_path = "combinators/sequential_composition/CompositionMeasure_for_ZeroConcentratedDivergence.tex"
)]
impl CompositionMeasure for ZeroConcentratedDivergence {
fn composability(&self, _adaptivity: Adaptivity) -> Fallible<Composability> {
Ok(Composability::Concurrent)
}
fn compose(&self, d_mids: Vec<Self::Distance>) -> Fallible<Self::Distance> {
d_mids.iter().try_fold(0.0, |sum, d_i| sum.inf_add(d_i))
}
}
#[proven(
proof_path = "combinators/sequential_composition/CompositionMeasure_for_ApproximateMaxDivergence.tex"
)]
impl CompositionMeasure for Approximate<MaxDivergence> {
fn composability(&self, _adaptivity: Adaptivity) -> Fallible<Composability> {
Ok(Composability::Concurrent)
}
fn compose(&self, d_mids: Vec<Self::Distance>) -> Fallible<Self::Distance> {
d_mids
.iter()
.try_fold((0.0, 0.0), |(eps_g, del_g), (eps_i, del_i)| {
Ok((eps_g.inf_add(eps_i)?, del_g.inf_add(del_i)?))
})
}
}
#[proven(
proof_path = "combinators/sequential_composition/CompositionMeasure_for_ZeroConcentratedDivergence.tex"
)]
impl CompositionMeasure for Approximate<ZeroConcentratedDivergence> {
fn composability(&self, _adaptivity: Adaptivity) -> Fallible<Composability> {
Ok(Composability::Sequential)
}
fn compose(&self, d_mids: Vec<Self::Distance>) -> Fallible<Self::Distance> {
d_mids
.iter()
.try_fold((0.0, 0.0), |(eps_g, del_g), (eps_i, del_i)| {
Ok((eps_g.inf_add(eps_i)?, del_g.inf_add(del_i)?))
})
}
}
#[proven(
proof_path = "combinators/sequential_composition/CompositionMeasure_for_RenyiDivergence.tex"
)]
impl CompositionMeasure for RenyiDivergence {
fn composability(&self, _adaptivity: Adaptivity) -> Fallible<Composability> {
Ok(Composability::Concurrent)
}
fn compose(&self, d_mids: Vec<Self::Distance>) -> Fallible<Self::Distance> {
Ok(Function::new_fallible(move |alpha| {
d_mids
.iter()
.map(|f| f.eval(alpha))
.try_fold(0.0, |sum, eps| sum.inf_add(&eps?))
}))
}
}