Update error calculator discretization parameter

Update the discretization parameter to match the work in fxr/485978 and
fxr/486957.

Change-Id: I9534e832b35cd61179ff791d4e0e773a5d886dbd
Reviewed-on: https://fuchsia-review.googlesource.com/c/cobalt/+/487217
Commit-Queue: Jared Weinstein <jaredweinstein@google.com>
Reviewed-by: Laura Peskin <pesk@google.com>
diff --git a/src/bin/config_parser/src/privacy/error_calculator.go b/src/bin/config_parser/src/privacy/error_calculator.go
index 174ae1a..4ca2458 100644
--- a/src/bin/config_parser/src/privacy/error_calculator.go
+++ b/src/bin/config_parser/src/privacy/error_calculator.go
@@ -45,8 +45,12 @@
 	if err != nil {
 		return -1, err
 	}
+	rangeSize, err := GetIntegerRangeSizeForReport(report)
+	if err != nil {
+		return -1, err
+	}
 	populationConstant := e.ParamsCalc.Constants.population
-	privacyEncodingParams, err := e.ParamsCalc.GetPrivacyEncodingParams(epsilon, populationConstant, sparsity)
+	privacyEncodingParams, err := e.ParamsCalc.GetPrivacyEncodingParams(epsilon, populationConstant, sparsity, rangeSize)
 	if err != nil {
 		return -1, err
 	}
diff --git a/src/bin/config_parser/src/privacy/error_calculator_test.go b/src/bin/config_parser/src/privacy/error_calculator_test.go
index 47e9cbb..b2a85f8 100644
--- a/src/bin/config_parser/src/privacy/error_calculator_test.go
+++ b/src/bin/config_parser/src/privacy/error_calculator_test.go
@@ -137,14 +137,14 @@
 		{args{&testMetric, &hourlyValueHistogram, 1, 20000, 0}, true, 34.19422624116276},
 
 		// Multi-contribution reports
-		{args{&testMetric, &fleetwideOccurrenceCount, 1, 10000, 0}, true, 211.57489543860999},
-		{args{&testMetric, &fleetwideOccurrenceCount, 10, 10000, 0}, true, 149.7228828879947},
-		{args{&testMetric, &fleetwideOccurrenceCount, 1, 20000, 0}, true, 299.2120865869517},
+		{args{&testMetric, &fleetwideOccurrenceCount, 1, 10000, 0}, true, 242.85533534365706},
+		{args{&testMetric, &fleetwideOccurrenceCount, 10, 10000, 0}, true, 214.6542376007753},
+		{args{&testMetric, &fleetwideOccurrenceCount, 1, 20000, 0}, true, 343.4493089376658},
 		{args{&testMetric, &fleetwideOccurrenceCountHighMax, 1, 10000, 0}, true, 1004.9807533333975},
-		{args{&testMetric, &fleetwideOccurrenceCountNegativeValue, 1, 10000, 0}, true, 211.57489543860999},
-		{args{&testMetric, &fleetwideHistogram, 1, 10000, 0}, true, 264.4686192982625},
-		{args{&testMetric, &fleetwideHistogram, 10, 10000, 0}, true, 187.15360360999338},
-		{args{&testMetric, &fleetwideHistogram, 1, 20000, 0}, true, 374.0151082336897},
+		{args{&testMetric, &fleetwideOccurrenceCountNegativeValue, 1, 10000, 0}, true, 242.85533534365706},
+		{args{&testMetric, &fleetwideHistogram, 1, 10000, 0}, true, 280.3775386576355},
+		{args{&testMetric, &fleetwideHistogram, 10, 10000, 0}, true, 235.47432404848092},
+		{args{&testMetric, &fleetwideHistogram, 1, 20000, 0}, true, 396.51371775441487},
 		{args{&testMetric, &fleetwideHistogramHighMax, 1, 10000, 0}, true, 1057.87447719305},
 
 		// Mean reports
@@ -157,10 +157,10 @@
 		// {args{&testMetric, &hourlyValueNumericStats, 1, 20000, 500}, true, 0.20996453488325503},
 		// {args{&testMetric, &hourlyValueNumericStats, 1, 10000, 2000}, true, 0.03425744055252169},
 
