From bcceec786744aa0a6c23b5cdd369ae38478f8768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20S=C3=A1nchez=20Medina?= Date: Sat, 8 Aug 2020 13:41:41 +0100 Subject: [PATCH 1/3] Refactor builders error check --- .../PyDP/algorithms/bounded_functions.cpp | 1 - .../PyDP/pydp_lib/algorithm_builder.hpp | 58 +++++++++---------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/bindings/PyDP/algorithms/bounded_functions.cpp b/src/bindings/PyDP/algorithms/bounded_functions.cpp index 3866219e..78466f1a 100644 --- a/src/bindings/PyDP/algorithms/bounded_functions.cpp +++ b/src/bindings/PyDP/algorithms/bounded_functions.cpp @@ -10,7 +10,6 @@ #include "algorithms/bounded-standard-deviation.h" #include "algorithms/bounded-sum.h" #include "algorithms/bounded-variance.h" -#include "base/statusor.h" #include "../pydp_lib/algorithm_builder.hpp" #include "../pydp_lib/casting.hpp" // our caster helper library diff --git a/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp b/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp index 82c16f75..cc847b75 100644 --- a/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp +++ b/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp @@ -18,49 +18,49 @@ template class AlgorithmBuilder { public: std::unique_ptr Build(double epsilon) { - base::StatusOr> obj; - obj = typename Algorithm::Builder().SetEpsilon(epsilon).Build().ValueOrDie(); - if (obj.ok()){ - return std::move(obj.ValueOrDie()); - } - else{ + base::StatusOr> obj = + typename Algorithm::Builder().SetEpsilon(epsilon).Build().ValueOrDie(); + + if (!obj.ok()) { throw std::runtime_error(obj.status().error_message()); } + + return std::move(obj.ValueOrDie()); } std::unique_ptr BuildWithBounds(double epsilon, T lower_bound, T upper_bound, int l0_sensitivity = 1, int linf_sensitivity = 1) { - base::StatusOr> obj; - obj = typename Algorithm::Builder() - .SetEpsilon(epsilon) - .SetLower(lower_bound) - .SetUpper(upper_bound) - .SetMaxPartitionsContributed(l0_sensitivity) - .SetMaxContributionsPerPartition(linf_sensitivity) - .Build(); - if (obj.ok()){ - return std::move(obj.ValueOrDie()); - } - else{ + base::StatusOr> obj = + typename Algorithm::Builder() + .SetEpsilon(epsilon) + .SetLower(lower_bound) + .SetUpper(upper_bound) + .SetMaxPartitionsContributed(l0_sensitivity) + .SetMaxContributionsPerPartition(linf_sensitivity) + .Build(); + + if (!obj.ok()) { throw std::runtime_error(obj.status().error_message()); - } + } + + return std::move(obj.ValueOrDie()); } std::unique_ptr BuildWithoutBounds(double epsilon, int l0_sensitivity = 1, int linf_sensitivity = 1) { - base::StatusOr> obj; - obj = typename Algorithm::Builder() - .SetEpsilon(epsilon) - .SetMaxPartitionsContributed(l0_sensitivity) - .SetMaxContributionsPerPartition(linf_sensitivity) - .Build(); - if (obj.ok()){ - return std::move(obj.ValueOrDie()); - } - else{ + base::StatusOr> obj = + typename Algorithm::Builder() + .SetEpsilon(epsilon) + .SetMaxPartitionsContributed(l0_sensitivity) + .SetMaxContributionsPerPartition(linf_sensitivity) + .Build(); + + if (!obj.ok()) { throw std::runtime_error(obj.status().error_message()); } + + return std::move(obj.ValueOrDie()); } std::map type_to_name = {{typeid(double), "Double"}, From e6069b02be4b31fa73d91f99bea8a9a1173b3ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20S=C3=A1nchez=20Medina?= Date: Sat, 8 Aug 2020 15:42:38 +0100 Subject: [PATCH 2/3] Bind more functions --- .../PyDP/algorithms/bounded_functions.cpp | 40 ++++++++++++++----- src/bindings/PyDP/algorithms/count.cpp | 8 +++- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/bindings/PyDP/algorithms/bounded_functions.cpp b/src/bindings/PyDP/algorithms/bounded_functions.cpp index 78466f1a..859f088f 100644 --- a/src/bindings/PyDP/algorithms/bounded_functions.cpp +++ b/src/bindings/PyDP/algorithms/bounded_functions.cpp @@ -52,22 +52,40 @@ void declareBoundedAlgorithm(py::module& m) { bld.def("privacy_budget_left", [](Algorithm& obj) { return obj.RemainingPrivacyBudget(); }); - // TODO - // bld.def("add_entries", [](Algorithm& obj, std::vector& v) { - // return obj.AddEntries(v.begin(), v.end()).ValueOrDie(); - // }); + bld.def("add_entries", [](Algorithm& obj, std::vector& v) { + obj.AddEntries(v.begin(), v.end()); + }); + + bld.def("partial_result", [](Algorithm& obj) { + auto result = obj.PartialResult(); + + if (!result.ok()) { + throw std::runtime_error(result.status().error_message()); + } + + return dp::GetValue(result.ValueOrDie()); + }); - // bld.def("partial_result", [](Algorithm& obj) { - // return dp::GetValue(obj.PartialResult().ValueOrDie()); - // }) - // bld.def("partial_result", [](Algorithm& obj, double privacy_budget) { - // return dp::GetValue(obj.PartialResult(privacy_budget).ValueOrDie()); - // }) + bld.def("partial_result", [](Algorithm& obj, double privacy_budget) { + auto result = obj.PartialResult(privacy_budget); + + if (!result.ok()) { + throw std::runtime_error(result.status().error_message()); + } + + return dp::GetValue(result.ValueOrDie()); + }); bld.def_property_readonly("epsilon", [](Algorithm& obj) { return obj.GetEpsilon(); }); bld.def("result", [](Algorithm& obj, std::vector& v) { - return dp::GetValue(obj.Result(v.begin(), v.end()).ValueOrDie()); + auto result = obj.Result(v.begin(), v.end()); + + if (!result.ok()) { + throw std::runtime_error(result.status().error_message()); + } + + return dp::GetValue(result.ValueOrDie()); }); } diff --git a/src/bindings/PyDP/algorithms/count.cpp b/src/bindings/PyDP/algorithms/count.cpp index 62d3c811..55909a56 100644 --- a/src/bindings/PyDP/algorithms/count.cpp +++ b/src/bindings/PyDP/algorithms/count.cpp @@ -31,7 +31,13 @@ void declareCount(py::module& m, string const& suffix) { .def("memory_used", &dp::Count::MemoryUsed) .def("result", [](dp::Count& obj, std::vector& v) { - return dp::GetValue(obj.Result(v.begin(), v.end()).ValueOrDie()); + auto result = obj.Result(v.begin(), v.end()); + + if (!result.ok()) { + throw std::runtime_error(result.status().error_message()); + } + + return dp::GetValue(result.ValueOrDie()); }) .def("partial_result", [](dp::Count& obj) { From b9c881c58b11412d17644b34a503e45d83153864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20S=C3=A1nchez=20Medina?= Date: Sat, 8 Aug 2020 20:38:20 +0100 Subject: [PATCH 3/3] Unifiy helper build function --- .../PyDP/algorithms/bounded_functions.cpp | 16 ++--- src/bindings/PyDP/algorithms/count.cpp | 2 + .../PyDP/pydp_lib/algorithm_builder.hpp | 63 ++++++++----------- 3 files changed, 33 insertions(+), 48 deletions(-) diff --git a/src/bindings/PyDP/algorithms/bounded_functions.cpp b/src/bindings/PyDP/algorithms/bounded_functions.cpp index 859f088f..78cf748a 100644 --- a/src/bindings/PyDP/algorithms/bounded_functions.cpp +++ b/src/bindings/PyDP/algorithms/bounded_functions.cpp @@ -27,27 +27,21 @@ void declareBoundedAlgorithm(py::module& m) { bld.def(py::init([](double epsilon, T lower_bound, T upper_bound, int l0_sensitivity, int linf_sensitivity) { py::print("Building with bounds"); - return builder().BuildWithBounds(epsilon, lower_bound, upper_bound, - l0_sensitivity, linf_sensitivity); + return builder().Build(epsilon, lower_bound, upper_bound, l0_sensitivity, + linf_sensitivity); }), py::arg("epsilon"), py::arg("lower_bound"), py::arg("upper_bound"), py::arg("l0_sensitivity") = 1, py::arg("linf_sensitivity") = 1); bld.def(py::init([](double epsilon, int l0_sensitivity, int linf_sensitivity) { py::print("Building without bounds"); - return builder().BuildWithoutBounds(epsilon, l0_sensitivity, - linf_sensitivity); + return builder().Build(epsilon, nullopt, nullopt, l0_sensitivity, + linf_sensitivity); }), py::arg("epsilon"), py::arg("l0_sensitivity") = 1, py::arg("linf_sensitivity") = 1); - // TODO: can't get it work - // bld.def_property_readonly("l0_sensitivity", [](Algorithm& obj){ - // return obj.GetMaxPartitionsContributed(); - // }); - // bld.def_property_readonly("linf_sensitivity", [](Algorithm& obj){ - // return obj.SetMaxContributionsPerPartition(); - // }); + bld.def_property_readonly("epsilon", [](Algorithm& obj) { return obj.GetEpsilon(); }); bld.def("privacy_budget_left", [](Algorithm& obj) { return obj.RemainingPrivacyBudget(); }); diff --git a/src/bindings/PyDP/algorithms/count.cpp b/src/bindings/PyDP/algorithms/count.cpp index 55909a56..75d81b69 100644 --- a/src/bindings/PyDP/algorithms/count.cpp +++ b/src/bindings/PyDP/algorithms/count.cpp @@ -29,6 +29,8 @@ void declareCount(py::module& m, string const& suffix) { //.def("serialize", &dp::Count::Serialize) //.def("merge", &dp::Count::Merge) .def("memory_used", &dp::Count::MemoryUsed) + .def_property_readonly("epsilon", + [](dp::Count& obj) { return obj.GetEpsilon(); }) .def("result", [](dp::Count& obj, std::vector& v) { auto result = obj.Result(v.begin(), v.end()); diff --git a/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp b/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp index cc847b75..32139ff7 100644 --- a/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp +++ b/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp @@ -14,48 +14,37 @@ namespace dp = differential_privacy; namespace differential_privacy { namespace python { +template +constexpr bool is_bounded_algorithm() { + return std::is_same>::value || + std::is_same>::value || + std::is_same>::value || + std::is_same>::value; +} + template class AlgorithmBuilder { public: - std::unique_ptr Build(double epsilon) { - base::StatusOr> obj = - typename Algorithm::Builder().SetEpsilon(epsilon).Build().ValueOrDie(); - - if (!obj.ok()) { - throw std::runtime_error(obj.status().error_message()); + std::unique_ptr Build(double epsilon, + std::optional lower_bound = std::nullopt, + std::optional upper_bound = std::nullopt, + std::optional l0_sensitivity = std::nullopt, + std::optional linf_sensitivity = std::nullopt) { + auto builder = typename Algorithm::Builder(); + + builder.SetEpsilon(epsilon); + + if (l0_sensitivity.has_value()) + builder.SetMaxPartitionsContributed(l0_sensitivity.value()); + if (linf_sensitivity.has_value()) + builder.SetMaxContributionsPerPartition(linf_sensitivity.value()); + + if constexpr (is_bounded_algorithm()) { + if (lower_bound.has_value()) builder.SetLower(lower_bound.value()); + if (upper_bound.has_value()) builder.SetUpper(upper_bound.value()); } - return std::move(obj.ValueOrDie()); - } - - std::unique_ptr BuildWithBounds(double epsilon, T lower_bound, - T upper_bound, int l0_sensitivity = 1, - int linf_sensitivity = 1) { - base::StatusOr> obj = - typename Algorithm::Builder() - .SetEpsilon(epsilon) - .SetLower(lower_bound) - .SetUpper(upper_bound) - .SetMaxPartitionsContributed(l0_sensitivity) - .SetMaxContributionsPerPartition(linf_sensitivity) - .Build(); - - if (!obj.ok()) { - throw std::runtime_error(obj.status().error_message()); - } - - return std::move(obj.ValueOrDie()); - } - - std::unique_ptr BuildWithoutBounds(double epsilon, int l0_sensitivity = 1, - int linf_sensitivity = 1) { - base::StatusOr> obj = - typename Algorithm::Builder() - .SetEpsilon(epsilon) - .SetMaxPartitionsContributed(l0_sensitivity) - .SetMaxContributionsPerPartition(linf_sensitivity) - .Build(); - + base::StatusOr> obj = builder.Build(); if (!obj.ok()) { throw std::runtime_error(obj.status().error_message()); }