blob: 00ab96327aac612b80c937ded482fb5e0107da90 [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_COUNT_H_
#define DIFFERENTIAL_PRIVACY_ALGORITHMS_COUNT_H_
#include "google/protobuf/any.pb.h"
#include "absl/status/status.h"
#include "base/statusor.h"
#include "algorithms/algorithm.h"
#include "algorithms/numerical-mechanisms.h"
#include "algorithms/util.h"
#include "proto/summary.pb.h"
#include "base/canonical_errors.h"
#include "base/status_macros.h"
namespace differential_privacy {
// Count the number of elements in a set, with differentially private noise.
template <typename T>
class Count : public Algorithm<T> {
public:
class Builder;
void AddEntry(const T& v) override { AddMultipleEntries(v, 1); }
base::StatusOr<ConfidenceInterval> NoiseConfidenceInterval(
double confidence_level, double privacy_budget = 1) override {
return mechanism_->NoiseConfidenceInterval(confidence_level,
privacy_budget);
}
// Create and return summary containing the count.
Summary Serialize() override {
// Create CountSummary.
CountSummary count_summ;
count_summ.set_count(count_);
// Create Summary.
Summary summary;
summary.mutable_data()->PackFrom(count_summ);
return summary;
}
// Add count from serialized data.
absl::Status Merge(const Summary& summary) override {
if (!summary.has_data()) {
return absl::InternalError("Cannot merge summary with no count data.");
}
// Add counts.
CountSummary count_summary;
if (!summary.data().UnpackTo(&count_summary)) {
return absl::InternalError("Count summary unable to be unpacked.");
}
SafeAdd<uint64_t>(count_, count_summary.count(), &count_);
return absl::OkStatus();
}
int64_t MemoryUsed() override {
int64_t memory = sizeof(Count<T>);
if (mechanism_) {
memory += mechanism_->MemoryUsed();
}
return memory;
}
protected:
base::StatusOr<Output> GenerateResult(double privacy_budget,
double noise_interval_level) override {
Output output;
int64_t countWithNoise;
SafeCastFromDouble(std::round(mechanism_->AddNoise(count_, privacy_budget)),
countWithNoise);
AddToOutput<int64_t>(&output, countWithNoise);
base::StatusOr<ConfidenceInterval> interval =
NoiseConfidenceInterval(noise_interval_level, privacy_budget);
if (interval.ok()) {
*(output.mutable_error_report()->mutable_noise_confidence_interval()) =
interval.value();
}
return output;
}
void ResetState() override { count_ = 0; }
uint64_t GetCount() const { return count_; }
// The constructor and count_ are non-private for testing.
Count(double epsilon, std::unique_ptr<NumericalMechanism> mechanism)
: Algorithm<T>(epsilon), count_(0), mechanism_(std::move(mechanism)) {}
private:
void AddMultipleEntries(const T& v, uint64_t num_of_entries) {
SafeAdd<uint64_t>(count_, num_of_entries, &count_);
}
// Friend class for testing only
friend class CountTestPeer;
uint64_t count_;
std::unique_ptr<NumericalMechanism> mechanism_;
};
template <typename T>
class Count<T>::Builder
: public AlgorithmBuilder<T, Count<T>, Count<T>::Builder> {
private:
using AlgorithmBuilder =
differential_privacy::AlgorithmBuilder<T, Count<T>, Count<T>::Builder>;
base::StatusOr<std::unique_ptr<Count<T>>> BuildAlgorithm() override {
std::unique_ptr<NumericalMechanism> mechanism;
ASSIGN_OR_RETURN(mechanism, AlgorithmBuilder::UpdateAndBuildMechanism());
return absl::WrapUnique(new Count<T>(AlgorithmBuilder::GetEpsilon().value(),
std::move(mechanism)));
}
};
} // namespace differential_privacy
#endif // DIFFERENTIAL_PRIVACY_ALGORITHMS_COUNT_H_