diff --git a/cli/cli.py b/cli/cli.py index b2ffc8a801..ded7a6adb7 100644 --- a/cli/cli.py +++ b/cli/cli.py @@ -469,13 +469,14 @@ class Algorithm(StrEnum): Algorithm.naive_ucc_verifier), Task.aucc_verification: TaskInfo([Algorithm.naive_aucc_verifier], Algorithm.naive_aucc_verifier), - Task.gfd_verification: TaskInfo([Algorithm.naive_gfd_verifier, Algorithm.gfd_verifier, Algorithm.egfd_verifier], + Task.gfd_verification: TaskInfo([Algorithm.naive_gfd_verifier, Algorithm.gfd_verifier, + Algorithm.egfd_verifier], Algorithm.naive_gfd_verifier), } ALGOS = { - Algorithm.pyro: desbordante.fd.algorithms.Pyro, - Algorithm.tane: desbordante.fd.algorithms.Tane, + Algorithm.pyro: desbordante.afd.algorithms.Pyro, + Algorithm.tane: desbordante.afd.algorithms.Tane, Algorithm.pfdtane: desbordante.pfd.algorithms.PFDTane, Algorithm.hyfd: desbordante.fd.algorithms.HyFD, Algorithm.fd_mine: desbordante.fd.algorithms.FdMine, @@ -487,7 +488,7 @@ class Algorithm(StrEnum): Algorithm.aid: desbordante.fd.algorithms.Aid, Algorithm.fastod: desbordante.od.algorithms.Fastod, Algorithm.order: desbordante.od.algorithms.Order, - Algorithm.spider: desbordante.ind.algorithms.Spider, + Algorithm.spider: desbordante.aind.algorithms.Spider, Algorithm.faida: desbordante.ind.algorithms.Faida, Algorithm.fd_first: desbordante.cfd.algorithms.FDFirst, Algorithm.naive_fd_verifier: desbordante.fd_verification.algorithms.FDVerifier, @@ -756,13 +757,13 @@ def decorator(func: Callable) -> Callable: in option_type_info.items(): arg = f'--{opt_name}' if opt_main_type == list: - if opt_additional_types[0] == desbordante.data_types.Table: + if opt_additional_types[0] == desbordante.data.Table: click.option(arg, type=(str, str, bool), multiple=True)(func) else: click.option(arg, multiple=True, type=opt_additional_types[0])(func) - elif opt_main_type == desbordante.data_types.Table: + elif opt_main_type == desbordante.data.Table: click.option(arg, type=(str, str, bool))(func) else: click.option(arg, type=opt_main_type)(func) diff --git a/examples/comparison_pfd_vs_afd.py b/examples/comparison_pfd_vs_afd.py index 07cfb7657d..3fe026ed77 100644 --- a/examples/comparison_pfd_vs_afd.py +++ b/examples/comparison_pfd_vs_afd.py @@ -26,8 +26,8 @@ def get_pfds(): pfds = set(get_pfds()) afds = set(get_afds()) -print("pFDs \ AFDs =", stringify(pfds - afds)) -print("AFDs \ pFDs =", stringify(afds - pfds)) +print("pFDs \\ AFDs =", stringify(pfds - afds)) +print("AFDs \\ pFDs =", stringify(afds - pfds)) print("AFDs ∩ pFDs =", stringify(afds & pfds)) print("1 - PerValue([DeviceId] -> Data) =", 0.1714285714) diff --git a/src/python_bindings/ac/bind_ac.cpp b/src/python_bindings/ac/bind_ac.cpp index 9255b57eb1..a3b276c292 100644 --- a/src/python_bindings/ac/bind_ac.cpp +++ b/src/python_bindings/ac/bind_ac.cpp @@ -1,4 +1,9 @@ -#include "bind_ac.h" +#include "ac/bind_ac.h" + +#include +#include +#include +#include #include #include @@ -7,9 +12,7 @@ #include "algorithms/algebraic_constraints/mining_algorithms.h" #include "py_util/bind_primitive.h" -namespace { namespace py = pybind11; -} // namespace namespace python_bindings { void BindAc(py::module_& main_module) { @@ -27,7 +30,7 @@ void BindAc(py::module_& main_module) { std::vector> res; res.reserve(ranges.ranges.size() / 2); assert(ranges.ranges.size() % 2 == 0); - for (size_t i = 0; i < ranges.ranges.size(); i += 2) { + for (std::size_t i = 0; i < ranges.ranges.size(); i += 2) { // TODO: change this once a proper conversion mechanism from // `model::INumericType` is implemented std::string l_endpoint = @@ -42,12 +45,9 @@ void BindAc(py::module_& main_module) { BindPrimitiveNoBase(ac_module, "AcAlgorithm") .def("get_ac_ranges", &ACAlgorithm::GetRangesCollections, py::return_value_policy::reference_internal) - .def( - "get_ac_exceptions", - [](ACAlgorithm& algo) { - algo.CollectACExceptions(); - return algo.GetACExceptions(); - }, - py::return_value_policy::reference_internal); + .def("get_ac_exceptions", [](ACAlgorithm& algo) { + algo.CollectACExceptions(); + return algo.GetACExceptions(); + }); } } // namespace python_bindings diff --git a/src/python_bindings/ar/bind_ar.cpp b/src/python_bindings/ar/bind_ar.cpp index ff71b1a758..3448fe618e 100644 --- a/src/python_bindings/ar/bind_ar.cpp +++ b/src/python_bindings/ar/bind_ar.cpp @@ -1,4 +1,4 @@ -#include "bind_ar.h" +#include "ar/bind_ar.h" #include #include @@ -7,9 +7,7 @@ #include "algorithms/association_rules/mining_algorithms.h" #include "py_util/bind_primitive.h" -namespace { namespace py = pybind11; -} // namespace namespace python_bindings { void BindAr(py::module_& main_module) { @@ -34,12 +32,6 @@ void BindAr(py::module_& main_module) { .def("get_itemnames", &ARAlgorithm::GetItemNamesVector) .def("get_ar_ids", &ARAlgorithm::GetArIDsList); - auto algos_module = ar_module.def_submodule("algorithms"); - auto default_algorithm = - detail::RegisterAlgorithm(algos_module, "Apriori"); - algos_module.attr("Default") = default_algorithm; - - // Perhaps in the future there will be a need for: - // default_algorithm.def("get_frequent_list", &Apriori::GetFrequentList); + BindAlgos(ar_module, {"Apriori"}); } } // namespace python_bindings diff --git a/src/python_bindings/bind_main_classes.cpp b/src/python_bindings/bind_main_classes.cpp index 2f3ea88a16..948bc8a3a6 100644 --- a/src/python_bindings/bind_main_classes.cpp +++ b/src/python_bindings/bind_main_classes.cpp @@ -14,8 +14,9 @@ #include "py_util/opt_to_py.h" #include "py_util/py_to_any.h" -namespace { namespace py = pybind11; + +namespace { using algos::Algorithm; auto const kVoidIndex = std::type_index{typeid(void)}; diff --git a/src/python_bindings/bindings.cpp b/src/python_bindings/bindings.cpp index c3c0ac798e..f6e5d637b2 100644 --- a/src/python_bindings/bindings.cpp +++ b/src/python_bindings/bindings.cpp @@ -7,7 +7,7 @@ #include "ar/bind_ar.h" #include "bind_main_classes.h" #include "cfd/bind_cfd.h" -#include "data/bind_data_types.h" +#include "data/bind_data.h" #include "dd/bind_split.h" #include "fd/bind_fd.h" #include "fd/bind_fd_verification.h" @@ -29,14 +29,21 @@ PYBIND11_MODULE(desbordante, module) { if (std::filesystem::exists("logging.conf")) { el::Loggers::configureFromGlobal("logging.conf"); } else { + using std::filesystem::is_empty, std::filesystem::remove; el::Configurations conf; conf.set(el::Level::Global, el::ConfigurationType::Enabled, "false"); el::Loggers::reconfigureAllLoggers(conf); + try { + static constexpr auto kElppDefaultFile = "myeasylog.log"; + if (is_empty(kElppDefaultFile)) remove(kElppDefaultFile); + } catch (std::filesystem::filesystem_error&) { + } } - for (auto bind_func : {BindMainClasses, BindDataTypes, BindFd, BindCfd, BindAr, BindUcc, BindAc, - BindOd, BindFdVerification, BindMfdVerification, BindUccVerification, - BindStatistics, BindInd, BindGfdVerification, BindSplit}) { + for (auto bind_func : + {BindMainClasses, BindDataModule, BindFd, BindCfd, BindAr, BindUcc, BindAc, BindOd, + BindFdVerification, BindMfdVerification, BindUccVerification, BindStatistics, BindInd, + BindGfdVerification, BindSplit}) { bind_func(module); } } diff --git a/src/python_bindings/data/bind_data_types.cpp b/src/python_bindings/data/bind_data.cpp similarity index 59% rename from src/python_bindings/data/bind_data_types.cpp rename to src/python_bindings/data/bind_data.cpp index 0ee22de4ff..0eeea3de62 100644 --- a/src/python_bindings/data/bind_data_types.cpp +++ b/src/python_bindings/data/bind_data.cpp @@ -1,4 +1,4 @@ -#include "bind_data_types.h" +#include "data/bind_data.h" #include #include @@ -6,19 +6,14 @@ #include "config/tabular_data/input_table_type.h" #include "model/table/column_combination.h" -namespace { namespace py = pybind11; -} // namespace namespace python_bindings { -void BindDataTypes(py::module_& main_module) { - auto data_module = main_module.def_submodule("data_types"); - data_module.doc() = R"doc( - Contains the types of data supported by Desbordante. - - Currently only used as tags for Algorithm.get_option_type - )doc"; - py::class_(data_module, "Table"); +void BindDataModule(py::module_& main_module) { + auto data_module = main_module.def_submodule("data"); + data_module.doc() = "Contains everything related to data itself."; + auto table_tag = py::class_(data_module, "Table"); + table_tag.doc() = "Tag type for tabular data."; using namespace model; py::class_(data_module, "ColumnCombination") diff --git a/src/python_bindings/data/bind_data_types.h b/src/python_bindings/data/bind_data.h similarity index 66% rename from src/python_bindings/data/bind_data_types.h rename to src/python_bindings/data/bind_data.h index d3a6b2d96e..addc2530a3 100644 --- a/src/python_bindings/data/bind_data_types.h +++ b/src/python_bindings/data/bind_data.h @@ -3,5 +3,5 @@ #include namespace python_bindings { -void BindDataTypes(pybind11::module_& main_module); +void BindDataModule(pybind11::module_& main_module); } // namespace python_bindings diff --git a/src/python_bindings/dd/bind_split.cpp b/src/python_bindings/dd/bind_split.cpp index e31846e1ce..2fe07a84ea 100644 --- a/src/python_bindings/dd/bind_split.cpp +++ b/src/python_bindings/dd/bind_split.cpp @@ -1,4 +1,4 @@ -#include "bind_split.h" +#include "dd/bind_split.h" #include #include @@ -7,9 +7,7 @@ #include "algorithms/dd/mining_algorithms.h" #include "py_util/bind_primitive.h" -namespace { namespace py = pybind11; -} // namespace namespace python_bindings { void BindSplit(py::module_& main_module) { diff --git a/src/python_bindings/fd/bind_fd.cpp b/src/python_bindings/fd/bind_fd.cpp index 609f7eb8d8..1f8e4740ca 100644 --- a/src/python_bindings/fd/bind_fd.cpp +++ b/src/python_bindings/fd/bind_fd.cpp @@ -1,4 +1,8 @@ -#include "bind_fd.h" +#include "fd/bind_fd.h" + +#include +#include +#include #include #include @@ -10,9 +14,9 @@ #include "py_util/bind_primitive.h" #include "util/bitset_utils.h" -namespace { namespace py = pybind11; +namespace { template py::tuple VectorToTuple(std::vector vec) { std::size_t const size = vec.size(); @@ -33,44 +37,45 @@ namespace python_bindings { void BindFd(py::module_& main_module) { using namespace algos; + static constexpr auto kFdName = "FD"; + auto fd_module = main_module.def_submodule("fd"); - py::class_(fd_module, "FD") - .def("__str__", &FD::ToLongString) - .def("to_long_string", &FD::ToLongString) - .def("to_short_string", &FD::ToShortString) - .def("to_index_tuple", - [](FD const& fd) { - return py::make_tuple(VectorToTuple(fd.GetLhsIndices()), - std::move(fd.GetRhsIndex())); - }) - .def("to_name_tuple", MakeFdNameTuple) - // TODO: implement proper equality check for FD - .def("__eq__", [](FD const& fd1, - FD const& fd2) { return fd1.ToNameTuple() == fd2.ToNameTuple(); }) - .def("__hash__", [](FD const& fd) { return py::hash(MakeFdNameTuple(fd)); }) - .def_property_readonly("lhs_indices", &FD::GetLhsIndices) - .def_property_readonly("rhs_index", &FD::GetRhsIndex); + auto fd = py::class_(fd_module, kFdName) + .def("__str__", &FD::ToLongString) + .def("to_long_string", &FD::ToLongString) + .def("to_short_string", &FD::ToShortString) + .def("to_index_tuple", + [](FD const& fd) { + return py::make_tuple(VectorToTuple(fd.GetLhsIndices()), + std::move(fd.GetRhsIndex())); + }) + .def("to_name_tuple", MakeFdNameTuple) + // TODO: implement proper equality check for FD + .def("__eq__", + [](FD const& fd1, FD const& fd2) { + return fd1.ToNameTuple() == fd2.ToNameTuple(); + }) + .def("__hash__", [](FD const& fd) { return py::hash(MakeFdNameTuple(fd)); }) + .def_property_readonly("lhs_indices", &FD::GetLhsIndices) + .def_property_readonly("rhs_index", &FD::GetRhsIndex); - static constexpr auto kPyroName = "Pyro"; - static constexpr auto kTaneName = "Tane"; - static constexpr auto kPFDTaneName = "PFDTane"; - auto fd_algos_module = - BindPrimitive(fd_module, py::overload_cast<>(&FDAlgorithm::FdList, py::const_), - "FdAlgorithm", "get_fds", - {"HyFD", "Aid", "Depminer", "DFD", "FastFDs", "FDep", "FdMine", - "FUN", kPyroName, kTaneName, kPFDTaneName}); + BindPrimitive( + fd_module, py::overload_cast<>(&FDAlgorithm::FdList, py::const_), "FdAlgorithm", + "get_fds", {"HyFD", "Aid", "Depminer", "DFD", "FastFDs", "FDep", "FdMine", "FUN"}, + // TODO: make FDs properly copyable. + // NOTE: this breaks FD objects that were not created on the last run of FD search, but + // avoids UB when the last run's FDs are accessed after the FD algorithm is destroyed by + // preventing the algorithm object from being garbage collected. + py::return_value_policy::reference_internal); - auto define_submodule = [&fd_algos_module, &main_module](char const* name, - std::vector algorithms) { - auto algos_module = main_module.def_submodule(name).def_submodule("algorithms"); - for (auto algo_name : algorithms) { - algos_module.attr(algo_name) = fd_algos_module.attr(algo_name); - } - algos_module.attr("Default") = algos_module.attr(algorithms.front()); - }; + auto afd_module = main_module.def_submodule("afd"); + // NOTE: Currently there is no AFD class, using FD instead. + afd_module.attr(kFdName) = fd; + BindAlgos(afd_module, {"Pyro", "Tane"}); - define_submodule("afd", {kPyroName, kTaneName}); - define_submodule("pfd", {kPFDTaneName}); + auto pfd_module = main_module.def_submodule("pfd"); + // NOTE: Currently there is no PFD class, using FD instead. + pfd_module.attr(kFdName) = fd; + BindAlgos(pfd_module, {"PFDTane"}); } } // namespace python_bindings diff --git a/src/python_bindings/fd/bind_fd_verification.cpp b/src/python_bindings/fd/bind_fd_verification.cpp index ca65c64236..ad63e62ad2 100644 --- a/src/python_bindings/fd/bind_fd_verification.cpp +++ b/src/python_bindings/fd/bind_fd_verification.cpp @@ -1,4 +1,4 @@ -#include "bind_fd_verification.h" +#include "fd/bind_fd_verification.h" #include #include @@ -8,9 +8,7 @@ #include "algorithms/fd/verification_algorithms.h" #include "py_util/bind_primitive.h" -namespace { namespace py = pybind11; -} // namespace namespace python_bindings { void BindFdVerification(pybind11::module_& main_module) { @@ -30,6 +28,8 @@ void BindFdVerification(pybind11::module_& main_module) { .def("get_num_error_rows", &FDVerifier::GetNumErrorRows) .def("get_highlights", &FDVerifier::GetHighlights); + // Create AFD verification module alias. We currently consider FD verification and AFD + // verification to be the same. main_module.attr("afd_verification") = fd_verification_module; } } // namespace python_bindings diff --git a/src/python_bindings/gfd/bind_gfd_verification.cpp b/src/python_bindings/gfd/bind_gfd_verification.cpp index 4361523e5a..f9deff7027 100644 --- a/src/python_bindings/gfd/bind_gfd_verification.cpp +++ b/src/python_bindings/gfd/bind_gfd_verification.cpp @@ -6,9 +6,7 @@ #include "algorithms/gfd/verification_algorithms.h" #include "py_util/bind_primitive.h" -namespace { namespace py = pybind11; -} // namespace namespace python_bindings { void BindGfdVerification(pybind11::module_& main_module) { @@ -20,6 +18,6 @@ void BindGfdVerification(pybind11::module_& main_module) { BindPrimitive( gfd_module, &GfdHandler::GfdList, "GfdAlgorithm", "get_gfds", - {"GfdValid", "EGfdValid", "NaiveGfdValid"}, py::return_value_policy::copy); + {"GfdValid", "EGfdValid", "NaiveGfdValid"}); } } // namespace python_bindings diff --git a/src/python_bindings/ind/bind_ind.cpp b/src/python_bindings/ind/bind_ind.cpp index e182a3848d..20c32e7e91 100644 --- a/src/python_bindings/ind/bind_ind.cpp +++ b/src/python_bindings/ind/bind_ind.cpp @@ -15,29 +15,21 @@ void BindInd(py::module_& main_module) { using namespace model; using namespace algos; + static constexpr auto kIndName = "IND"; + auto ind_module = main_module.def_submodule("ind"); - py::class_(ind_module, "IND") - .def("__str__", &IND::ToLongString) - .def("to_short_string", &IND::ToShortString) - .def("to_long_string", &IND::ToLongString) - .def("get_lhs", &IND::GetLhs) - .def("get_rhs", &IND::GetRhs); - - static constexpr auto kSpiderName = "Spider"; - static constexpr auto kMindName = "Mind"; - - auto ind_algos_module = - BindPrimitive(ind_module, &INDAlgorithm::INDList, "IndAlgorithm", - "get_inds", {kSpiderName, "Faida", kMindName}); - auto define_submodule = [&ind_algos_module, &main_module](char const* name, - std::vector algorithms) { - auto algos_module = main_module.def_submodule(name).def_submodule("algorithms"); - for (auto algo_name : algorithms) { - algos_module.attr(algo_name) = ind_algos_module.attr(algo_name); - } - algos_module.attr("Default") = algos_module.attr(algorithms.front()); - }; - - define_submodule("aind", {kSpiderName, kMindName}); + auto ind = py::class_(ind_module, kIndName) + .def("__str__", &IND::ToLongString) + .def("to_short_string", &IND::ToShortString) + .def("to_long_string", &IND::ToLongString) + .def("get_lhs", &IND::GetLhs) + .def("get_rhs", &IND::GetRhs); + + BindPrimitive(ind_module, &INDAlgorithm::INDList, "IndAlgorithm", "get_inds", {"Faida"}); + + auto aind_module = main_module.def_submodule("aind"); + // Currently there is no AIND primitive, using IND instead. + aind_module.attr(kIndName) = ind; + BindAlgos(aind_module, {"Spider", "Mind"}); } } // namespace python_bindings diff --git a/src/python_bindings/mfd/bind_mfd_verification.cpp b/src/python_bindings/mfd/bind_mfd_verification.cpp index 6e7d3bfd71..007b1b7ffa 100644 --- a/src/python_bindings/mfd/bind_mfd_verification.cpp +++ b/src/python_bindings/mfd/bind_mfd_verification.cpp @@ -1,4 +1,4 @@ -#include "bind_mfd_verification.h" +#include "mfd/bind_mfd_verification.h" #include #include @@ -7,9 +7,7 @@ #include "algorithms/metric/verification_algorithms.h" #include "py_util/bind_primitive.h" -namespace { namespace py = pybind11; -} // namespace namespace python_bindings { void BindMfdVerification(py::module_& main_module) { diff --git a/src/python_bindings/od/bind_od.cpp b/src/python_bindings/od/bind_od.cpp index 7d168acdd9..167e8e598c 100644 --- a/src/python_bindings/od/bind_od.cpp +++ b/src/python_bindings/od/bind_od.cpp @@ -1,4 +1,4 @@ -#include "bind_od.h" +#include "od/bind_od.h" #include #include @@ -54,16 +54,12 @@ void BindOd(py::module_& main_module) { .def_readonly("lhs", &ListOD::lhs) .def_readonly("rhs", &ListOD::rhs); - static constexpr auto kFastodName = "Fastod"; - static constexpr auto kOrderName = "Order"; - - auto fastod_algos_module = - BindPrimitiveNoBase(od_module, "Fastod") - .def("get_asc_ods", &algos::Fastod::GetAscendingDependencies) - .def("get_desc_ods", &algos::Fastod::GetDescendingDependencies) - .def("get_simple_ods", &algos::Fastod::GetSimpleDependencies); - auto order_algos_module = - BindPrimitiveNoBase(od_module, "Order").def("get_list_ods", [](Order& algo) { + auto [fastod, od_algos_module] = BindNoBaseAndSetDefault(od_module, "Fastod"); + fastod.def("get_asc_ods", &algos::Fastod::GetAscendingDependencies) + .def("get_desc_ods", &algos::Fastod::GetDescendingDependencies) + .def("get_simple_ods", &algos::Fastod::GetSimpleDependencies); + detail::RegisterAlgorithm(od_algos_module, "Order") + .def("get_list_ods", [](Order& algo) { OrderDependencies const& map_res = algo.GetValidODs(); std::vector res; for (auto const& [lhs, rhs_list] : map_res) { @@ -73,8 +69,6 @@ void BindOd(py::module_& main_module) { } return res; }); - - main_module.attr("od_module") = od_module; } } // namespace python_bindings diff --git a/src/python_bindings/py_util/bind_primitive.h b/src/python_bindings/py_util/bind_primitive.h index 4389fbe921..5d4625b39c 100644 --- a/src/python_bindings/py_util/bind_primitive.h +++ b/src/python_bindings/py_util/bind_primitive.h @@ -2,7 +2,11 @@ #include #include +#include +#include +#include #include +#include #include @@ -48,15 +52,25 @@ template using MemberPointerClass = typename MemberPointerClassHelper::type; } // namespace detail +template +void BindAlgos(pybind11::module_& primitive_module, + std::array algo_names) { + auto algos_module = primitive_module.def_submodule("algorithms"); + auto arr_iter = algo_names.begin(); + auto default_algorithm = detail::RegisterAlgorithm(algos_module, *arr_iter++); + (detail::RegisterAlgorithm(algos_module, *arr_iter++), ...); + algos_module.attr("Default") = default_algorithm; +} + template -auto BindPrimitive(pybind11::module_& module, auto result_method, char const* base_name, - char const* base_result_method_name, - std::array algo_names, - // UB if incorrect. If your algorithm base method is a simple - // util::PrimitiveCollection<...>::AsList() call, the default should work, - // otherwise consult pybind11's docs. - pybind11::return_value_policy result_rv_policy = - pybind11::return_value_policy::reference_internal) { +void BindPrimitive( + pybind11::module_& module, auto result_method, char const* base_name, + char const* base_result_method_name, + std::array algo_names, + // If using the default, make sure your primitive's objects will not become invalid after + // the algorithm's object is destroyed (for example, if they contain a plain pointer to + // schema). If they cannot work without the algorithm's object, rework them. + pybind11::return_value_policy result_rv_policy = pybind11::return_value_policy::copy) { namespace py = pybind11; using algos::Algorithm; @@ -65,24 +79,24 @@ auto BindPrimitive(pybind11::module_& module, auto result_method, char const* ba using Base = detail::MemberPointerClass; py::class_(module, base_name) .def(base_result_method_name, result_method, result_rv_policy); - auto algos_module = module.def_submodule("algorithms"); - auto arr_iter = algo_names.begin(); - auto default_module = detail::RegisterAlgorithm(algos_module, *arr_iter++); - (detail::RegisterAlgorithm(algos_module, *arr_iter++), ...); - algos_module.attr("Default") = default_module; - return algos_module; + BindAlgos(module, std::move(algo_names)); } template -auto BindPrimitiveNoBase(pybind11::module_& module, char const* algo_name) { +auto BindNoBaseAndSetDefault(pybind11::module_& module, char const* algo_name) { namespace py = pybind11; using algos::Algorithm; auto algos_module = module.def_submodule("algorithms"); - auto default_module = + auto default_algorithm = detail::RegisterAlgorithm(algos_module, algo_name); - algos_module.attr("Default") = default_module; - return default_module; + algos_module.attr("Default") = default_algorithm; + return std::pair{default_algorithm, algos_module}; +} + +template +auto BindPrimitiveNoBase(pybind11::module_& module, char const* algo_name) { + return BindNoBaseAndSetDefault(module, algo_name).first; } } // namespace python_bindings diff --git a/src/python_bindings/py_util/create_dataframe_reader.cpp b/src/python_bindings/py_util/create_dataframe_reader.cpp index ce9e4c8127..41e5c05595 100644 --- a/src/python_bindings/py_util/create_dataframe_reader.cpp +++ b/src/python_bindings/py_util/create_dataframe_reader.cpp @@ -1,4 +1,7 @@ -#include "create_dataframe_reader.h" +#include "py_util/create_dataframe_reader.h" + +#include +#include #include "config/exceptions.h" #include "py_util/dataframe_reader.h" diff --git a/src/python_bindings/py_util/create_dataframe_reader.h b/src/python_bindings/py_util/create_dataframe_reader.h index 705a57be0c..f9a7e6259a 100644 --- a/src/python_bindings/py_util/create_dataframe_reader.h +++ b/src/python_bindings/py_util/create_dataframe_reader.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include "config/tabular_data/input_table_type.h" diff --git a/src/python_bindings/py_util/dataframe_reader.cpp b/src/python_bindings/py_util/dataframe_reader.cpp index 3013df0b57..33aa892a11 100644 --- a/src/python_bindings/py_util/dataframe_reader.cpp +++ b/src/python_bindings/py_util/dataframe_reader.cpp @@ -1,5 +1,6 @@ -#include "dataframe_reader.h" +#include "py_util/dataframe_reader.h" +#include #include #include #include diff --git a/src/python_bindings/py_util/dataframe_reader.h b/src/python_bindings/py_util/dataframe_reader.h index 00526305ba..2567959fb4 100644 --- a/src/python_bindings/py_util/dataframe_reader.h +++ b/src/python_bindings/py_util/dataframe_reader.h @@ -1,5 +1,10 @@ #pragma once +#include +#include +#include +#include + #include #include "model/table/idataset_stream.h" diff --git a/src/python_bindings/py_util/get_py_type.cpp b/src/python_bindings/py_util/get_py_type.cpp index 5255d7e59d..1461a81bda 100644 --- a/src/python_bindings/py_util/get_py_type.cpp +++ b/src/python_bindings/py_util/get_py_type.cpp @@ -1,4 +1,4 @@ -#include "get_py_type.h" +#include "py_util/get_py_type.h" #include #include @@ -6,6 +6,7 @@ #include #include +#include #include #include "algorithms/cfd/enums.h" diff --git a/src/python_bindings/py_util/opt_to_py.cpp b/src/python_bindings/py_util/opt_to_py.cpp index 71ba870752..3c9b39593a 100644 --- a/src/python_bindings/py_util/opt_to_py.cpp +++ b/src/python_bindings/py_util/opt_to_py.cpp @@ -1,9 +1,13 @@ -#include "opt_to_py.h" +#include "py_util/opt_to_py.h" #include +#include #include #include +#include +#include +#include #include #include "algorithms/metric/enums.h" @@ -14,8 +18,9 @@ #include "config/max_lhs/type.h" #include "config/thread_number/type.h" -namespace { namespace py = pybind11; + +namespace { using ConvFunction = std::function; template diff --git a/src/python_bindings/py_util/py_to_any.cpp b/src/python_bindings/py_util/py_to_any.cpp index d8eb12e923..88cf249262 100644 --- a/src/python_bindings/py_util/py_to_any.cpp +++ b/src/python_bindings/py_util/py_to_any.cpp @@ -1,5 +1,12 @@ +#include "py_util/py_to_any.h" + #include +#include +#include +#include +#include #include +#include #include #include @@ -19,9 +26,9 @@ #include "py_util/create_dataframe_reader.h" #include "util/enum_to_available_values.h" -namespace { - namespace py = pybind11; + +namespace { using ConvFunc = std::function; template diff --git a/src/python_bindings/py_util/py_to_any.h b/src/python_bindings/py_util/py_to_any.h index 3eece098ec..579cb49a05 100644 --- a/src/python_bindings/py_util/py_to_any.h +++ b/src/python_bindings/py_util/py_to_any.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include #include diff --git a/src/python_bindings/statistics/bind_statistics.cpp b/src/python_bindings/statistics/bind_statistics.cpp index 5a23403be0..62846dd6da 100644 --- a/src/python_bindings/statistics/bind_statistics.cpp +++ b/src/python_bindings/statistics/bind_statistics.cpp @@ -1,14 +1,19 @@ -#include "bind_statistics.h" +#include "statistics/bind_statistics.h" +#include +#include + +#include #include #include #include "algorithms/statistics/data_stats.h" +#include "algorithms/statistics/statistic.h" +#include "model/types/builtin.h" +#include "model/types/type.h" #include "py_util/bind_primitive.h" -namespace { namespace py = pybind11; -} // namespace namespace PYBIND11_NAMESPACE { namespace detail { diff --git a/src/python_bindings/ucc/bind_ucc.cpp b/src/python_bindings/ucc/bind_ucc.cpp index 517fca8e1f..50b2b90379 100644 --- a/src/python_bindings/ucc/bind_ucc.cpp +++ b/src/python_bindings/ucc/bind_ucc.cpp @@ -1,4 +1,4 @@ -#include "bind_ucc.h" +#include "ucc/bind_ucc.h" #include #include @@ -9,10 +9,8 @@ #include "py_util/bind_primitive.h" #include "util/bitset_utils.h" -namespace { namespace py = pybind11; using model::UCC; -} // namespace namespace python_bindings { void BindUcc(py::module_& main_module) { @@ -22,8 +20,13 @@ void BindUcc(py::module_& main_module) { py::class_(ucc_module, "UCC") .def("__str__", &UCC::ToIndicesString) .def_property_readonly("indices", &UCC::GetColumnIndicesAsVector); - BindPrimitive(ucc_module, - py::overload_cast<>(&UCCAlgorithm::UCCList, py::const_), - "UccAlgorithm", "get_uccs", {"HyUCC", "PyroUCC"}); + BindPrimitive( + ucc_module, py::overload_cast<>(&UCCAlgorithm::UCCList, py::const_), "UccAlgorithm", + "get_uccs", {"HyUCC", "PyroUCC"}, + // TODO: make UCCs independent of the algorithm. + // NOTE: a new run of the algorithm will break the previous run's UCCs with this RV + // policy. On the contrary, the algorithm's object will not be garbage collected (thus + // breaking all UCCs obtained from it) until all UCCs are. + py::return_value_policy::reference_internal); } } // namespace python_bindings diff --git a/src/python_bindings/ucc/bind_ucc_verification.cpp b/src/python_bindings/ucc/bind_ucc_verification.cpp index e7e8646a7a..95013f2dbc 100644 --- a/src/python_bindings/ucc/bind_ucc_verification.cpp +++ b/src/python_bindings/ucc/bind_ucc_verification.cpp @@ -1,4 +1,4 @@ -#include "bind_ucc_verification.h" +#include "ucc/bind_ucc_verification.h" #include #include @@ -6,9 +6,7 @@ #include "algorithms/ucc/verification_algorithms.h" #include "py_util/bind_primitive.h" -namespace { namespace py = pybind11; -} // namespace namespace python_bindings { void BindUccVerification(pybind11::module_& main_module) { @@ -22,6 +20,8 @@ void BindUccVerification(pybind11::module_& main_module) { .def("get_num_rows_violating_ucc", &UCCVerifier::GetNumRowsViolatingUCC) .def("get_clusters_violating_ucc", &UCCVerifier::GetClustersViolatingUCC) .def("get_error", &UCCVerifier::GetError); + // Create AUCC verification module alias. We currently consider UCC verification and AUCC + // verification to be the same. main_module.attr("aucc_verification") = ucc_verification_module; } } // namespace python_bindings