Skip to content

Commit d59291d

Browse files
committed
impl
1 parent a409a4b commit d59291d

3 files changed

Lines changed: 50 additions & 5 deletions

File tree

build_PyDP.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ echo -e "Running bazel with:\n\tPLATFORM=$PLATFORM\n\tPYTHONHOME=$PYTHONHOME\n\t
1313
# Compile code
1414
bazel coverage src/python:pydp \
1515
--config $PLATFORM \
16+
--subcommands \
1617
--verbose_failures \
1718
--action_env=PYTHON_BIN_PATH=$PYTHONHOME \
1819
--action_env=PYTHON_LIB_PATH=$PYTHONPATH

src/bindings/PyDP/algorithms/qunatile_tree.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ dp::QuantileTree<double>::Privatized GetPrivatizeTree(
4444
dp_params.mechanism_builder = std::make_unique<dp::GaussianMechanism::Builder>();
4545
} else {
4646
throw py::value_error("noise_type can be 'laplace' or 'gaussian', but it is '" +
47-
noise_type + "'./**/");
47+
noise_type + "'.");
4848
}
4949
auto status_or_result = tree.MakePrivate(dp_params);
5050
if (!status_or_result.ok()) {
@@ -89,15 +89,28 @@ void init_algorithms_quantile_tree(py::module& m) {
8989
to_return.mutable_data()->PackFrom(obj.Serialize());
9090
return to_return;
9191
});
92-
py_class.def("merge", &dp::QuantileTree<double>::Merge, py::arg("summary"));
92+
py_class.def(
93+
"merge",
94+
[](dp::QuantileTree<double>& tree, const dp::Summary& summary) {
95+
if (!summary.has_data()) {
96+
throw std::runtime_error("Cannot merge summary, no data.");
97+
}
98+
99+
dp::BoundedQuantilesSummary quantiles_summary;
100+
if (!summary.data().UnpackTo(&quantiles_summary)) {
101+
throw std::runtime_error("Fail to upack data");
102+
}
103+
tree.Merge(quantiles_summary);
104+
},
105+
py::arg("summary"));
93106

94107
py_class.def(
95108
"compute_quantiles",
96109
[](dp::QuantileTree<double>& tree, double epsilon, double delta,
97-
int max_partitions_contributed_to, int max_contributions_per_partition,
110+
int max_partitions_contributed, int max_contributions_per_partition,
98111
const std::vector<double>& quantiles, const std::string& noise_type) {
99112
dp::QuantileTree<double>::Privatized privatized_tree =
100-
GetPrivatizeTree(tree, epsilon, delta, max_partitions_contributed_to,
113+
GetPrivatizeTree(tree, epsilon, delta, max_partitions_contributed,
101114
max_contributions_per_partition, noise_type);
102115

103116
std::vector<double> output;
@@ -110,7 +123,7 @@ void init_algorithms_quantile_tree(py::module& m) {
110123
}
111124
return output;
112125
},
113-
py::arg("epsilon"), py::arg("delta"), py::arg("max_partitions_contributed_to"),
126+
py::arg("epsilon"), py::arg("delta"), py::arg("max_partitions_contributed"),
114127
py::arg("max_contributions_per_partition"), py::arg("quantiles"),
115128
py::arg("noise_type") = "laplace", "Compute multiple quantiles.");
116129

tests/algorithms/test_quantile_tree.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22

3+
import pydp._pydp as dp
34
from pydp.algorithms.quantile_tree import QuantileTree
45

56

@@ -70,3 +71,33 @@ def test_quantiles_and_confidence_intervals(self):
7071
<= dp_quantile_ci.upper_bound
7172
)
7273
assert dp_quantile_ci.upper_bound - dp_quantile_ci.lower_bound < 0.01
74+
75+
def test_serialize_deserialize(self):
76+
lower, upper = 0, 1000
77+
height, branching_factor = 5, 10
78+
tree1 = QuantileTree(lower, upper, height, branching_factor)
79+
80+
# Add elements 0,..1000 to the tree.
81+
for i in range(1001):
82+
tree1.add_entry(i)
83+
84+
serialized_tree = tree1.serialize().to_bytes()
85+
86+
# Deserialize
87+
# 1.Create empty tree with the same parameters.
88+
tree2 = QuantileTree(lower, upper, height, branching_factor)
89+
# 2. Merge serialized_tree to tree2.
90+
tree2.merge(dp.bytes_to_summary(serialized_tree))
91+
92+
# Check that tree2 computes correct quantiles. For this use high
93+
# epsilon, which means small noise and close to the real quantiles.
94+
eps, delta = 10000, 0
95+
quantiles_to_compute = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9, 0.9]
96+
dp_quantiles = tree2.compute_quantiles(
97+
eps, delta, 1, 1, quantiles_to_compute, "laplace"
98+
)
99+
100+
# Check that DP quantiles are close to expected.
101+
for quantile, dp_quantile in zip(quantiles_to_compute, dp_quantiles):
102+
expected_quantile = quantile * upper
103+
assert abs(expected_quantile - dp_quantile) < 0.1

0 commit comments

Comments
 (0)