Skip to content

Commit

Permalink
Update serialization in C++ (still backwards compatible)
Browse files Browse the repository at this point in the history
C++:
* Refactor code and introduced `BoundsProvider` making it easier to
  implement new bounding algorithms.
* Add `ApproxBoundsAsBoundsProvider` wrapper for using `ApproxBounds`
  with the new interface.
* Add new serialization for `BoundsProvider`.
* Move reconstruction logic for clamped bounds into separate class.
* Change serialization for sum, mean, and variance which is still
  fully backwards compatible (for now).

PoB:
* New sharded public partitions implementation is now by default on.

Proto changes:
* Deprecate `bounds_summary` field in all protos (still populated)
* Add new message and field to support adding new `BoundsProvider`

PipelineDP4j:
* Make flatten work with local collections
* Sort ranks in quantiles
* Allow relative budget spec for group selection

Python DP Accounting:
* Add tests for `AdditiveNoisePrivacyLoss` classes

Change-Id: Ie66e82fc222597a9a1c817bf118d014b7b144fdd
GitOrigin-RevId: 6bcc4974328347eb2eaa3955795c7965a255a536
  • Loading branch information
Differential Privacy Team authored and dibakch committed Jan 29, 2025
1 parent d23c270 commit efc926c
Show file tree
Hide file tree
Showing 36 changed files with 1,887 additions and 260 deletions.
4 changes: 0 additions & 4 deletions cc/accounting/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ cc_library(
deps = [
":convolution",
"//accounting/common",
"@boost//:lexical_cast",
"@boost//:math",
"@boost//:multiprecision",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
Expand Down Expand Up @@ -139,9 +137,7 @@ cc_library(
deps = [
":pld",
"//accounting/common",
"@boost//:lexical_cast",
"@boost//:math",
"@boost//:multiprecision",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings:str_format",
Expand Down
63 changes: 60 additions & 3 deletions cc/algorithms/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ cc_test(
],
)

cc_library(
name = "bounds-provider",
hdrs = ["bounds-provider.h"],
visibility = ["//visibility:private"],
deps = [
"//algorithms/internal:clamped-calculation-without-bounds",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_differential_privacy//proto:data_cc_proto",
"@com_google_differential_privacy//proto:summary_cc_proto",
],
)

cc_library(
name = "order-statistics",
hdrs = ["order-statistics.h"],
Expand Down Expand Up @@ -139,11 +152,13 @@ cc_library(
deps = [
":algorithm",
":approx-bounds",
":approx-bounds-as-bounds-provider",
":bounds-provider",
":numerical-mechanisms",
":util",
"//algorithms/internal:clamped-calculation-without-bounds",
"//proto:util-lib",
"@com_google_absl//absl/log",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
Expand All @@ -159,16 +174,17 @@ cc_test(
size = "small",
srcs = ["bounded-sum_test.cc"],
deps = [
":algorithm",
":approx-bounds",
":approx-bounds-as-bounds-provider",
":bounded-sum",
":numerical-mechanisms",
":numerical-mechanisms-testing",
"//base/testing:proto_matchers",
"//base/testing:status_matchers",
"//proto:util-lib",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_differential_privacy//proto:data_cc_proto",
"@com_google_googletest//:gtest_main",
],
Expand All @@ -181,9 +197,12 @@ cc_library(
deps = [
":algorithm",
":approx-bounds",
":approx-bounds-as-bounds-provider",
":bounds-provider",
":numerical-mechanisms",
":util",
"//algorithms/internal:bounded-mean-ci",
"//algorithms/internal:clamped-calculation-without-bounds",
"//proto:util-lib",
"@com_google_absl//absl/log",
"@com_google_absl//absl/memory",
Expand All @@ -205,7 +224,9 @@ cc_test(
srcs = ["bounded-mean_test.cc"],
deps = [
":approx-bounds",
":approx-bounds-as-bounds-provider",
":bounded-mean",
":bounds-provider",
":numerical-mechanisms",
":numerical-mechanisms-testing",
"//base/testing:proto_matchers",
Expand Down Expand Up @@ -244,8 +265,11 @@ cc_library(
deps = [
":algorithm",
":approx-bounds",
":approx-bounds-as-bounds-provider",
":bounds-provider",
":numerical-mechanisms",
":util",
"//algorithms/internal:clamped-calculation-without-bounds",
"//proto:util-lib",
"@com_google_absl//absl/log",
"@com_google_absl//absl/log:check",
Expand All @@ -265,6 +289,7 @@ cc_test(
srcs = ["bounded-variance_test.cc"],
deps = [
":approx-bounds",
":approx-bounds-as-bounds-provider",
":bounded-variance",
":numerical-mechanisms",
":numerical-mechanisms-testing",
Expand Down Expand Up @@ -496,6 +521,7 @@ cc_library(
":algorithm",
":numerical-mechanisms",
":util",
"//algorithms/internal:clamped-calculation-without-bounds",
"//proto:util-lib",
"@com_google_absl//absl/log",
"@com_google_absl//absl/memory",
Expand All @@ -516,6 +542,7 @@ cc_test(
":approx-bounds",
":numerical-mechanisms",
":numerical-mechanisms-testing",
"//algorithms/internal:clamped-calculation-without-bounds",
"//base/testing:proto_matchers",
"//base/testing:status_matchers",
"@com_google_absl//absl/memory",
Expand All @@ -527,6 +554,36 @@ cc_test(
],
)

cc_library(
name = "approx-bounds-as-bounds-provider",
hdrs = ["approx-bounds-as-bounds-provider.h"],
visibility = ["//visibility:private"],
deps = [
":approx-bounds",
":bounds-provider",
"//algorithms/internal:clamped-calculation-without-bounds",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_cc_differential_privacy//base:status_macros",
],
)

cc_test(
name = "approx-bounds-as-bounds-provider_test",
srcs = ["approx-bounds-as-bounds-provider_test.cc"],
deps = [
":approx-bounds",
":approx-bounds-as-bounds-provider",
":bounds-provider",
"//algorithms/internal:clamped-calculation-without-bounds",
"//base/testing:status_matchers",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:status_matchers",
"@com_google_absl//absl/status:statusor",
"@com_google_googletest//:gtest_main",
],
)

cc_library(
name = "bounded-algorithm",
hdrs = ["bounded-algorithm.h"],
Expand Down
104 changes: 104 additions & 0 deletions cc/algorithms/approx-bounds-as-bounds-provider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// Copyright 2024 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_CPP_ALGORITHMS_APPROX_BOUNDS_AS_BOUNDS_PROVIDER_H_
#define DIFFERENTIAL_PRIVACY_CPP_ALGORITHMS_APPROX_BOUNDS_AS_BOUNDS_PROVIDER_H_

#include <cstdint>
#include <memory>
#include <utility>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "algorithms/approx-bounds.h"
#include "algorithms/bounds-provider.h"
#include "algorithms/internal/clamped-calculation-without-bounds.h"
#include "base/status_macros.h"

namespace differential_privacy {

// Adapter to use ApproxBounds as a BoundsProvider. Wraps an ApproxBounds
// object.
template <typename T>
class ApproxBoundsAsBoundsProvider final : public BoundsProvider<T> {
public:
explicit ApproxBoundsAsBoundsProvider(
std::unique_ptr<ApproxBounds<T>> approx_bounds)
: approx_bounds_(std::move(approx_bounds)) {}

void AddEntry(const T& entry) override { approx_bounds_->AddEntry(entry); }

virtual absl::StatusOr<BoundsResult<T>> FinalizeAndCalculateBounds()
override {
ASSIGN_OR_RETURN(Output output, approx_bounds_->PartialResult());
BoundsResult<T> result;
result.lower_bound = GetValue<T>(output.elements(0).value());
result.upper_bound = GetValue<T>(output.elements(1).value());
return result;
}

BoundingReport GetBoundingReport(
const BoundsResult<T>& bounds_result) override {
return approx_bounds_->GetBoundingReport(bounds_result.lower_bound,
bounds_result.upper_bound);
}

void Reset() override { approx_bounds_->Reset(); }

int64_t MemoryUsed() const override {
return sizeof(*this) + approx_bounds_->MemoryUsed();
}

double GetEpsilon() const override { return approx_bounds_->GetEpsilon(); }

double GetDelta() const override { return approx_bounds_->GetDelta(); }

BoundsSummary Serialize() const override {
Summary summary = approx_bounds_->Serialize();
BoundsSummary bounds_summary;
summary.data().UnpackTo(bounds_summary.mutable_approx_bounds_summary());
return bounds_summary;
}

absl::Status Merge(const BoundsSummary& bounds_summary) {
if (!bounds_summary.has_approx_bounds_summary()) {
return absl::InternalError("approx_bounds_summary must be set");
}
Summary summary;
const bool pack_successful = summary.mutable_data()->PackFrom(
bounds_summary.approx_bounds_summary());
if (!pack_successful) {
return absl::InternalError("Cannot pack bounds summary");
}
return approx_bounds_->Merge(summary);
}

std::unique_ptr<internal::ClampedCalculationWithoutBounds<T>>
CreateClampedCalculationWithoutBounds() const override {
return approx_bounds_->CreateClampedCalculationWithoutBounds();
}

// Returns a pointer to the wrapped ApproxBounds object. Does not transfer
// ownership. Only use for testing.
ApproxBounds<T>* GetApproxBoundsForTesting() { return approx_bounds_.get(); }

private:
std::unique_ptr<ApproxBounds<T>> approx_bounds_;
};

} // namespace differential_privacy

#endif // DIFFERENTIAL_PRIVACY_CPP_ALGORITHMS_APPROX_BOUNDS_AS_BOUNDS_PROVIDER_H_
Loading

0 comments on commit efc926c

Please sign in to comment.