use std::iter::Sum;
use opendp_derive::bootstrap;
use super::can_int_sum_overflow;
use crate::{
core::{Function, StabilityMap, Transformation},
domains::{AtomDomain, VectorDomain},
error::Fallible,
metrics::{AbsoluteDistance, IntDistance, SymmetricDistance},
traits::Integer,
};
#[cfg(feature = "ffi")]
mod ffi;
#[bootstrap(features("contrib"), generics(T(example = "$get_first(bounds)")))]
pub fn make_sized_bounded_int_checked_sum<T: Integer>(
size: usize,
bounds: (T, T),
) -> Fallible<
Transformation<
VectorDomain<AtomDomain<T>>,
SymmetricDistance,
AtomDomain<T>,
AbsoluteDistance<T>,
>,
>
where
for<'a> T: Sum<&'a T>,
{
if can_int_sum_overflow(size, bounds.clone()) {
return fallible!(
MakeTransformation,
"potential for overflow when computing function. You could resolve this by choosing tighter clipping bounds or by using a data type with greater bit-depth."
);
}
let (lower, upper) = bounds.clone();
let range = upper.inf_sub(&lower)?;
Transformation::new(
VectorDomain::new(AtomDomain::new_closed(bounds)?).with_size(size),
SymmetricDistance,
AtomDomain::default(),
AbsoluteDistance::default(),
Function::new(|arg: &Vec<T>| arg.iter().sum()),
StabilityMap::new_fallible(
move |d_in: &IntDistance| T::inf_cast(d_in / 2).and_then(|d_in| d_in.inf_mul(&range)),
),
)
}
#[cfg(test)]
mod test;