blob: 54928befb6d2b82ab08f780d0825ee0406d5ef4a [file] [log] [blame]
// Copyright 2021 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 (
"math"
"testing"
)
func TestGetPmfBinomialDistributionSimple(t *testing.T) {
pmf, err := getPmfBinomialDistribution(2, 0.5, 0)
if err != nil {
t.Errorf("getPmfBinomialDistributionibution returned error: %s", err.Error())
return
}
expectedPmf := make(ProbabilityMassFunction)
expectedPmf[0] = 0.25
expectedPmf[1] = 0.5
expectedPmf[2] = 0.25
if !deepEqualWithError(pmf, expectedPmf, 0.001) {
t.Errorf("Incorrect PMF computed by getPmfBinomialDistribution: expected %v, got %v", expectedPmf, pmf)
}
}
func TestGetPmfBinomialDistributionHardWithTruncation(t *testing.T) {
truncation := 0.01
pmf, err := getPmfBinomialDistribution(100, 0.5, truncation)
if err != nil {
t.Errorf("getPmfBinomialDistribution returned error: %s", err.Error())
return
}
error := 0.0001
if !equalWithError(pmf[2], 0, error) || !equalWithError(pmf[40], 0.0108, error) || !equalWithError(pmf[51], 0.0780, error) || !equalWithError(pmf[90], 0, error) {
t.Errorf("Incorrect PMF computed by getPmfBinomialDistribution: expected values 2:0, 40: 0.0108, 51: 0.0780, 90: 0, got %v", pmf)
}
sum := 0.0
for _, prob := range pmf {
sum += prob
}
if equalWithError(sum+truncation, 1.0, 0.0001) {
t.Errorf("Incorrect PMF computed by getPmfBinomialDistribution: expected mass of the truncated distribution to be close to %f, got %f", 1.0-truncation, sum)
}
}
func TestGetPmfShiftedBinomialDistributionSimple(t *testing.T) {
pmf, err := getPmfShiftedBinomialDistribution(2, 0.4, 0)
if err != nil {
t.Errorf("getPmfShiftedBinomialDistribution returned error: %s", err.Error())
return
}
expectedPmf := make(ProbabilityMassFunction)
expectedPmf[0] = 0.24
expectedPmf[1] = 0.52
expectedPmf[2] = 0.24
if !deepEqualWithError(pmf, expectedPmf, 0.001) {
t.Errorf("Incorrect PMF computed by getPmfBinomialDistribution: expected %v, got %v", expectedPmf, pmf)
}
}
func TestGetPmfShiftedBinomialDistributionHardWithTruncation(t *testing.T) {
truncation := 0.01
pmf, err := getPmfShiftedBinomialDistribution(100, 0.4, truncation)
if err != nil {
t.Errorf("getPmfShiftedBinomialDistribution returned error: %s", err.Error())
return
}
error := 0.001
if !equalWithError(pmf[5], 0, error) || !equalWithError(pmf[39], 0.079, error) || !equalWithError(pmf[50], 0.0112, error) || !equalWithError(pmf[70], 0, error) {
t.Errorf("Incorrect PMF computed by getPmfBinomialDistribution: expected values 5:0, 39: 0.079, 50: 0.0112, 70: 0, got %v", pmf)
}
sum := 0.0
for _, prob := range pmf {
sum += prob
}
if equalWithError(sum+truncation, 1.0, 0.0001) {
t.Errorf("Incorrect PMF computed by getPMFBinomialDistribution: expected mass of the truncated distribution to be close to %f, got %f", 1.0-truncation, sum)
}
}
func TestGetPrivacyLossDistribution(t *testing.T) {
discretization := 0.0001
expectedPmf := make(ProbabilityMassFunction)
expectedPmf[-8108] = 0.0092
expectedPmf[-6060] = 0.0415
expectedPmf[-4625] = 0.0261
expectedPmf[-3482] = 0.0622
expectedPmf[-2577] = 0.1175
expectedPmf[-2047] = 0.0225
expectedPmf[1] = 0.3149
expectedPmf[2049] = 0.0276
expectedPmf[2579] = 0.1521
expectedPmf[3484] = 0.0881
expectedPmf[4627] = 0.0415
expectedPmf[6062] = 0.0760
expectedPmf[8110] = 0.0207
resultPld, err := getPrivacyLossDistribution(3, 1, 0.4, 0.0, discretization)
if err != nil {
t.Errorf("getPrivacyLossDistribution returned error: %s", err.Error())
return
}
if !deepEqualWithError(expectedPmf, resultPld.pmf, 0.0001) {
t.Errorf("Incorrect result of getPrivacyLossDistribution without truncation: expected %v, got %v", expectedPmf, resultPld.pmf)
}
}
func TestGetPrivacyLossDistributionForLargePopulationTotalMass(t *testing.T) {
truncation := 0.000001
discretization := 0.001
resultPld, err := getPrivacyLossDistribution(300000, 1000, 0.4, truncation, discretization)
if err != nil {
t.Errorf("getPrivacyLossDistribution returned error: %s", err.Error())
return
}
sum := 0.0
for _, prob := range resultPld.pmf {
sum += prob
}
if equalWithError(sum+truncation, 1.0, 0.0000001) {
t.Errorf("Incorrect PMF computed by getPrivacyLossDistribution: expected mass of the truncated distribution to be close to %f, got %f", 1.0-truncation, sum)
}
}
func TestCorrectnessOfFindOptimalBitFlipProbability(t *testing.T) {
p1, err := findOptimalBitFlipProbability(1.0, -1, 64, 1, 0.01, 0.01)
if err != nil {
t.Errorf("findOptimalBitFlipProbability returned error: %s", err.Error())
return
}
p2, err := findOptimalBitFlipProbability(1.0, -1, 64, 20, 0.01, 0.01)
if err != nil {
t.Errorf("findOptimalBitFlipProbability returned error: %s", err.Error())
return
}
if p1 == p2 {
t.Errorf("Incorrectly computed optimal bit-flip probability for two different sparsity parameters: expected distinct values, got the same value")
}
}
func TestFindOptimalBitFlipProbability(t *testing.T) {
p, err := findOptimalBitFlipProbability(1.0, 0.01, 50, 3, 0.001, 0.00001)
if err != nil {
t.Errorf("findOptimalBitFlipProbability returned error: %s", err.Error())
return
}
if !equalWithError(p, 0.1989, 0.001) {
t.Errorf("Incorrectly computed optimal bit-flip probability: expected %f, got %f", 0.1989, p)
}
}
func TestSortednessOfCheckPrivacyResults(t *testing.T) {
wasTrue := false
for p := 0.0; p <= 0.5; p += 0.09 {
isPrivate, err := checkPrivacy(1.0, 15, 3, 0.01, p, 0.01)
if err != nil {
t.Errorf("checkPrivacy returned error: %s", err.Error())
return
}
if isPrivate {
wasTrue = true
} else {
if wasTrue {
t.Errorf("For bit-flip-probability %f we got that the algorithm is not DP, though for the previous value of bit-flip-probability %f the algorithm was private", p, p-0.01)
return
}
}
}
}
func TestGetDeltaForPrivacyLossDistributionDecreasingValues(t *testing.T) {
prevDivergence := math.Inf(+1)
for p := 0.01; p <= 0.5; p += 0.09 {
pld, err := getPrivacyLossDistribution(5, 3, p, 0.001*0.01, 0.01)
if err != nil {
t.Errorf("getPrivacyLossDistribution on p=%f returned error: %s", p, err.Error())
return
}
divergence := pld.getDeltaForPrivacyLossDistribution(1.0)
if divergence > prevDivergence {
t.Errorf("Divergence should decrease, but it increased with growing p from: %f to %f:", prevDivergence, divergence)
}
}
}
func TestRootMeanSquaredError(t *testing.T) {
rmse := rootMeanSquaredError(0.4, 30, 6)
if !equalWithError(127.9843, rmse, 0.001) {
t.Errorf("Incorrect result of rootMeanSquaredError: expected error to be %f got %f", 127.9843, rmse)
}
rmse = rootMeanSquaredError(0.3, 100, 4)
if !equalWithError(62.7495, rmse, 0.001) {
t.Errorf("Incorrect result of rootMeanSquaredError: expected error to be %f got %f", 62.7495, rmse)
}
}
func TestRealSumRMSE(t *testing.T) {
rmse := realSumRMSE(0.4, 35, 5)
if !equalWithError(21.5023, rmse, 0.001) {
t.Errorf("Incorrect result of realSumRMSE: expected error to be %f got %f", 21.5023, rmse)
}
rmse = realSumRMSE(0.2, 150, 9)
if !equalWithError(15.3307, rmse, 0.001) {
t.Errorf("Incorrect result of realSumRMSE: expected error to be %f got %f", 15.3307, rmse)
}
}
func TestPyramidNumber(t *testing.T) {
number := pyramidNumber(5.0)
if !equalWithError(55.0, number, 0.001) {
t.Errorf("Incorrect result of pyramidNumber: expected to get %f got %f", 55.0, number)
}
number = pyramidNumber(0.0)
if !equalWithError(0.0, number, 0.001) {
t.Errorf("Incorrect result of pyramidNumber: expected to get %f got %f", 0.0, number)
}
}
func TestFindOptimalDiscretization(t *testing.T) {
discretization := findOptimalDiscretization(0.1, 1000)
if 2 != discretization {
t.Errorf("Incorrect result of findOptimalDiscretization: expected discretization to be %d got %d", 2, discretization)
}
discretization = findOptimalDiscretization(0.01, 1000)
if 5 != discretization {
t.Errorf("Incorrect result of findOptimalDiscretization: expected discretization to be %d got %d", 5, discretization)
}
}
func TestFindPrivacyEncodingParameters(t *testing.T) {
p, discretization, err := FindPrivacyEncodingParameters(1.0, 50, 5)
if err != nil {
t.Errorf("FindPrivacyEncodingParameters returned error: %s", err.Error())
return
}
if !equalWithError(p, 0.223, 0.001) {
t.Errorf("Incorrectly computed optimal bit-flip probability: expected %f, got %f", 0.223, p)
}
if discretization != 2 {
t.Errorf("Incorrectly computed optimal discretization: expected %d, got %d", 2, discretization)
}
}