opendp/transformations/sum/int/checked/
mod.rs1use std::iter::Sum;
2
3use opendp_derive::bootstrap;
4
5use super::can_int_sum_overflow;
6use crate::{
7 core::{Function, StabilityMap, Transformation},
8 domains::{AtomDomain, VectorDomain},
9 error::Fallible,
10 metrics::{AbsoluteDistance, IntDistance, SymmetricDistance},
11 traits::Integer,
12};
13
14#[cfg(feature = "ffi")]
15mod ffi;
16
17#[bootstrap(features("contrib"), generics(T(example = "$get_first(bounds)")))]
18pub fn make_sized_bounded_int_checked_sum<T: Integer>(
32 size: usize,
33 bounds: (T, T),
34) -> Fallible<
35 Transformation<
36 VectorDomain<AtomDomain<T>>,
37 SymmetricDistance,
38 AtomDomain<T>,
39 AbsoluteDistance<T>,
40 >,
41>
42where
43 for<'a> T: Sum<&'a T>,
44{
45 if can_int_sum_overflow(size, bounds.clone()) {
46 return fallible!(
47 MakeTransformation,
48 "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."
49 );
50 }
51
52 let (lower, upper) = bounds.clone();
53 let range = upper.inf_sub(&lower)?;
54 Transformation::new(
55 VectorDomain::new(AtomDomain::new_closed(bounds)?).with_size(size),
56 SymmetricDistance,
57 AtomDomain::default(),
58 AbsoluteDistance::default(),
59 Function::new(|arg: &Vec<T>| arg.iter().sum()),
60 StabilityMap::new_fallible(
61 move |d_in: &IntDistance| T::inf_cast(d_in / 2).and_then(|d_in| d_in.inf_mul(&range)),
64 ),
65 )
66}
67
68#[cfg(test)]
69mod test;