diff --git a/src/bindings/BUILD b/src/bindings/BUILD index 76bbd6e6..3fa8691d 100644 --- a/src/bindings/BUILD +++ b/src/bindings/BUILD @@ -29,4 +29,4 @@ pybind_extension( "@google_dp//algorithms:order-statistics", "@google_dp//proto:util-lib" ], -) \ No newline at end of file +) diff --git a/src/bindings/PyDP/algorithms/bounded_functions.cpp b/src/bindings/PyDP/algorithms/bounded_functions.cpp index 8e878336..d42240de 100644 --- a/src/bindings/PyDP/algorithms/bounded_functions.cpp +++ b/src/bindings/PyDP/algorithms/bounded_functions.cpp @@ -1,111 +1,59 @@ // Provides bindings for Bounded Functions -#include "../../c/c_api.h" - -#include "../pydp_lib/casting.hpp" // our caster helper library -#include "../pydp_lib/helper_class.hpp" // Dummy helper class - #include "pybind11/complex.h" #include "pybind11/functional.h" #include "pybind11/pybind11.h" #include "pybind11/stl.h" -using namespace std; +#include "algorithms/algorithm.h" +#include "algorithms/bounded-mean.h" +#include "algorithms/bounded-standard-deviation.h" +#include "algorithms/bounded-sum.h" +#include "algorithms/bounded-variance.h" -namespace py = pybind11; +#include "../pydp_lib/algorithm_builder.hpp" +#include "../pydp_lib/casting.hpp" // our caster helper library -class BoundedMeanDummy : public Dummy { - public: - using Dummy::Dummy; - double Result(py::list l) override { - return Result_BoundedMean(obj, l); - } -}; - -class BoundedSumDummy : public Dummy { - public: - using Dummy::Dummy; - double Result(py::list l) override { - return Result_BoundedSum(obj, l); - } -}; - -class BoundedStandardDeviationDummy : public Dummy { - public: - using Dummy::Dummy; - double Result(py::list l) override { - return Result_BoundedStandardDeviation(obj, l); - } -}; +using namespace std; -class BoundedVarianceDummy : public Dummy { - public: - using Dummy::Dummy; - double Result(py::list l) override { - return Result_BoundedVariance(obj, l); - } -}; +namespace py = pybind11; +namespace dp = differential_privacy; -void declareBoundedMean(py::module& m) { - py::class_ bld(m, "BoundedMean"); +template +void declareBoundedAlgorithm(py::module& m) { + using builder = typename dp::python::AlgorithmBuilder; + py::class_ bld(m, builder().get_algorithm_name().c_str()); bld.attr("__module__") = "pydp"; - bld.def(py::init(), py::return_value_policy::reference, - py::call_guard()); - bld.def(py::init(), py::return_value_policy::reference, - py::call_guard()); - bld.def("result", &BoundedMeanDummy::Result); - bld.def_property("l0_sensitivity", &BoundedMeanDummy::get_l0_sensitivity, - &BoundedMeanDummy::set_l0_sensitivity); - bld.def_property("linf_sensitivity", &BoundedMeanDummy::get_linf_sensitivity, - &BoundedMeanDummy::set_linf_sensitivity); + 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); + }), + 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); + }), + py::arg("epsilon"), py::arg("l0_sensitivity") = 1, + py::arg("linf_sensitivity") = 1); + bld.def("result", [](Algorithm& obj, std::vector& v) { + return dp::GetValue(obj.Result(v.begin(), v.end()).ValueOrDie()); + }); } -void declareBoundedSum(py::module& m) { - py::class_ cls(m, "BoundedSum"); - cls.attr("__module__") = "pydp"; - cls.def(py::init(), py::return_value_policy::reference, - py::call_guard()); - cls.def(py::init(), py::return_value_policy::reference, - py::call_guard()); - cls.def("result", &BoundedSumDummy::Result); - cls.def_property("l0_sensitivity", &BoundedSumDummy::get_l0_sensitivity, - &BoundedSumDummy::set_l0_sensitivity); - cls.def_property("linf_sensitivity", &BoundedSumDummy::get_linf_sensitivity, - &BoundedSumDummy::set_linf_sensitivity); -} +void init_algorithms_bounded_functions(py::module& m) { + declareBoundedAlgorithm>(m); + declareBoundedAlgorithm>(m); -void declareBoundedStandardDeviation(py::module& m) { - py::class_ cls(m, "BoundedStandardDeviation"); - cls.attr("__module__") = "pydp"; - cls.def(py::init(), py::return_value_policy::reference, - py::call_guard()); - cls.def(py::init(), py::return_value_policy::reference, - py::call_guard()); - cls.def("result", &BoundedStandardDeviationDummy::Result); - cls.def_property("l0_sensitivity", &BoundedStandardDeviationDummy::get_l0_sensitivity, - &BoundedStandardDeviationDummy::set_l0_sensitivity); - cls.def_property("linf_sensitivity", - &BoundedStandardDeviationDummy::get_linf_sensitivity, - &BoundedSumDummy::set_linf_sensitivity); -} + declareBoundedAlgorithm>(m); + declareBoundedAlgorithm>(m); -void declareBoundedVariance(py::module& m) { - py::class_ cls(m, "BoundedVariance"); - cls.attr("__module__") = "pydp"; - cls.def(py::init(), py::return_value_policy::reference, - py::call_guard()); - cls.def(py::init(), py::return_value_policy::reference, - py::call_guard()); - cls.def("result", &BoundedVarianceDummy::Result); - cls.def_property("l0_sensitivity", &BoundedVarianceDummy::get_l0_sensitivity, - &BoundedVarianceDummy::set_l0_sensitivity); - cls.def_property("linf_sensitivity", &BoundedVarianceDummy::get_linf_sensitivity, - &BoundedVarianceDummy::set_linf_sensitivity); -} + declareBoundedAlgorithm>(m); + declareBoundedAlgorithm>(m); -void init_algorithms_bounded_functions(py::module& m) { - declareBoundedMean(m); - declareBoundedSum(m); - declareBoundedStandardDeviation(m); - declareBoundedVariance(m); + declareBoundedAlgorithm>(m); + declareBoundedAlgorithm>(m); } diff --git a/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp b/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp index 9b7e7298..c76b1d83 100644 --- a/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp +++ b/src/bindings/PyDP/pydp_lib/algorithm_builder.hpp @@ -2,8 +2,14 @@ #define PYDP_LIB_ALGORITHM_H_ #include "algorithms/algorithm.h" +#include "algorithms/bounded-mean.h" +#include "algorithms/bounded-standard-deviation.h" +#include "algorithms/bounded-sum.h" +#include "algorithms/bounded-variance.h" #include "algorithms/numerical-mechanisms.h" +namespace dp = differential_privacy; + namespace differential_privacy { namespace python { @@ -17,6 +23,61 @@ class AlgorithmBuilder { .Build() .ValueOrDie(); } + + std::unique_ptr BuildWithBounds(double epsilon, T lower_bound, + T upper_bound, int l0_sensitivity = 1, + int linf_sensitivity = 1) { + return typename Algorithm::Builder() + .SetLaplaceMechanism(absl::make_unique()) + .SetEpsilon(epsilon) + .SetLower(lower_bound) + .SetUpper(upper_bound) + .SetMaxPartitionsContributed(l0_sensitivity) + .SetMaxContributionsPerPartition(linf_sensitivity) + .Build() + .ValueOrDie(); + } + + std::unique_ptr BuildWithoutBounds(double epsilon, int l0_sensitivity = 1, + int linf_sensitivity = 1) { + return typename Algorithm::Builder() + .SetLaplaceMechanism(absl::make_unique()) + .SetEpsilon(epsilon) + .SetMaxPartitionsContributed(l0_sensitivity) + .SetMaxContributionsPerPartition(linf_sensitivity) + .Build() + .ValueOrDie(); + } + + std::string get_algorithm_name() { + // Set the suffix string + std::string suffix = ""; + // TODO: Change to mapping function + if (typeid(T) == typeid(int)) { + suffix = "Int"; + } else if (typeid(T) == typeid(double)) { + suffix = "Double"; + } else { + throw std::runtime_error("Binding error - Only int and double types supported"); + } + + // Set the algorithm name string + std::string name = ""; + // TODO: Change to mapping function + if (typeid(Algorithm) == typeid(dp::BoundedMean)) { + name = "BoundedMean"; + } else if (typeid(Algorithm) == typeid(dp::BoundedSum)) { + name = "BoundedSum"; + } else if (typeid(Algorithm) == typeid(dp::BoundedStandardDeviation)) { + name = "BoundedStandardDeviation"; + } else if (typeid(Algorithm) == typeid(dp::BoundedVariance)) { + name = "BoundedVariance"; + } else { + throw std::runtime_error(std::string("Binding error - Unsupported algorithm: ") + + std::string(typeid(Algorithm).name())); + } + return (name + suffix); + } }; } // namespace python