-		{args{&testMetric, &fleetwideMeans, 1, 10000, 500}, true, 1034.0131324817698},
-		{args{&testMetric, &fleetwideMeans, 10, 10000, 500}, true, 426.22967217469716},
-		{args{&testMetric, &fleetwideMeans, 1, 20000, 500}, true, 1619.5676003943095},
-		{args{&testMetric, &fleetwideMeans, 1, 10000, 2000}, true, 1.4456690853472534},
+		{args{&testMetric, &fleetwideMeans, 1, 10000, 500}, true, 1140.9529271415656},
+		{args{&testMetric, &fleetwideMeans, 10, 10000, 500}, true, 819.2029589502301},
+		{args{&testMetric, &fleetwideMeans, 1, 20000, 500}, true, 1702.9973681087847},
+		{args{&testMetric, &fleetwideMeans, 1, 10000, 2000}, true, 1.5632868282802292},
 		{args{&testMetric, &fleetwideMeansHighMaxCount, 1, 10000, 500}, true, 2373.764851498005},
 		{args{&testMetric, &fleetwideMeansHighMaxCount, 10, 10000, 500}, true, 2239.957602630985},
 		{args{&testMetric, &fleetwideMeansHighMaxCount, 1, 20000, 500}, true, 2453.988452255676},
diff --git a/src/bin/config_parser/src/privacy/privacy_encoding_params.go b/src/bin/config_parser/src/privacy/privacy_encoding_params.go
index 80d038d..5beb245 100644
--- a/src/bin/config_parser/src/privacy/privacy_encoding_params.go
+++ b/src/bin/config_parser/src/privacy/privacy_encoding_params.go
@@ -207,10 +207,7 @@
 }
 
 // GetPrivacyEncodingParamsForReport looks up the corresponding PrivacyEncodingParams from |calc|'s
-// paramMap, given a |metric| and |report|. If |report| has an integer range size which is smaller
-// than the number of index points computed by |calc|, this function uses that integer range size as
-// the NumIndexPoints field of the returned PrivacyEncodingParams in order to avoid incurring
-// unnecessary rounding error.
+// paramMap, given a |metric| and |report|.
 //
 // If paramMap does not have a key which exactly matches the values drawn from |metric|, |report|,
 // and |calc.constants|, then parameters are returned for the closest key which provides at least as
@@ -226,29 +223,30 @@
 		return params, err
 	}
 
-	rangeSize, err := getIntegerRangeSizeForReport(report)
+	rangeSize, err := GetIntegerRangeSizeForReport(report)
 	if err != nil {
 		return params, err
 	}
 
-	params, err = calc.GetPrivacyEncodingParams(epsilon, calc.Constants.population, sparsity)
+	return calc.GetPrivacyEncodingParams(epsilon, calc.Constants.population, sparsity, rangeSize)
 	if err != nil {
 		return params, err
 	}
 
-	if rangeSize < uint64(params.NumIndexPoints) {
-		params.NumIndexPoints = uint32(rangeSize)
-	}
-
 	return params, err
 }
 
-// Given an |epsilon|, |population|, and |sparsity|, looks up the corresponding PrivacyEncodingParams from |calc|'s paramMap.
+// Given an |epsilon|, |population|, and |sparsity|, looks up the corresponding
+// PrivacyEncodingParams from |calc|'s paramMap.
+//
+// If |rangeSize| is smaller than the number of index points computed by |calc|, this
+// function uses that |rangeSize| as the NumIndexPoints field of the returned
+// PrivacyEncodingParams in order to avoid incurring unnecessary rounding error.
 //
 // If paramMap does not have a key which exactly matches the tuple (|epsilon|, |population|, |sparsity|),
