blob: 32f1727d1baf9e87496c3e4ae602fd0cd5db9cf5 [file] [log] [blame]
//
// Copyright 2019 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.
//
#ifndef DIFFERENTIAL_PRIVACY_ALGORITHMS_BOUNDED_STANDARD_DEVIATION_H_
#define DIFFERENTIAL_PRIVACY_ALGORITHMS_BOUNDED_STANDARD_DEVIATION_H_
#include <cmath>
#include <memory>
#include <type_traits>
#include <utility>
#include <cstdint>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "algorithms/algorithm.h"
#include "algorithms/approx-bounds.h"
#include "algorithms/bounded-algorithm.h"
#include "algorithms/bounded-variance.h"
#include "algorithms/numerical-mechanisms.h"
#include "algorithms/util.h"
#include "proto/util.h"
#include "proto/data.pb.h"
#include "proto/summary.pb.h"
#include "base/status_macros.h"
// Bounded Stddev is deprecated in favor of using variance and taking the sqrt
// of the result.
namespace differential_privacy {
// Incrementally provides a differentially private standard deviation for values
// in the range [lower..upper]. Values outside of this range will be clamped so
// they lie in the range. The output will also be clamped between 0 and (upper -
// lower).
//
// The implementation simply computes the bounded variance and takes the square
// root, which is differentially private by the post-processing theorem. It
// relies on the fact that the bounded variance algorithm guarantees that the
// output is non-negative.
template <typename T>
class ABSL_DEPRECATED(
"Use BoundedVariance instead and take the sqrt of the result")
BoundedStandardDeviation : public Algorithm<T> {
static_assert(
std::is_arithmetic<T>::value,
"BoundedStandardDeviation can only be used for arithmetic types");
public:
// Builder for BoundedStandardDeviation algorithm.
class ABSL_DEPRECATED(
"Use BoundedVariance instead and take the sqrt of the result") Builder;
void AddEntry(const T& t) override { variance_->AddEntry(t); }
// Returns a BoundedVarianceSummary.
Summary Serialize() const override { return variance_->Serialize(); }
// Merges from BoundedVarianceSummary.
absl::Status Merge(const Summary& summary) override {
return variance_->Merge(summary);
}
int64_t MemoryUsed() override {
int64_t memory = sizeof(BoundedStandardDeviation<T>);
if (variance_) {
memory += variance_->MemoryUsed();
}
return memory;
}
double GetEpsilon() const override { return variance_->GetEpsilon(); }
// Returns the epsilon used to calculate approximate bounds. If approximate
// bounds are not used, returns 0.
double GetBoundingEpsilon() const { return variance_->GetBoundingEpsilon(); }
// Returns the epsilon used to calculate the noisy mean. If bounds are
// specified explicitly, this will be the total epsilon used by the algorithm.
double GetAggregationEpsilon() const {
return variance_->GetAggregationEpsilon();
}
private:
BoundedStandardDeviation(const double epsilon,
std::unique_ptr<BoundedVariance<T>> variance)
: Algorithm<T>(epsilon), variance_(std::move(variance)) {}
absl::StatusOr<Output> GenerateResult(double noise_interval_level) override {
ASSIGN_OR_RETURN(Output variance_output,
variance_->PartialResult(noise_interval_level));
double stdev = std::sqrt(GetValue<double>(variance_output));
SetValue<double>(variance_output.mutable_elements(0)->mutable_value(),
stdev);
return variance_output;
}
void ResetState() override { variance_->Reset(); }
std::unique_ptr<BoundedVariance<T>> variance_;
};
template <typename T>
class BoundedStandardDeviation<T>::Builder {
public:
BoundedStandardDeviation<T>::Builder& SetEpsilon(double epsilon) {
variance_builder_.SetEpsilon(epsilon);
return *this;
}
BoundedStandardDeviation<T>::Builder& SetDelta(double delta) {
variance_builder_.SetDelta(delta);
return *this;
}
BoundedStandardDeviation<T>::Builder& SetMaxPartitionsContributed(
int max_partitions_contributed) {
variance_builder_.SetMaxPartitionsContributed(max_partitions_contributed);
return *this;
}
BoundedStandardDeviation<T>::Builder& SetMaxContributionsPerPartition(
int max_contributions_per_partition) {
variance_builder_.SetMaxContributionsPerPartition(
max_contributions_per_partition);
return *this;
}
BoundedStandardDeviation<T>::Builder& SetUpper(T upper) {
variance_builder_.SetUpper(upper);
return *this;
}
BoundedStandardDeviation<T>::Builder& SetLower(T lower) {
variance_builder_.SetLower(lower);
return *this;
}
BoundedStandardDeviation<T>::Builder& SetApproxBounds(
std::unique_ptr<ApproxBounds<T>> approx_bounds) {
variance_builder_.SetApproxBounds(std::move(approx_bounds));
return *this;
}
BoundedStandardDeviation<T>::Builder& SetLaplaceMechanism(
std::unique_ptr<NumericalMechanismBuilder> builder) {
variance_builder_.SetLaplaceMechanism(std::move(builder));
return *this;
}
absl::StatusOr<std::unique_ptr<BoundedStandardDeviation<T>>> Build() {
ASSIGN_OR_RETURN(std::unique_ptr<BoundedVariance<T>> variance,
variance_builder_.Build());
const double epsilon = variance->GetEpsilon();
return absl::WrapUnique(
new BoundedStandardDeviation(epsilon, std::move(variance)));
}
private:
typename BoundedVariance<T>::Builder variance_builder_;
};
} // namespace differential_privacy
#endif // DIFFERENTIAL_PRIVACY_ALGORITHMS_BOUNDED_STANDARD_DEVIATION_H_