blob: 07d6c78b98e8a62bbbb0bfb80538d8510258fb99 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package privacy
import (
"config"
"fmt"
"math"
)
type ErrorCalculator struct {
ParamsCalc PrivacyEncodingParamsCalculator
}
// Public factory method for creating an ErrorCalculator given a
// PrivacyEncodingParamsCalculator.
func NewErrorCalculator(paramsCalc PrivacyEncodingParamsCalculator) *ErrorCalculator {
return &ErrorCalculator{paramsCalc}
}
// Public factory method for creating an ErrorCalculator given the file path
// of the PrivacyEncodingParams.
func NewErrorCalculatorFromPrivacyParams(privacyParamsPath string) (*ErrorCalculator, error) {
paramsCalculator, err := NewPrivacyEncodingParamsCalculator(privacyParamsPath)
if err != nil {
return nil, err
}
errorCalculator := NewErrorCalculator(*paramsCalculator)
if err != nil {
return nil, err
}
return errorCalculator, nil
}
// Given a |metric|, |report|, and |params|, estimates the report row error.
//
// Row error is temporarily -1 unless |epsilon| is 0 due to deprecated Rappor
// encoding scheme.
//
// TODO(b/278932979): update this comment once error calculation is implemented for
// Poisson encoding scheme.
func (e *ErrorCalculator) Estimate(metric *config.MetricDefinition, report *config.ReportDefinition, epsilon float64, population uint64, minDenominatorEstimate uint64) (estimate float64, err error) {
if epsilon == 0 {
return 0, nil
}
var errorEstimate float64
switch report.GetReportType() {
case config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS:
fallthrough
case config.ReportDefinition_UNIQUE_DEVICE_COUNTS:
fallthrough
case config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS:
fallthrough
case config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS:
fallthrough
case config.ReportDefinition_FLEETWIDE_HISTOGRAMS:
fallthrough
case config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS:
fallthrough
case config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS:
fallthrough
case config.ReportDefinition_FLEETWIDE_MEANS:
fallthrough
default:
reportType := config.ReportDefinition_ReportType_name[int32(report.GetReportType())]
return -1, fmt.Errorf("error estimation is not supported for reports of type %s", reportType)
}
if math.IsNaN(errorEstimate) || math.IsInf(errorEstimate, 0) {
return errorEstimate, fmt.Errorf("error estimation failed to return valid result due to an invalid or missing field")
}
return errorEstimate, nil
}
func meanReportConfigurationError(report *config.ReportDefinition, minDenominatorEstimate uint64) error {
if minDenominatorEstimate == 0 {
return fmt.Errorf("user estimate for lower bound on unnoised denominator required for %s", report.GetReportType())
}
if report.MaxValue == 0 && report.MinValue == 0 {
return fmt.Errorf("MinValue and MaxValue required to estimate error for %s", report.GetReportType())
}
return nil
}