Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python bindings cleanup #425

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions examples/comparison_pfd_vs_afd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
22 changes: 11 additions & 11 deletions src/python_bindings/ac/bind_ac.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#include "bind_ac.h"
#include "ac/bind_ac.h"

#include <cstddef>
#include <string>
#include <utility>
#include <vector>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
Expand All @@ -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) {
Expand All @@ -27,7 +30,7 @@ void BindAc(py::module_& main_module) {
std::vector<std::pair<pybind11::float_, pybind11::float_>> 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 =
Expand All @@ -42,12 +45,9 @@ void BindAc(py::module_& main_module) {
BindPrimitiveNoBase<ACAlgorithm>(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
12 changes: 2 additions & 10 deletions src/python_bindings/ar/bind_ar.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "bind_ar.h"
#include "ar/bind_ar.h"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
Expand All @@ -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) {
Expand All @@ -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<Apriori, ARAlgorithm>(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<ARAlgorithm, Apriori>(ar_module, {"Apriori"});
}
} // namespace python_bindings
3 changes: 2 additions & 1 deletion src/python_bindings/bind_main_classes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)};

Expand Down
15 changes: 11 additions & 4 deletions src/python_bindings/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
#include "bind_data_types.h"
#include "data/bind_data.h"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#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_<config::InputTable>(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_<config::InputTable>(data_module, "Table");
table_tag.doc() = "Tag type for tabular data.";

using namespace model;
py::class_<ColumnCombination>(data_module, "ColumnCombination")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
#include <pybind11/pybind11.h>

namespace python_bindings {
void BindDataTypes(pybind11::module_& main_module);
void BindDataModule(pybind11::module_& main_module);
} // namespace python_bindings
4 changes: 1 addition & 3 deletions src/python_bindings/dd/bind_split.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "bind_split.h"
#include "dd/bind_split.h"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
Expand All @@ -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) {
Expand Down
79 changes: 42 additions & 37 deletions src/python_bindings/fd/bind_fd.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#include "bind_fd.h"
#include "fd/bind_fd.h"

#include <cstddef>
#include <initializer_list>
#include <vector>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
Expand All @@ -10,9 +14,9 @@
#include "py_util/bind_primitive.h"
#include "util/bitset_utils.h"

namespace {
namespace py = pybind11;

namespace {
template <typename ElementType>
py::tuple VectorToTuple(std::vector<ElementType> vec) {
std::size_t const size = vec.size();
Expand All @@ -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>(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>(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<hyfd::HyFD, Aid, Depminer, DFD, FastFDs, FDep, FdMine, FUN, Pyro, Tane,
PFDTane>(fd_module, py::overload_cast<>(&FDAlgorithm::FdList, py::const_),
"FdAlgorithm", "get_fds",
{"HyFD", "Aid", "Depminer", "DFD", "FastFDs", "FDep", "FdMine",
"FUN", kPyroName, kTaneName, kPFDTaneName});
BindPrimitive<hyfd::HyFD, Aid, Depminer, DFD, FastFDs, FDep, FdMine, FUN>(
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<char const*> 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<FDAlgorithm, Pyro, Tane>(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<FDAlgorithm, PFDTane>(pfd_module, {"PFDTane"});
}
} // namespace python_bindings
6 changes: 3 additions & 3 deletions src/python_bindings/fd/bind_fd_verification.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "bind_fd_verification.h"
#include "fd/bind_fd_verification.h"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
Expand All @@ -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) {
Expand All @@ -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
4 changes: 1 addition & 3 deletions src/python_bindings/gfd/bind_gfd_verification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -20,6 +18,6 @@ void BindGfdVerification(pybind11::module_& main_module) {

BindPrimitive<GfdValidation, EGfdValidation, NaiveGfdValidation>(
gfd_module, &GfdHandler::GfdList, "GfdAlgorithm", "get_gfds",
{"GfdValid", "EGfdValid", "NaiveGfdValid"}, py::return_value_policy::copy);
{"GfdValid", "EGfdValid", "NaiveGfdValid"});
}
} // namespace python_bindings
Loading
Loading