blob: 3031086e994694515bd06ebd86bad125a5cd6b37 [file] [log] [blame]
//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.google.privacy.differentialprivacy;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.Double.isFinite;
import com.google.privacy.differentialprivacy.proto.SummaryOuterClass.MechanismType;
import java.util.Objects;
import javax.annotation.Nullable;
/** Utilities which validate the correctness of DP parameters. */
public class DpPreconditions {
private DpPreconditions() {}
static void checkEpsilon(double epsilon) {
double epsilonLowerBound = 1.0 / (1L << 50);
checkArgument(
Double.isFinite(epsilon) && epsilon >= epsilonLowerBound,
"epsilon must be >= %s and < infinity. Provided value: %s",
epsilonLowerBound,
epsilon);
}
static void checkNoiseDelta(Double delta, Noise noise) {
if (noise.getMechanismType() == MechanismType.LAPLACE
|| noise.getMechanismType() == MechanismType.DISCRETE_LAPLACE) {
checkArgument(
delta == null,
"delta should not be set when (Discrete) Laplace noise is used. Provided value: %s",
delta);
} else if (noise.getMechanismType() == MechanismType.GAUSSIAN) {
checkNotNull(delta);
checkDelta(delta);
// For unknown noise, delta may or may not be null, but if it is not null it should be between
// 0 and 1.
} else if (delta != null) {
checkArgument(
delta >= 0 && delta < 1, "delta must be >= 0 and < 1. Provided value: %s", delta);
}
}
static void checkDelta(double delta) {
checkArgument(delta > 0 && delta < 1, "delta must be > 0 and < 1. Provided value: %s", delta);
}
static void checkSensitivities(int l0Sensitivity, double lInfSensitivity) {
checkL0Sensitivity(l0Sensitivity);
checkArgument(
Double.isFinite(lInfSensitivity) && lInfSensitivity > 0,
"lInfSensitivity must be > 0 and finite. Provided value: %s",
lInfSensitivity);
}
static void checkL0Sensitivity(int l0Sensitivity) {
checkArgument(
l0Sensitivity > 0, "l0Sensitivity must be > 0. Provided value: %s", l0Sensitivity);
}
static void checkL1Sensitivity(double l1Sensitivity) {
checkArgument(
Double.isFinite(l1Sensitivity) && l1Sensitivity > 0,
"l1Sensitivity must be > 0 and finite. Provided value: %s",
l1Sensitivity);
}
static void checkMaxPartitionsContributed(int maxPartitionsContributed) {
// maxPartitionsContributed is the user-facing parameter, which is technically the same as
// L0 sensitivity used by the noise internally.
checkL0Sensitivity(maxPartitionsContributed);
}
static void checkMaxContributionsPerPartition(int maxContributionsPerPartition) {
checkArgument(
maxContributionsPerPartition > 0,
"maxContributionsPerPartitions must be > 0. Provided value: %s",
maxContributionsPerPartition);
}
static void checkBounds(double lower, double upper) {
checkArgument(
upper >= lower,
"The upper bound should be greater than the lower bound. Provided values: "
+ "lower = %s upper = %s",
lower,
upper);
checkArgument(
isFinite(lower) && isFinite(upper),
"Lower and upper bounds should be finite. Provided values: " + "lower = %s upper = %s",
lower,
upper);
}
static void checkBoundsNotEqual(double lower, double upper) {
checkArgument(
upper != lower,
"Lower and upper bounds cannot be equal to each other. Provided values: "
+ "lower = %s upper = %s",
lower,
upper);
}
static void checkMergeDeltaAreEqual(@Nullable Double delta1, double delta2) {
if (delta1 != null) {
checkArgument(
Double.compare(delta1, delta2) == 0,
"Failed to merge: unequal values of delta. " + "delta1 = %s, delta2 = %s",
delta1,
delta2);
} else {
checkArgument(
Double.compare(delta2, 0.0) == 0,
"Failed to merge: unequal values of delta. " + "delta1 = %s, delta2 = %s",
delta1,
delta2);
}
}
static void checkMergeEpsilonAreEqual(double epsilon1, double epsilon2) {
checkArgument(
Double.compare(epsilon1, epsilon2) == 0,
"Failed to merge: unequal values of epsilon. " + "epsilon1 = %s, epsilon2 = %s",
epsilon1,
epsilon2);
}
static void checkMergeBoundsAreEqual(double lower1, double lower2, double upper1, double upper2) {
checkArgument(
Double.compare(lower1, lower2) == 0,
"Failed to merge: unequal lower bounds. " + "lower1 = %s, lower2 = %s",
lower1,
lower2);
checkArgument(
Double.compare(upper1, upper2) == 0,
"Failed to merge: unequal upper bounds. " + "upper1 = %s, upper2 = %s",
upper1,
upper2);
}
static void checkMergeMaxContributionsPerPartitionAreEqual(
int maxContributionsPerPartition1, int maxContributionsPerPartition2) {
checkArgument(
maxContributionsPerPartition1 == maxContributionsPerPartition2,
"Failed to merge: unequal values of maxContributionsPerPartition. "
+ "maxContributionsPerPartition1 = %s, maxContributionsPerPartition2 = %s",
maxContributionsPerPartition1,
maxContributionsPerPartition2);
}
static void checkMergeMaxPartitionsContributedAreEqual(
int maxPartitionsContributed1, int maxPartitionsContributed2) {
checkArgument(
maxPartitionsContributed1 == maxPartitionsContributed2,
"Failed to merge: unequal values of maxPartitionsContributed. "
+ "maxPartitionsContributed1 = %s, maxPartitionsContributed2 = %s",
maxPartitionsContributed1,
maxPartitionsContributed2);
}
static void checkMergeMechanismTypesAreEqual(MechanismType type1, MechanismType type2) {
checkArgument(
Objects.equals(type1, type2),
"Failed to merge: unequal mechanism types. type1 = %s, type2 = %s",
type1,
type2);
}
static void checkAlpha(double alpha) {
checkArgument(
0 < alpha && alpha < 1,
"alpha should be strictly between 0 and 1. Provided value: %s",
alpha);
}
static void checkNoiseComputeQuantileArguments(
Noise noise,
double rank,
int l0Sensitivity,
double lInfSensitivity,
double epsilon,
@Nullable Double delta) {
checkSensitivities(l0Sensitivity, lInfSensitivity);
checkEpsilon(epsilon);
checkNoiseDelta(delta, noise);
checkArgument(rank > 0 && rank < 1, "rank must be > 0 and < 1. Provided value: %s", rank);
}
}