summaryrefslogtreecommitdiff
path: root/src/python/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/include')
-rw-r--r--src/python/include/Alpha_complex_factory.h118
-rw-r--r--src/python/include/Alpha_complex_interface.h62
-rw-r--r--src/python/include/Persistent_cohomology_interface.h40
-rw-r--r--src/python/include/Simplex_tree_interface.h72
-rw-r--r--src/python/include/pybind11_diagram_utils.h25
5 files changed, 185 insertions, 132 deletions
diff --git a/src/python/include/Alpha_complex_factory.h b/src/python/include/Alpha_complex_factory.h
index 3405fdd6..41eb72c1 100644
--- a/src/python/include/Alpha_complex_factory.h
+++ b/src/python/include/Alpha_complex_factory.h
@@ -31,15 +31,34 @@ namespace Gudhi {
namespace alpha_complex {
-template <typename CgalPointType>
-std::vector<double> pt_cgal_to_cython(CgalPointType const& point) {
- std::vector<double> vd;
- vd.reserve(point.dimension());
- for (auto coord = point.cartesian_begin(); coord != point.cartesian_end(); coord++)
- vd.push_back(CGAL::to_double(*coord));
- return vd;
-}
+// template Functor that transforms a CGAL point to a vector of double as expected by cython
+template<typename CgalPointType, bool Weighted>
+struct Point_cgal_to_cython;
+
+// Specialized Unweighted Functor
+template<typename CgalPointType>
+struct Point_cgal_to_cython<CgalPointType, false> {
+ std::vector<double> operator()(CgalPointType const& point) const
+ {
+ std::vector<double> vd;
+ vd.reserve(point.dimension());
+ for (auto coord = point.cartesian_begin(); coord != point.cartesian_end(); coord++)
+ vd.push_back(CGAL::to_double(*coord));
+ return vd;
+ }
+};
+// Specialized Weighted Functor
+template<typename CgalPointType>
+struct Point_cgal_to_cython<CgalPointType, true> {
+ std::vector<double> operator()(CgalPointType const& weighted_point) const
+ {
+ const auto& point = weighted_point.point();
+ return Point_cgal_to_cython<decltype(point), false>()(point);
+ }
+};
+
+// Function that transforms a cython point (aka. a vector of double) to a CGAL point
template <typename CgalPointType>
static CgalPointType pt_cython_to_cgal(std::vector<double> const& vec) {
return CgalPointType(vec.size(), vec.begin(), vec.end());
@@ -51,24 +70,35 @@ class Abstract_alpha_complex {
virtual bool create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square,
bool default_filtration_value) = 0;
+
+ virtual std::size_t num_vertices() const = 0;
virtual ~Abstract_alpha_complex() = default;
};
-class Exact_Alphacomplex_dD final : public Abstract_alpha_complex {
+template <bool Weighted = false>
+class Exact_alpha_complex_dD final : public Abstract_alpha_complex {
private:
using Kernel = CGAL::Epeck_d<CGAL::Dynamic_dimension_tag>;
- using Point = typename Kernel::Point_d;
+ using Bare_point = typename Kernel::Point_d;
+ using Point = std::conditional_t<Weighted, typename Kernel::Weighted_point_d,
+ typename Kernel::Point_d>;
public:
- Exact_Alphacomplex_dD(const std::vector<std::vector<double>>& points, bool exact_version)
+ Exact_alpha_complex_dD(const std::vector<std::vector<double>>& points, bool exact_version)
+ : exact_version_(exact_version),
+ alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal<Bare_point>)) {
+ }
+
+ Exact_alpha_complex_dD(const std::vector<std::vector<double>>& points,
+ const std::vector<double>& weights, bool exact_version)
: exact_version_(exact_version),
- alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal<Point>)) {
+ alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal<Bare_point>), weights) {
}
virtual std::vector<double> get_point(int vh) override {
- Point const& point = alpha_complex_.get_point(vh);
- return pt_cgal_to_cython(point);
+ // Can be a Weighted or a Bare point in function of Weighted
+ return Point_cgal_to_cython<Point, Weighted>()(alpha_complex_.get_point(vh));
}
virtual bool create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square,
@@ -76,65 +106,49 @@ class Exact_Alphacomplex_dD final : public Abstract_alpha_complex {
return alpha_complex_.create_complex(*simplex_tree, max_alpha_square, exact_version_, default_filtration_value);
}
+ virtual std::size_t num_vertices() const override {
+ return alpha_complex_.num_vertices();
+ }
+
private:
bool exact_version_;
- Alpha_complex<Kernel> alpha_complex_;
+ Alpha_complex<Kernel, Weighted> alpha_complex_;
};
-class Inexact_Alphacomplex_dD final : public Abstract_alpha_complex {
+template <bool Weighted = false>
+class Inexact_alpha_complex_dD final : public Abstract_alpha_complex {
private:
using Kernel = CGAL::Epick_d<CGAL::Dynamic_dimension_tag>;
- using Point = typename Kernel::Point_d;
+ using Bare_point = typename Kernel::Point_d;
+ using Point = std::conditional_t<Weighted, typename Kernel::Weighted_point_d,
+ typename Kernel::Point_d>;
public:
- Inexact_Alphacomplex_dD(const std::vector<std::vector<double>>& points, bool exact_version)
- : exact_version_(exact_version),
- alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal<Point>)) {
+ Inexact_alpha_complex_dD(const std::vector<std::vector<double>>& points)
+ : alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal<Bare_point>)) {
+ }
+
+ Inexact_alpha_complex_dD(const std::vector<std::vector<double>>& points, const std::vector<double>& weights)
+ : alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal<Bare_point>), weights) {
}
virtual std::vector<double> get_point(int vh) override {
- Point const& point = alpha_complex_.get_point(vh);
- return pt_cgal_to_cython(point);
+ // Can be a Weighted or a Bare point in function of Weighted
+ return Point_cgal_to_cython<Point, Weighted>()(alpha_complex_.get_point(vh));
}
virtual bool create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square,
bool default_filtration_value) override {
- return alpha_complex_.create_complex(*simplex_tree, max_alpha_square, exact_version_, default_filtration_value);
+ return alpha_complex_.create_complex(*simplex_tree, max_alpha_square, false, default_filtration_value);
}
- private:
- bool exact_version_;
- Alpha_complex<Kernel> alpha_complex_;
-};
-
-template <complexity Complexity>
-class Alphacomplex_3D final : public Abstract_alpha_complex {
- private:
- using Point = typename Alpha_complex_3d<Complexity, false, false>::Bare_point_3;
-
- static Point pt_cython_to_cgal_3(std::vector<double> const& vec) {
- return Point(vec[0], vec[1], vec[2]);
- }
-
- public:
- Alphacomplex_3D(const std::vector<std::vector<double>>& points)
- : alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal_3)) {
- }
-
- virtual std::vector<double> get_point(int vh) override {
- Point const& point = alpha_complex_.get_point(vh);
- return pt_cgal_to_cython(point);
- }
-
- virtual bool create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square,
- bool default_filtration_value) override {
- return alpha_complex_.create_complex(*simplex_tree, max_alpha_square);
+ virtual std::size_t num_vertices() const override {
+ return alpha_complex_.num_vertices();
}
private:
- Alpha_complex_3d<Complexity, false, false> alpha_complex_;
+ Alpha_complex<Kernel, Weighted> alpha_complex_;
};
-
} // namespace alpha_complex
} // namespace Gudhi
diff --git a/src/python/include/Alpha_complex_interface.h b/src/python/include/Alpha_complex_interface.h
index 23be194d..469b91ce 100644
--- a/src/python/include/Alpha_complex_interface.h
+++ b/src/python/include/Alpha_complex_interface.h
@@ -27,10 +27,23 @@ namespace alpha_complex {
class Alpha_complex_interface {
public:
- Alpha_complex_interface(const std::vector<std::vector<double>>& points, bool fast_version, bool exact_version)
- : points_(points),
- fast_version_(fast_version),
- exact_version_(exact_version) {
+ Alpha_complex_interface(const std::vector<std::vector<double>>& points,
+ const std::vector<double>& weights,
+ bool fast_version, bool exact_version) {
+ const bool weighted = (weights.size() > 0);
+ if (fast_version) {
+ if (weighted) {
+ alpha_ptr_ = std::make_unique<Inexact_alpha_complex_dD<true>>(points, weights);
+ } else {
+ alpha_ptr_ = std::make_unique<Inexact_alpha_complex_dD<false>>(points);
+ }
+ } else {
+ if (weighted) {
+ alpha_ptr_ = std::make_unique<Exact_alpha_complex_dD<true>>(points, weights, exact_version);
+ } else {
+ alpha_ptr_ = std::make_unique<Exact_alpha_complex_dD<false>>(points, exact_version);
+ }
+ }
}
std::vector<double> get_point(int vh) {
@@ -39,38 +52,23 @@ class Alpha_complex_interface {
void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square,
bool default_filtration_value) {
- if (points_.size() > 0) {
- std::size_t dimension = points_[0].size();
- if (dimension == 3 && !default_filtration_value) {
- if (fast_version_)
- alpha_ptr_ = std::make_unique<Alphacomplex_3D<Gudhi::alpha_complex::complexity::FAST>>(points_);
- else if (exact_version_)
- alpha_ptr_ = std::make_unique<Alphacomplex_3D<Gudhi::alpha_complex::complexity::EXACT>>(points_);
- else
- alpha_ptr_ = std::make_unique<Alphacomplex_3D<Gudhi::alpha_complex::complexity::SAFE>>(points_);
- if (!alpha_ptr_->create_simplex_tree(simplex_tree, max_alpha_square, default_filtration_value)) {
- // create_simplex_tree will fail if all points are on a plane - Retry with dD by setting dimension to 2
- dimension--;
- alpha_ptr_.reset();
- }
- }
- // Not ** else ** because we have to take into account if 3d fails
- if (dimension != 3 || default_filtration_value) {
- if (fast_version_) {
- alpha_ptr_ = std::make_unique<Inexact_Alphacomplex_dD>(points_, exact_version_);
- } else {
- alpha_ptr_ = std::make_unique<Exact_Alphacomplex_dD>(points_, exact_version_);
- }
- alpha_ptr_->create_simplex_tree(simplex_tree, max_alpha_square, default_filtration_value);
- }
- }
+ // Nothing to be done in case of an empty point set
+ if (alpha_ptr_->num_vertices() > 0)
+ alpha_ptr_->create_simplex_tree(simplex_tree, max_alpha_square, default_filtration_value);
+ }
+
+ static void set_float_relative_precision(double precision) {
+ // cf. Exact_alpha_complex_dD kernel type in Alpha_complex_factory.h
+ CGAL::Epeck_d<CGAL::Dynamic_dimension_tag>::FT::set_relative_precision_of_to_double(precision);
+ }
+
+ static double get_float_relative_precision() {
+ // cf. Exact_alpha_complex_dD kernel type in Alpha_complex_factory.h
+ return CGAL::Epeck_d<CGAL::Dynamic_dimension_tag>::FT::get_relative_precision_of_to_double();
}
private:
std::unique_ptr<Abstract_alpha_complex> alpha_ptr_;
- std::vector<std::vector<double>> points_;
- bool fast_version_;
- bool exact_version_;
};
} // namespace alpha_complex
diff --git a/src/python/include/Persistent_cohomology_interface.h b/src/python/include/Persistent_cohomology_interface.h
index e5a3dfba..945378a0 100644
--- a/src/python/include/Persistent_cohomology_interface.h
+++ b/src/python/include/Persistent_cohomology_interface.h
@@ -12,6 +12,8 @@
#define INCLUDE_PERSISTENT_COHOMOLOGY_INTERFACE_H_
#include <gudhi/Persistent_cohomology.h>
+#include <gudhi/Simplex_tree.h> // for Extended_simplex_type
+
#include <cstdlib>
#include <vector>
@@ -223,6 +225,44 @@ persistent_cohomology::Persistent_cohomology<FilteredComplex, persistent_cohomol
return out;
}
+ using Filtration_value = typename FilteredComplex::Filtration_value;
+ using Birth_death = std::pair<Filtration_value, Filtration_value>;
+ using Persistence_subdiagrams = std::vector<std::vector<std::pair<int, Birth_death>>>;
+
+ Persistence_subdiagrams compute_extended_persistence_subdiagrams(Filtration_value min_persistence){
+ Persistence_subdiagrams pers_subs(4);
+ auto const& persistent_pairs = Base::get_persistent_pairs();
+ for (auto pair : persistent_pairs) {
+ std::pair<Filtration_value, Extended_simplex_type> px = stptr_->decode_extended_filtration(stptr_->filtration(get<0>(pair)),
+ stptr_->efd);
+ std::pair<Filtration_value, Extended_simplex_type> py = stptr_->decode_extended_filtration(stptr_->filtration(get<1>(pair)),
+ stptr_->efd);
+ std::pair<int, Birth_death> pd_point = std::make_pair(stptr_->dimension(get<0>(pair)),
+ std::make_pair(px.first, py.first));
+ if(std::abs(px.first - py.first) > min_persistence){
+ //Ordinary
+ if (px.second == Extended_simplex_type::UP && py.second == Extended_simplex_type::UP){
+ pers_subs[0].push_back(pd_point);
+ }
+ // Relative
+ else if (px.second == Extended_simplex_type::DOWN && py.second == Extended_simplex_type::DOWN){
+ pers_subs[1].push_back(pd_point);
+ }
+ else{
+ // Extended+
+ if (px.first < py.first){
+ pers_subs[2].push_back(pd_point);
+ }
+ //Extended-
+ else{
+ pers_subs[3].push_back(pd_point);
+ }
+ }
+ }
+ }
+ return pers_subs;
+ }
+
private:
// A copy
FilteredComplex* stptr_;
diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h
index 629f6083..0317ea39 100644
--- a/src/python/include/Simplex_tree_interface.h
+++ b/src/python/include/Simplex_tree_interface.h
@@ -15,9 +15,7 @@
#include <gudhi/distance_functions.h>
#include <gudhi/Simplex_tree.h>
#include <gudhi/Points_off_io.h>
-#ifdef GUDHI_USE_EIGEN3
#include <gudhi/Flag_complex_edge_collapser.h>
-#endif
#include <iostream>
#include <vector>
@@ -42,6 +40,9 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> {
using Complex_simplex_iterator = typename Base::Complex_simplex_iterator;
using Extended_filtration_data = typename Base::Extended_filtration_data;
using Boundary_simplex_iterator = typename Base::Boundary_simplex_iterator;
+ using Siblings = typename Base::Siblings;
+ using Node = typename Base::Node;
+ typedef bool (*blocker_func_t)(Simplex simplex, void *user_data);
public:
@@ -63,6 +64,30 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> {
return (result.second);
}
+ void insert_matrix(double* filtrations, int n, int stride0, int stride1, double max_filtration) {
+ // We could delegate to insert_graph, but wrapping the matrix in a graph interface is too much work,
+ // and this is a bit more efficient.
+ auto& rm = this->root()->members_;
+ for(int i=0; i<n; ++i) {
+ char* p = reinterpret_cast<char*>(filtrations) + i * stride0;
+ double fv = *reinterpret_cast<double*>(p + i * stride1);
+ if(fv > max_filtration) continue;
+ auto sh = rm.emplace_hint(rm.end(), i, Node(this->root(), fv));
+ Siblings* children = nullptr;
+ // Should we make a first pass to count the number of edges so we can reserve the right space?
+ for(int j=i+1; j<n; ++j) {
+ double fe = *reinterpret_cast<double*>(p + j * stride1);
+ if(fe > max_filtration) continue;
+ if(!children) {
+ children = new Siblings(this->root(), i);
+ sh->second.assign_children(children);
+ }
+ children->members().emplace_hint(children->members().end(), j, Node(children, fe));
+ }
+ }
+
+ }
+
// Do not interface this function, only used in alpha complex interface for complex creation
bool insert_simplex(const Simplex& simplex, Filtration_value filtration = 0) {
Insertion_result result = Base::insert_simplex(simplex, filtration);
@@ -133,38 +158,7 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> {
return;
}
- std::vector<std::vector<std::pair<int, std::pair<Filtration_value, Filtration_value>>>> compute_extended_persistence_subdiagrams(const std::vector<std::pair<int, std::pair<Filtration_value, Filtration_value>>>& dgm, Filtration_value min_persistence){
- std::vector<std::vector<std::pair<int, std::pair<Filtration_value, Filtration_value>>>> new_dgm(4);
- for (unsigned int i = 0; i < dgm.size(); i++){
- std::pair<Filtration_value, Extended_simplex_type> px = this->decode_extended_filtration(dgm[i].second.first, this->efd);
- std::pair<Filtration_value, Extended_simplex_type> py = this->decode_extended_filtration(dgm[i].second.second, this->efd);
- std::pair<int, std::pair<Filtration_value, Filtration_value>> pd_point = std::make_pair(dgm[i].first, std::make_pair(px.first, py.first));
- if(std::abs(px.first - py.first) > min_persistence){
- //Ordinary
- if (px.second == Extended_simplex_type::UP && py.second == Extended_simplex_type::UP){
- new_dgm[0].push_back(pd_point);
- }
- // Relative
- else if (px.second == Extended_simplex_type::DOWN && py.second == Extended_simplex_type::DOWN){
- new_dgm[1].push_back(pd_point);
- }
- else{
- // Extended+
- if (px.first < py.first){
- new_dgm[2].push_back(pd_point);
- }
- //Extended-
- else{
- new_dgm[3].push_back(pd_point);
- }
- }
- }
- }
- return new_dgm;
- }
-
Simplex_tree_interface* collapse_edges(int nb_collapse_iteration) {
-#ifdef GUDHI_USE_EIGEN3
using Filtered_edge = std::tuple<Vertex_handle, Vertex_handle, Filtration_value>;
std::vector<Filtered_edge> edges;
for (Simplex_handle sh : Base::skeleton_simplex_range(1)) {
@@ -178,7 +172,7 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> {
}
for (int iteration = 0; iteration < nb_collapse_iteration; iteration++) {
- edges = Gudhi::collapse::flag_complex_collapse_edges(edges);
+ edges = Gudhi::collapse::flag_complex_collapse_edges(std::move(edges));
}
Simplex_tree_interface* collapsed_stree_ptr = new Simplex_tree_interface();
// Copy the original 0-skeleton
@@ -190,9 +184,13 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> {
collapsed_stree_ptr->insert({std::get<0>(remaining_edge), std::get<1>(remaining_edge)}, std::get<2>(remaining_edge));
}
return collapsed_stree_ptr;
-#else
- throw std::runtime_error("Unable to collapse edges as it requires Eigen3 >= 3.1.0.");
-#endif
+ }
+
+ void expansion_with_blockers_callback(int dimension, blocker_func_t user_func, void *user_data) {
+ Base::expansion_with_blockers(dimension, [&](Simplex_handle sh){
+ Simplex simplex(Base::simplex_vertex_range(sh).begin(), Base::simplex_vertex_range(sh).end());
+ return user_func(simplex, user_data);
+ });
}
// Iterator over the simplex tree
diff --git a/src/python/include/pybind11_diagram_utils.h b/src/python/include/pybind11_diagram_utils.h
index 2d5194f4..5cb7c48b 100644
--- a/src/python/include/pybind11_diagram_utils.h
+++ b/src/python/include/pybind11_diagram_utils.h
@@ -17,16 +17,9 @@
namespace py = pybind11;
typedef py::array_t<double> Dgm;
-// Get m[i,0] and m[i,1] as a pair
-static auto pairify(void* p, py::ssize_t h, py::ssize_t w) {
- return [=](py::ssize_t i){
- char* birth = (char*)p + i * h;
- char* death = birth + w;
- return std::make_pair(*(double*)birth, *(double*)death);
- };
-}
-
-inline auto numpy_to_range_of_pairs(py::array_t<double> dgm) {
+// build_point(double birth, double death, ssize_t index) -> Point
+template<class BuildPoint>
+inline auto numpy_to_range_of_pairs(py::array_t<double> dgm, BuildPoint build_point) {
py::buffer_info buf = dgm.request();
// shape (n,2) or (0) for empty
if((buf.ndim!=2 || buf.shape[1]!=2) && (buf.ndim!=1 || buf.shape[0]!=0))
@@ -34,6 +27,16 @@ inline auto numpy_to_range_of_pairs(py::array_t<double> dgm) {
// In the case of shape (0), avoid reading non-existing strides[1] even if we won't use it.
py::ssize_t stride1 = buf.ndim == 2 ? buf.strides[1] : 0;
auto cnt = boost::counting_range<py::ssize_t>(0, buf.shape[0]);
- return boost::adaptors::transform(cnt, pairify(buf.ptr, buf.strides[0], stride1));
+
+ char* p = static_cast<char*>(buf.ptr);
+ auto h = buf.strides[0];
+ auto w = stride1;
+ // Get m[i,0] and m[i,1] as a pair
+ auto pairify = [=](py::ssize_t i){
+ char* birth = p + i * h;
+ char* death = birth + w;
+ return build_point(*(double*)birth, *(double*)death, i);
+ };
+ return boost::adaptors::transform(cnt, pairify);
// Be careful that the returned range cannot contain references to dead temporaries.
}