diff --git a/src/bindings/PyDP/algorithms/bounded_functions.cpp b/src/bindings/PyDP/algorithms/bounded_functions.cpp index 3866219e..78cf748a 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 @@ -28,47 +27,59 @@ 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(); }); - // 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..75d81b69 100644 --- a/src/bindings/PyDP/algorithms/count.cpp +++ b/src/bindings/PyDP/algorithms/count.cpp @@ -29,9 +29,17 @@ 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) { - 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) { diff --git a/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp b/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp index 82c16f75..32139ff7 100644 --- a/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp +++ b/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp @@ -14,53 +14,42 @@ 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; - obj = typename Algorithm::Builder().SetEpsilon(epsilon).Build().ValueOrDie(); - if (obj.ok()){ - return std::move(obj.ValueOrDie()); - } - else{ - 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(); - 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{ - throw std::runtime_error(obj.status().error_message()); - } - } + builder.SetEpsilon(epsilon); - 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()); + 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()); } - else{ + + base::StatusOr> obj = builder.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"},