-// then parameters are returned for the closest key which provides |epsilon|-differential privacy (in the shuffled model) or better.
-// See getBestMappedKey for more details.
-func (calc *PrivacyEncodingParamsCalculator) GetPrivacyEncodingParams(epsilon float64, population uint64, sparsity uint64) (params PrivacyEncodingParams, err error) {
+// then parameters are returned for the closest key which provides |epsilon|-differential privacy
+// (in the shuffled model) or better. See getBestMappedKey for more details.
+func (calc *PrivacyEncodingParamsCalculator) GetPrivacyEncodingParams(epsilon float64, population uint64, sparsity uint64, rangeSize uint64) (params PrivacyEncodingParams, err error) {
 	key, err := getBestMappedKey(epsilon, population, sparsity, &calc.mapped)
 	if err != nil {
 		return params, err
@@ -259,7 +257,10 @@
 		return params, fmt.Errorf("no params found for key: (epsilon=%f, population=%d, sparsity=%d)", key.epsilon, key.population, key.sparsity)
 	}
 
-	return calc.paramMap[key], nil
+	if rangeSize < uint64(params.NumIndexPoints) {
+		params.NumIndexPoints = uint32(rangeSize)
+	}
+	return params, nil
 }
 
 // Returns the number of valid integer values for |report|. For FleetwideOccurrenceCounts,
@@ -273,7 +274,7 @@
 //
 // A FleetwideMeans report has two separate configured ranges: one for sum values and another for
 // count values. The returned range size is the maximum of the two range sizes.
-func getIntegerRangeSizeForReport(report *config.ReportDefinition) (rangeSize uint64, err error) {
+func GetIntegerRangeSizeForReport(report *config.ReportDefinition) (rangeSize uint64, err error) {
 	switch report.ReportType {
 	case config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
 		config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
diff --git a/src/bin/config_parser/src/privacy/privacy_encoding_params_test.go b/src/bin/config_parser/src/privacy/privacy_encoding_params_test.go
index 098655a..da98652 100644
--- a/src/bin/config_parser/src/privacy/privacy_encoding_params_test.go
+++ b/src/bin/config_parser/src/privacy/privacy_encoding_params_test.go
@@ -170,7 +170,7 @@
 		{&unsetReportTypeReport, false, 0},
 	}
 	for _, test := range tests {
-		result, err := getIntegerRangeSizeForReport(test.report)
+		result, err := GetIntegerRangeSizeForReport(test.report)
 		if test.valid && err != nil {
 			t.Errorf("getIntegerRangeSizeForReport() failed for report %s: %v", test.report.ReportName, err)
 		} else if !test.valid && err == nil {
@@ -478,6 +478,7 @@
 		epsilon    float64
 		population uint64
 		sparsity   uint64
+		rangeSize  uint64
 	}
 	var tests = []struct {
 		input    args
@@ -486,20 +487,22 @@
 	}{
 		// Valid input:
 		// The best-match key is {1.0, 10000, 10}.
-		{args{1.0, 15000, 5}, true, PrivacyEncodingParams{0.019537480548024178, 4}},
+		{args{1.0, 15000, 5, 4}, true, PrivacyEncodingParams{0.019537480548024178, 4}},
 		// The best-match key is {5.0, 10000, 1}.
-		{args{10.0, 15000, 1}, true, PrivacyEncodingParams{0.000906200148165226, 12}},
+		{args{10.0, 15000, 1, 12}, true, PrivacyEncodingParams{0.000906200148165226, 12}},
+		// The rangeSize is smaller than numIndexPoints.
+		{args{10.0, 15000, 1, 6}, true, PrivacyEncodingParams{0.000906200148165226, 6}},
 
 		// Invalid input:
 		// The target epsilon is smaller than all mapped epsilons.
-		{args{0.5, 10000, 1}, false, PrivacyEncodingParams{}},
+		{args{0.5, 10000, 1, 1}, false, PrivacyEncodingParams{}},
 		// The target population is smaller than all mapped populations.
-		{args{1.0, 5000, 1}, false, PrivacyEncodingParams{}},
+		{args{1.0, 5000, 1, 1}, false, PrivacyEncodingParams{}},
 		// The target sparsity is larger than all mapped sparsities.
-		{args{1.0, 10000, 100}, false, PrivacyEncodingParams{}},
+		{args{1.0, 10000, 100, 1}, false, PrivacyEncodingParams{}},
 	}
 	for _, test := range tests {
-		result, err := calc.GetPrivacyEncodingParams(test.input.epsilon, test.input.population, test.input.sparsity)
+		result, err := calc.GetPrivacyEncodingParams(test.input.epsilon, test.input.population, test.input.sparsity, test.input.rangeSize)
 		if test.valid && err != nil {
 			t.Errorf("GetPrivacyEncodingParams(%v, %v, %v) failed: %v", test.input.epsilon, test.input.population, test.input.sparsity, err)
 		} else if !test.valid && err == nil {