@@ -657,8 +657,35 @@ func ComplementaryGaussianTolerance(flakinessK, l0Sensitivity, lInfSensitivity,
657657 return math .Erfinv (math .Pow (10 , - flakinessK )) * noise .SigmaForGaussian (int64 (l0Sensitivity ), lInfSensitivity , epsilon , delta ) * math .Sqrt (2 )
658658}
659659
660+ // GaussianToleranceForMean returns tolerances to be used in approxEquals for tests
661+ // for mean using Gaussian Noise to pass with 10⁻ᵏ flakiness.
662+ //
663+ // The return values include the tolerances for count, normalized sum, and mean.
664+ //
665+ // - flakinessK: parameter used to specify k in the flakiness.
666+ // - lower: minimum possible value of the input entities.
667+ // - upper: maximum possible value of the input entities.
668+ // - epsilon: the differential privacy parameter epsilon.
669+ // - stats.NormalizedSum: \sum { clamp(x_i, lower, upper) - midPoint }.
670+ //
671+ // distanceFromMidPoint = upper - midPoint, where midPoint = (lower + upper)/2.
672+ //
673+ // To see the logic and the math behind flakiness and tolerance calculation,
674+ // See https://github.com/google/differential-privacy/blob/main/privacy-on-beam/docs/Tolerance_Calculation.pdf
675+ func GaussianToleranceForMean (
676+ flakinessK , lower , upper float64 , maxContributionsPerPartition , maxPartitionsContributed int64 ,
677+ epsilon float64 , delta float64 , stats VarianceStatistics ,
678+ ) (VarianceStatistics , error ) {
679+ getToleranceOfNoise := func (flakinessK , eps , delta float64 , sensitivify sensitivity ) float64 {
680+ return GaussianTolerance (flakinessK , sensitivify .L0 , sensitivify .LInf , eps , delta )
681+ }
682+ return toleranceForNoisyMeanImpl (
683+ flakinessK , lower , upper , maxContributionsPerPartition , maxPartitionsContributed ,
684+ epsilon , delta , stats , getToleranceOfNoise )
685+ }
686+
660687// LaplaceToleranceForMean returns tolerances to be used in approxEquals for tests
661- // for mean to pass with 10⁻ᵏ flakiness.
688+ // for mean using Laplace Noise to pass with 10⁻ᵏ flakiness.
662689//
663690// The return values include the tolerances for count, normalized sum, and mean.
664691//
@@ -675,24 +702,46 @@ func ComplementaryGaussianTolerance(flakinessK, l0Sensitivity, lInfSensitivity,
675702func LaplaceToleranceForMean (
676703 flakinessK , lower , upper float64 , maxContributionsPerPartition , maxPartitionsContributed int64 ,
677704 epsilon float64 , stats VarianceStatistics ,
705+ ) (VarianceStatistics , error ) {
706+ getToleranceOfNoise := func (flakinessK , eps , delta float64 , sensitivify sensitivity ) float64 {
707+ return LaplaceTolerance (flakinessK , sensitivify .L1 , eps )
708+ }
709+ const delta float64 = 0 // Not used.
710+ return toleranceForNoisyMeanImpl (
711+ flakinessK , lower , upper , maxContributionsPerPartition , maxPartitionsContributed ,
712+ epsilon , delta , stats , getToleranceOfNoise )
713+ }
714+
715+ // toleranceForNoisyMeanImpl calculates the tolerance for noisy mean of a certain noise kind.
716+ //
717+ // The return values include the tolerances for count, normalized sum, and mean.
718+ //
719+ // - getToleranceOfNoise calculates the noise specific tolerance given flakiness and sensitivity.
720+ func toleranceForNoisyMeanImpl (
721+ flakinessK , lower , upper float64 ,
722+ maxContributionsPerPartition , maxPartitionsContributed int64 ,
723+ epsilon , delta float64 , stats VarianceStatistics ,
724+ getToleranceOfNoise func (flakinessK , eps , delta float64 , sensitivify sensitivity ) float64 ,
678725) (VarianceStatistics , error ) {
679726 // The term below is equivalent to -log_10(1-sqrt(1-1e-k)).
680727 // It is formulated this way to increase precision and to avoid having this term go to infinity.
681728 // Count and normalized sum uses the same following flakiness for simplicity.
682729 newFlakinessK := - math .Log10 (- math .Expm1 (0.5 * math .Log1p (- math .Pow (10 , - flakinessK ))))
683730 halfEpsilon := epsilon / 2
731+ halfDelta := delta / 2
684732
685733 computer := sensitivityComputer {
686734 Lower : lower ,
687735 Upper : upper ,
688736 MaxContributionsPerPartition : maxContributionsPerPartition ,
689737 MaxPartitionsContributed : maxPartitionsContributed ,
690738 }
691- l1Count := computer .SensitivitiesForCount (). L1
692- l1NormalizedSum := computer .SensitivitiesForNormalizedSum (). L1
739+ countSens := computer .SensitivitiesForCount ()
740+ normalizedSumSens := computer .SensitivitiesForNormalizedSum ()
693741
694- countTolerance := math .Ceil (LaplaceTolerance (newFlakinessK , l1Count , halfEpsilon ))
695- normalizedSumTolerance := LaplaceTolerance (newFlakinessK , l1NormalizedSum , halfEpsilon )
742+ countTolerance := math .Ceil (getToleranceOfNoise (newFlakinessK , halfEpsilon , halfDelta , countSens ))
743+ normalizedSumTolerance := getToleranceOfNoise (
744+ newFlakinessK , halfEpsilon , halfDelta , normalizedSumSens )
696745
697746 tolerances := VarianceStatistics {
698747 Count : countTolerance ,
0 commit comments