Skip to content

Commit

Permalink
bugfix and small changes
Browse files Browse the repository at this point in the history
  • Loading branch information
derohde committed Aug 23, 2021
1 parent 1103cc2 commit 74c8d4d
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 61 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions include/curve.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ class Curves : public std::vector<Curve> {
return std::vector<Curve>::operator[](i);
}

inline void set(const curve_number_t i, const Curve &val) {
std::vector<Curve>::operator[](i) = val;
}

inline curve_size_t get_m() const {
return m;
}
Expand Down
4 changes: 4 additions & 0 deletions include/point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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='[email protected]',
description='A fast, scalable and light-weight C++ Fréchet distance library, exposed to python and focused on (k,l)-clustering of polygonal curves.',
Expand Down
38 changes: 16 additions & 22 deletions src/curve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,41 +23,35 @@ Curve::Curve(const Points &points, const std::string &name) : Points(points), vs
#endif
}

Curve::Curve(const py::array_t<coordinate_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<coordinate_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);
}
}

Expand Down
48 changes: 11 additions & 37 deletions src/fred_python_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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 &center_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;
Expand Down Expand Up @@ -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;
Expand All @@ -137,6 +109,7 @@ PYBIND11_MODULE(backend, m) {
.def(py::init<dimensions_t>())
.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)
Expand All @@ -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)
;
Expand All @@ -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>())
Expand All @@ -198,7 +173,7 @@ PYBIND11_MODULE(backend, m) {
.def("__repr__", &fd::Distance::repr)
;

py::class_<ddtw::Distance>(m, "Discrete_Dynamic_Time_Warping_Distance_Result")
py::class_<ddtw::Distance>(m, "Discrete_Dynamic_Time_Warping_Distance")
.def(py::init<>())
.def_readwrite("time", &ddtw::Distance::time)
.def_readwrite("value", &ddtw::Distance::value)
Expand Down Expand Up @@ -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);
}

0 comments on commit 74c8d4d

Please sign in to comment.