From 74c8d4d7bb489c8bb3606cb4dc013300b1cfc204 Mon Sep 17 00:00:00 2001 From: Dennis Rohde Date: Mon, 23 Aug 2021 08:22:42 +0200 Subject: [PATCH] bugfix and small changes --- README.md | 2 +- include/curve.hpp | 4 ++++ include/point.hpp | 4 ++++ setup.py | 2 +- src/curve.cpp | 38 +++++++++++++---------------- src/fred_python_wrapper.cpp | 48 +++++++++---------------------------- 6 files changed, 37 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index bb69dbf..f5de3bc 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ By default, Fred will automatically determine the number of threads to use. If y #### discrete dynamic time warping distance - signature: `fred.discrete_dynamic_time_warping(curve1, curve2)` -- returns: `fred.Discrete_Dynamic_Time_Warping_Distance_Result` with members `value` and `time` +- returns: `fred.Discrete_Dynamic_Time_Warping_Distance` with members `value` and `time` ### Curve Simplification diff --git a/include/curve.hpp b/include/curve.hpp index 8aedcb7..2bd4294 100644 --- a/include/curve.hpp +++ b/include/curve.hpp @@ -162,6 +162,10 @@ class Curves : public std::vector { return std::vector::operator[](i); } + inline void set(const curve_number_t i, const Curve &val) { + std::vector::operator[](i) = val; + } + inline curve_size_t get_m() const { return m; } diff --git a/include/point.hpp b/include/point.hpp index 87508ef..3f664a5 100644 --- a/include/point.hpp +++ b/include/point.hpp @@ -36,6 +36,10 @@ class Point : public Coordinates { return Coordinates::operator[](i); } + inline void set(const dimensions_t i, coordinate_t val) { + Coordinates::operator[](i) = val; + } + #pragma omp declare simd inline const coordinate_t& operator[](const dimensions_t i) const { return Coordinates::operator[](i); diff --git a/setup.py b/setup.py index 93393ed..9868893 100644 --- a/setup.py +++ b/setup.py @@ -74,7 +74,7 @@ def build_extension(self, ext): setup( name='Fred-Frechet', - version='1.7.3', + version='1.7.4', author='Dennis Rohde', author_email='dennis.rohde@tu-dortmund.de', description='A fast, scalable and light-weight C++ Fréchet distance library, exposed to python and focused on (k,l)-clustering of polygonal curves.', diff --git a/src/curve.cpp b/src/curve.cpp index 4529730..01c344f 100644 --- a/src/curve.cpp +++ b/src/curve.cpp @@ -23,41 +23,35 @@ Curve::Curve(const Points &points, const std::string &name) : Points(points), vs #endif } -Curve::Curve(const py::array_t &in, const std::string &name) : Points(in.request().shape[0], in.request().ndim > 1 ? in.request().shape[1] : 1), name{name}, vstart{0}, vend{Points::size() - 1} { - auto buffer = in.request(); +Curve::Curve(const py::array_t &in, const std::string &name) : Points(in.request().shape[0], in.request().ndim > 1 ? in.request().shape[1] : 1), name{name}, vstart{0}, vend{Points::size() - 1} { + const dimensions_t n_dimensions = in.ndim(); + auto shape = in.shape(); + const curve_size_t number_points = shape[0]; - const dimensions_t n_dimensions = buffer.ndim; - - if (n_dimensions > 2){ - std::cerr << "A Curve requires a 1- or 2-dimensional numpy array of type " << typeid(coordinate_t).name() << "." << std::endl; - std::cerr << "Current dimensions: " << n_dimensions << std::endl; - std::cerr << "WARNING: constructed empty curve" << std::endl; - return; - } - - const curve_size_t number_points = buffer.shape[0]; - + if (n_dimensions > 2){ + std::cerr << "A Curve requires a 1- or 2-dimensional numpy array of type " << typeid(coordinate_t).name() << "." << std::endl; + std::cerr << "Current dimensions: " << n_dimensions << std::endl; + std::cerr << "WARNING: constructed empty curve" << std::endl; + return; + } + if (n_dimensions == 2) { - const dimensions_t point_size = buffer.shape[1]; - - auto accessor = in.unchecked<2>(); + const dimensions_t point_size = shape[1]; #if DEBUG std::cout << "constructing curve of size " << number_points << " and " << point_size << " dimensions" << std::endl; #endif #pragma omp parallel for simd - for (curve_size_t i = 0; i < number_points; ++i) { - for(curve_size_t j = 0; j < point_size; ++j){ - Points::operator[](i)[j] = accessor(i, j); + for (curve_size_t i = 0; i < number_points; ++i) { + for(dimensions_t j = 0; j < point_size; ++j){ + Points::operator[](i)[j] = *in.data(i, j); } } } else { - auto accessor = in.unchecked<1>(); - #pragma omp parallel for simd for (curve_size_t i = 0; i < number_points; ++i) { - Points::operator[](i)[0] = accessor(i); + Points::operator[](i)[0] = *in.data(i); } } diff --git a/src/fred_python_wrapper.cpp b/src/fred_python_wrapper.cpp index baabc37..3108933 100644 --- a/src/fred_python_wrapper.cpp +++ b/src/fred_python_wrapper.cpp @@ -29,25 +29,6 @@ namespace ddtw = Dynamic_Time_Warping::Discrete; const distance_t default_epsilon = 0.001; -fc::Distance continuous_frechet(const Curve &curve1, const Curve &curve2) { - return fc::distance(curve1, curve2); -} - -fd::Distance discrete_frechet(const Curve &curve1, const Curve &curve2) { - return fd::distance(curve1, curve2); -} - -ddtw::Distance discrete_dynamic_time_warping(const Curve &curve1, const Curve &curve2) { - return ddtw::distance(curve1, curve2); -} - -Curves jl_transform(const Curves &in, const double epsilon, const bool empirical_constant = true) { - - Curves curvesrp = JLTransform::transform_naive(in, epsilon, empirical_constant); - - return curvesrp; -} - void set_frechet_epsilon(const double eps) { fc::epsilon = eps; } @@ -64,16 +45,6 @@ bool get_frechet_rounding() { return fc::round; } -Clustering::Clustering_Result dtw_one_median(const Curves &in) { - auto result = Clustering::two_two_dtw_one_two_median(in); - return result; -} - -Clustering::Clustering_Result dtw_one_median_exact(const Curves &in) { - auto result = Clustering::two_two_dtw_one_two_median_exact(in); - return result; -} - Clustering::Clustering_Result klcenter(const curve_number_t num_centers, const curve_size_t ell, const Curves &in, Clustering::Distance_Matrix &distances, const Curves ¢er_domain = Curves(), const bool random_start_center = true) { auto result = Clustering::kl_center(num_centers, ell, in, distances, false, center_domain, random_start_center); return result; @@ -129,6 +100,7 @@ void set_number_threads(std::uint64_t number) { omp_set_dynamic(0); omp_set_num_threads(number); } + PYBIND11_MODULE(backend, m) { m.attr("default_epsilon_continuous_frechet") = default_epsilon; @@ -137,6 +109,7 @@ PYBIND11_MODULE(backend, m) { .def(py::init()) .def("__len__", &Point::dimensions) .def("__getitem__", &Point::get) + .def("__setitem__", &Point::set) .def("__str__", &Point::str) .def("__iter__", [](Point &v) { return py::make_iterator(v.begin(), v.end()); }, py::keep_alive<0, 1>()) .def("__repr__", &Point::repr) @@ -150,6 +123,7 @@ PYBIND11_MODULE(backend, m) { .def("__str__", &Points::str) .def("__iter__", [](Points &v) { return py::make_iterator(v.begin(), v.end()); }, py::keep_alive<0, 1>()) .def("__repr__", &Points::repr) + .def("add", &Points::add) .def_property_readonly("values", &Points::as_ndarray) .def_property_readonly("centroid", &Points::centroid) ; @@ -175,6 +149,7 @@ PYBIND11_MODULE(backend, m) { .def("add", &Curves::add) .def("simplify", &Curves::simplify) .def("__getitem__", &Curves::get, py::return_value_policy::reference) + .def("__setitem__", &Curves::set) .def("__len__", &Curves::number) .def("__str__", &Curves::str) .def("__iter__", [](Curves &v) { return py::make_iterator(v.begin(), v.end()); }, py::keep_alive<0, 1>()) @@ -198,7 +173,7 @@ PYBIND11_MODULE(backend, m) { .def("__repr__", &fd::Distance::repr) ; - py::class_(m, "Discrete_Dynamic_Time_Warping_Distance_Result") + py::class_(m, "Discrete_Dynamic_Time_Warping_Distance") .def(py::init<>()) .def_readwrite("time", &ddtw::Distance::time) .def_readwrite("value", &ddtw::Distance::value) @@ -239,26 +214,25 @@ PYBIND11_MODULE(backend, m) { m.def("get_continuous_frechet_epsilon", &get_frechet_epsilon); m.def("get_continuous_frechet_rounding", &get_frechet_rounding); - m.def("continuous_frechet", &continuous_frechet); - m.def("discrete_frechet", &discrete_frechet); - m.def("discrete_dynamic_time_warping", &discrete_dynamic_time_warping); + m.def("continuous_frechet", &fc::distance); + m.def("discrete_frechet", &fd::distance); + m.def("discrete_dynamic_time_warping", &ddtw::distance); m.def("weak_minimum_error_simplification", &weak_minimum_error_simplification); m.def("approximate_weak_minimum_link_simplification", &approximate_weak_minimum_link_simplification); m.def("approximate_weak_minimum_error_simplification", &approximate_weak_minimum_error_simplification); - m.def("dimension_reduction", &jl_transform, py::arg("in") = Curves(), py::arg("epsilon")= 0.5, py::arg("empirical_constant") = true); + m.def("dimension_reduction", &JLTransform::transform_naive, py::arg("in") = Curves(), py::arg("epsilon") = 0.5, py::arg("empirical_constant") = true); m.def("discrete_klcenter", &klcenter, py::arg("num_centers") = 1, py::arg("ell") = 2, py::arg("in") = Curves(), py::arg("distances") = Clustering::Distance_Matrix(), py::arg("center_domain") = Curves(), py::arg("random_start_center") = true); m.def("discrete_klmedian", &klmedian, py::arg("num_centers") = 1, py::arg("ell") = 2, py::arg("in") = Curves(), py::arg("distances") = Clustering::Distance_Matrix(), py::arg("center_domain") = Curves()); // these are experimental - //m.def("two_two_dtw_one_two_median", dtw_one_median); - //m.def("two_two_dtw_one_two_median_exact", dtw_one_median_exact); + //m.def("two_two_dtw_one_two_median", &Clustering::two_two_dtw_one_two_median); + //m.def("two_two_dtw_one_two_median_exact", &Clustering::two_two_dtw_one_two_median_exact); //def("discrete_onemedian_sampling", onemedian_sampling, onemedian_sampling_overloads()); //def("discrete_onemedian_exhaustive", onemedian_exhaustive, onemedian_exhaustive_overloads()); //def("onemedian_coreset", onemedian_coreset, onemedian_coreset_overloads()); - m.def("set_maximum_number_threads", set_number_threads); }